Docs
Jev Browser Control lets Claude and Codex drive a real Chrome. Claude plans; Jev, TypeSafe's decision model, chooses the clicks when you hand it a task. The MCP server opens its own Chrome window, so there is nothing to install in your browser. If you'd rather Claude worked in your everyday Chrome, there is an extension for that.
Install
You need Node.js 18 or newer and Google Chrome. The MCP server starts on your computer whenever Claude or Codex starts, and opens a Chrome window the first time it is used.
Add your key
Every browser step is one Jev call, and typing a value is one call to a small text model. Both come off your prepaid credits.
- Create an account in the dashboard. Your key (it starts with
jbc_) is shown once, so copy it. - Add credits by card, from $10. Credits don't expire.
- Pass the key when you connect Claude or Codex (next step), with
-e JBC_API_KEY=jbc_….
To keep the key out of Claude's and Codex's config, put it in a file on your computer instead, and leave out -e in the next step:
mkdir -p ~/.jev-browser-control echo 'JBC_API_KEY=jbc_…your key…' >> ~/.jev-browser-control/config.env chmod 600 ~/.jev-browser-control/config.env
Each call costs five times what OpenRouter charges for it. Your dashboard lists every call and what it cost.
Connect Claude and Codex
Claude Code
claude mcp add -s user -e JBC_API_KEY=jbc_…your key… jev-browser -- npx -y https://jevbrowsercontrol.com/downloads/jev-browser-control-mcp-0.4.2.tgz
Or paste the key into Claude and ask it to install Jev Browser Control: it runs this command for you.
Codex
codex mcp add jev-browser --env JBC_API_KEY=jbc_…your key… -- npx -y https://jevbrowsercontrol.com/downloads/jev-browser-control-mcp-0.4.2.tgz
The first start downloads the server and Playwright, which takes about ten seconds. If Codex reports a startup timeout, add startup_timeout_sec = 60 under [mcp_servers.jev-browser] in ~/.codex/config.toml.
Claude Desktop
Settings → Developer → Edit Config, add this, and restart Claude Desktop:
{
"mcpServers": {
"jev-browser": {
"command": "npx",
"args": ["-y", "https://jevbrowsercontrol.com/downloads/jev-browser-control-mcp-0.4.2.tgz"],
"env": { "JBC_API_KEY": "jbc_…your key…" }
}
}
}
From source
git clone https://github.com/nexibeo/jev-browser-control cd jev-browser-control node scripts/install-agents.mjs
That registers the server for Claude Code and Codex and also installs a skill and a Claude Code subagent that know how to use the tools well.
Restart Claude and ask “check the browser status”. A Chrome window opens, and Claude reports Browser: ready and Jev: jevbrowsercontrol.com credits.
~/.jev-browser-control/chrome-profile. When a site needs a login, sign in there yourself once; the login is kept for the next session. Several Claude and Codex sessions share the one window, and when the session that opened it ends, the next one takes over.Your everyday Chrome: the extension
With the extension, Claude works in your normal Chrome, with your logins and open tabs. It also gives you a side panel to run tasks yourself, and it is what Grok Bot and other remote apps connect to.
- Download the extension (.zip, version 0.2.3) and unzip it.
- Open
chrome://extensionsand switch on Developer mode (top right). - Click Load unpacked and choose the unzipped folder.
- Pin the orange cursor icon. Clicking it opens the side panel; the settings page opens by itself the first time. Paste your key there and press Test connection. It answers with your balance.
- Register the MCP server in extension mode:
claude mcp add -s user -e JBC_MODE=extension jev-browser -- npx -y https://jevbrowsercontrol.com/downloads/jev-browser-control-mcp-0.4.2.tgz
In extension mode the server opens a bridge on 127.0.0.1:10522, and the extension connects to it. “Check the browser status” should report the extension as connected, and the side panel shows Claude connected. The extension works in Chrome, Edge, Brave and other Chromium browsers, version 120 or newer. A Chrome Web Store listing is on its way; until then Chrome keeps the unpacked extension installed, it just won't update itself.
claude.ai, ChatGPT, Grok Bot and other remote AI apps
Apps that run in the cloud can't start a program on your computer. For them, jevbrowsercontrol.com runs the same tools as a remote MCP server at https://jevbrowsercontrol.com/mcp, and passes each call to your extension, so the app works in your own Chrome with your logins.
- Create an account in the dashboard and add credits. Remote control itself is free; Jev's calls come off your credits.
- In the extension's settings, under Remote AI apps, switch on “Let remote AI apps control this browser”. It uses your credits key, or a separate key you paste there. The side panel shows Remote on once it is connected.
- Add Jev Browser Control to the app:
- claude.ai (and the Claude apps): Settings → Connectors → Add custom connector. Name it “Jev Browser Control”, enter the URL
https://jevbrowsercontrol.com/mcpand connect. - ChatGPT (developer mode): create an app or connector with the same URL and choose OAuth sign-in.
- In both, a jevbrowsercontrol.com page opens: sign in (with an email link or one of your API keys) and click Allow.
- claude.ai (and the Claude apps): Settings → Connectors → Add custom connector. Name it “Jev Browser Control”, enter the URL
Apps that take a key instead of a sign-in, such as Grok Bot, use the URL with your key as a bearer token:
URL: https://jevbrowsercontrol.com/mcp Authorization: Bearer jbc_…your key…
For Grok Bot there is a ready-made template, Jev Browser Operator, that sets this up and knows how to use the tools.
Each app you allow gets its own key, named “OAuth · app name”, in your dashboard. Revoke that key to disconnect the app. The sign-in uses OAuth 2.1 with PKCE and dynamic client registration; the details are at /.well-known/oauth-authorization-server.
Each remote call adds a round trip through the relay (about 0.3 seconds), and a single jev_task stops after 85 seconds, so split longer work into several tasks. Screen recordings and reading the page's clipboard work only with the MCP server on your own computer.
Use it
From Claude or Codex
Ask in plain words: “Use the browser to find the opening hours of the Rijksmuseum,” or “Fill in the contact form on example.com with my details: …”. Claude decides when to drive the browser itself and when to hand a sub-task to Jev with jev_task. Put every value that has to be typed into your request; Jev's text helper never makes up personal details. You can watch every step in the Chrome window.
From the side panel (extension)
Click the toolbar icon, type a goal such as “Find the cheapest one-way flight from Zürich to London on 20 October”, and press Run. Each step shows what Jev chose, how sure it was and how long it took. Stop ends the task at once.
Tools
| Tool | Arguments | What it does |
|---|---|---|
jev_task | goal, details, url, newTab, maxSteps, maxSeconds, allowIrreversible | Runs a task with Jev. Returns the status, every step, the cost and the final page's text. |
jev_find | description | The visible element that best matches a description, with probabilities. |
jev_check | statement | The probability that a statement about the page is true. |
jev_stop | Stops running Jev tasks. | |
browser_snapshot | full | Numbered elements and visible text. full lists the whole page. |
browser_click | ref | Clicks element [ref]. |
browser_type | ref, text, submit | Replaces a field's text; submit presses Enter. |
browser_select | ref, option | Chooses a dropdown option by its label. |
browser_press_key | key, ref | Enter, Tab, Escape, arrows, or combos like Control+A. |
browser_scroll | direction, amount | Scrolls about one screen. |
browser_navigate | url, newTab | Opens a URL, optionally in a new tab. |
browser_tabs | action, tabId | Lists tabs, or selects one. |
browser_close_tab | tabId | Closes a tab. |
browser_back | forward | History back or forward. |
browser_read | format, offset, limit | The whole page as markdown, text or links. |
browser_screenshot | quality | A JPEG of the visible page. |
browser_hover | ref | Moves the mouse onto an element, for menus that open on hover (reaction pickers, navigation menus). |
browser_clipboard | The text the page just copied, for example after a “Copy link” menu item. | |
browser_record | action (start, stop), name | Records the browser window; stop saves an MP4 on your computer and returns its path. |
browser_wait | text, seconds | Waits for text to appear. |
browser_status | Browser, current tab, key and limits. The first call opens the Chrome window. |
How a jev_task ends
| Status | Meaning |
|---|---|
done | Jev chose DONE and its separate goal check agreed. |
done_unconfirmed | Jev chose DONE but the goal check disagreed. Look at the page. |
needs_confirmation | The next click may buy, pay, send, post or delete. It was not clicked. |
needs_input | A field needs a value the goal doesn't give. Nothing was made up. |
blocked / stuck | No useful action left, or three actions in a row changed nothing. |
budget | A limit on actions, seconds or cost was reached. |
Safety
- Jev only chooses among options the page snapshot offered. Its answer is an element number that code maps to a real element; it never becomes a selector, coordinates or a script.
- Password and file-upload fields are never offered, to Jev or to Claude.
- Clicks that buy, pay, send, post or delete stop for confirmation (setting: on by default). So does a Comment, Reply or Send button next to a text box that holds text, because it would publish it.
- Blocked sites: neither Jev nor Claude acts on domains you list.
- Page text is sent to Jev as untrusted data. Prompt injection on a web page can still mislead a model, so keep limits on and check results.
- The MCP server listens on 127.0.0.1 only. Other Claude sessions need a local token, and in extension mode only Chrome extensions can connect (web pages can't).
- The Chrome window of the MCP server has its own profile, with only the logins you make there. The extension acts in your normal Chrome profile with all your logins; for risky work, use a separate Chrome profile.
Settings
For the MCP server's own Chrome window, put these in ~/.jev-browser-control/config.env, one per line:
| Line | Default |
|---|---|
JBC_MAX_STEPS=30, JBC_MAX_SECONDS=120, JBC_MAX_COST_USD=0.10 | Limits per task |
JBC_BLOCKED_SITES=mybank.com,paypal.com | None. Domains the browser may not open or act on. |
JBC_CONFIRM_IRREVERSIBLE=0 | On: tasks stop before clicks that buy, pay, send, post or delete. |
JBC_HEADLESS=1 | Off: the window is visible. |
CHROME_PATH=/path/to/chrome | The installed Google Chrome. |
JBC_PROFILE_DIR=/path | ~/.jev-browser-control/chrome-profile |
In the extension, the same choices are on its settings page:
| Setting | Default |
|---|---|
| Jev model | ~typesafe/jev-latest (always the newest; the tilde is required) |
| Text model | inception/mercury-2.5 |
| Limits per task | 30 actions, 120 seconds, $0.10 |
| Ask before irreversible clicks | On |
| Input | Trusted (Chrome shows “started debugging this browser” while Jev acts). Synthetic events avoid the bar, but some sites ignore them. |
| Claude bridge port | 10522 (set JBC_PORT for the MCP server too if you change it) |
Your key stays on this computer, in config.env or in Chrome's local extension storage, and is sent only to jevbrowsercontrol.com.
Credits API
With a credits key you can call Jev from your own code. The requests and responses match OpenRouter's, so an OpenRouter client only needs a new base URL and key.
| Endpoint | Use |
|---|---|
POST /api/v1/decisions | Jev decisions: {model, state, questions}. Also at /api/alpha/decisions. |
POST /api/v1/chat/completions | The small text models (no streaming). |
GET /api/v1/balance | Your remaining credits. |
GET /api/v1/models | Allowed models and their price here. |
curl https://jevbrowsercontrol.com/api/v1/decisions \
-H "Authorization: Bearer $JBC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "~typesafe/jev-latest",
"state": { "page": "Checkout: 2 items, total $31.50" },
"questions": {
"has_items": { "type": "noul", "instructions": "Does the cart in `page` contain items?" }
}
}'
Each response's usage.cost is what you were charged (5× OpenRouter's cost for that call), and usage.credits_remaining is your balance after it. Failed calls are free. Errors use OpenRouter's shape: 401 bad key, 402 out of credits, 429 too many requests per minute.
Troubleshooting
“Chrome could not start”
Install Google Chrome, or point CHROME_PATH in config.env at a Chrome or Chromium binary. If it says the profile is in use, a Chrome window from an earlier session is still open: close it and ask again.
“No key for Jev”
Add JBC_API_KEY=jbc_… to ~/.jev-browser-control/config.env and ask again. There is no need to restart Claude.
Claude says the extension is not connected
Keep Chrome open and click the Jev toolbar icon; that wakes the extension, and it connects within a second. Check that “Let Claude control this browser” is on in the settings, and that nothing else uses port 10522.
“This page can't be controlled by extensions”
Chrome doesn't let extensions script chrome:// pages, the Chrome Web Store or other extensions. Open a normal website first.
Clicks do nothing while DevTools is open
Only one debugger can attach to a tab. With DevTools open the extension falls back to synthetic events, which some sites ignore. Close DevTools.
Jev picked the wrong thing
Jev can be confidently wrong between look-alikes (“Cold Email” and “Cold Outreach”). Name the target precisely in the goal, and verify the result with jev_check or a snapshot.
Open source
The extension and MCP server are MIT-licensed at github.com/nexibeo/jev-browser-control. The loop's design (one request for the operation plus a target for every operation, freshness checks before input) comes from Browser Use's Jev Ultrafast, also MIT. Issues and pull requests are welcome.