firefox-jev
Allows controlling and automating a Firefox browser, including navigation, clicking, typing, selecting, and reading page content, with fast element selection via the Jev model and fallback to Claude for ambiguous decisions.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
firefox-jev-mcp
An MCP server that lets Claude drive Firefox, with a fast decision model for clicks: Claude plans, Jev (TypeSafe) picks the element to act on, and Claude only takes over when Jev hesitates.
Why
With a classic browser MCP server, the LLM rereads the page and decides on every click: one model turn per action, so a few seconds each time. Most clicks are simple decisions ("which link leads to Paris?"). firefox-jev-mcp hands them to Jev, a model that generates no text and returns one probability per page element, in about a second. Claude keeps what it does best: understanding the request, planning, and settling ambiguous cases.
Related MCP server: jev-reflex
Results
Same task, same prompt, same model (Claude Opus 5.5 through claude -p), two races run in parallel: start from the Wikipedia article "Titanic" and reach "Eiffel Tower" by clicking links only (no search, no typing, no typed URL, no going back).
Wikipedia race | firefox-jev-mcp | Mozilla firefox-devtools-mcp |
Total time | 14.7 s | 23.4 s |
of which Claude thinking | 7.9 s | 19.1 s |
Claude turns | 4 | 12 |
Claude tokens | 20.8k | 88.5k |
Cost per race, Claude and Jev included | €0.033 | €0.050 |
Over 4 races, firefox-jev-mcp finished first every time: 17.2, 19.2, 22.7 and 14.7 s, against 23.5, 20.2, 27.8 and 23.4 s (the first ones used earlier versions of the server). At those rates, 1,000 races cost €32.74 against €49.60.
Basic actions, measured without an LLM on 4 real pages (median of 4 runs after a warm-up run):
Basic action | firefox-jev-mcp | Mozilla firefox-devtools-mcp | Google chrome-devtools-mcp | Playwright MCP | Playwright MCP |
Browser | Firefox | Firefox | Chrome | Chrome | Firefox |
Click, until the next page has loaded | 181 ms | 290 ms [1] | 326 ms | 958 ms | 1,257 ms |
Navigate to a URL | 186 ms | 129 ms [2] | 280 ms | 248 ms | 388 ms |
Snapshot of a Wikipedia article, in tokens [3] | 3.7k | 1.1k [4] | 215k | 209k | 209k |
Median over 3 pages: its snapshot does not show the Hacker News navigation links.
Returns as soon as the HTML is parsed (DOMContentLoaded), before loading finishes.
Estimate: characters divided by 4.
Truncated to 100 lines by default.
Prices used: public API prices (Claude Opus 5.5, Jev 1.13 at $0.042 per million input tokens, output free), ECB rate of 2026-09-23. Method, raw data and scripts to reproduce everything are in bench/ (documented in French).
How it works
Claude Code
| MCP tools (stdio)
v
Local MCP server (server/, TypeScript)
|-- Jev API: one Choice over the page elements + one Noul "goal reached?",
| then verification Nouls when the Choice hesitates
|
| WebSocket ws://127.0.0.1:8765 (moz-extension:// origin only)
v
Firefox extension (extension/)
|-- content.js: extracts interactive elements, clicks, types, waits for rendering to finish
'-- background.js: WebSocket bridge, tabs, navigation, iframes, network tracking, copies of received PDFsBefore each read (browser_snapshot, browser_read, steps of browse_goal), the extension waits for the page to finish rendering: the tab's data requests are done, the structure has been stable for 250 ms, and no loading indicator is visible ("Loading...", aria-busy, a progress bar without a value). It waits 4 s at most and reports an indicator that is still visible. A page that has already rendered is read without delay.
The browse_goal tool runs on its own: page snapshot, Jev's decision, action, and so on until the goal. It stops when the goal is reached, when Jev hesitates, or when the action is sensitive (paying, deleting, sending), and then gives Claude the best candidates, ready to use. Claude remains the orchestrator: the extension never contacts Claude, which works with a Claude subscription, without an Anthropic API key.
How Jev decides, step by step
Duplicates are merged. Links to the same URL (menu, card, footer) become a single option. The probabilities of a Choice always add up to 1: without merging, Jev splits its probability across equivalent links, and its confidence drops even though it has no doubt about the destination.
Used elements are removed. An element already clicked or filled on the current page is no longer offered, which avoids loops.
Text to type is known to Jev. With
typeText, Jev knows a search is possible. WithouttypeText, search fields are not offered to it.Choice + Noul "goal reached?" in a single request.
Verification when the Choice hesitates. Below
minConfidence(0.6), a second call asks one Noul per candidate among the top 3: "does this action move towards the goal?". A Choice is relative and shares its probability across several valid paths. A Noul is absolute. The loop acts if the chosen candidate reachesverifyThreshold(0.8), otherwise it hands back to Claude.Arrival check. After each action, a Noul sees the previous page, the action taken and the current page, for goals defined by the starting page ("the 3rd story", "the cheapest book").
Dropdowns. A Choice over the options picks the value to select. A list drawn by the page (ARIA combobox: Angular Material, React Select...) often only has its options once open: the loop clicks it first, then
selectclicks the option and closes the list.Typing.
typeTextis typed only once, and Enter is pressed only in a search field.
Above 250 options (the API limits a Choice to 255), the decision takes two passes: one Choice per slice of 200, in parallel requests, then a final Choice over the top 5 of each slice.
Getting started
Requirements: Node.js 20 or later, Firefox 142 or later, a TypeSafe API key (console.typesafe.ai), and pdftotext to read PDFs (package poppler-utils).
npm install
cp .env.example .env # then set TYPESAFE_API_KEYConnect the server to Claude Code for all projects:
claude mcp add firefox-jev --scope user -- "$(pwd)/node_modules/.bin/tsx" "$(pwd)/server/src/index.ts"Or run
claudefrom this folder: the.mcp.jsonfile is detected. The server only opens port 8765 on the first tool call, so sessions that do not use Firefox do not block it.Install the
/firefoxcommand, available in all projects:ln -s "$(pwd)/skills/firefox" ~/.claude/skills/firefoxAsk Claude, for example:
/firefox open the API documentation on example.com. The command starts Firefox if needed (browser_launchtool), then chains the tools.
To start Firefox by hand, with the extension, in the dedicated profile (./firefox-profile, created on first launch): npm run firefox. The extension badge shows ON when a Claude Code session is connected.
Driving your everyday Firefox
The extension can also run in your everyday Firefox profile, to act on pages you already have open (resuming a form from an email, for example). It is off by default there: one click on its button gives control to Claude (badge ON), a second click takes it back. While it is on, it takes priority over the dedicated profile, which reconnects as soon as it is turned off.
Claude works in its own tab, in the background: the tab you are looking at stays displayed (a stream keeps playing), and tools without a tabId target the tab Claude is working in. On the first call, Claude only takes over the active tab if it is empty, otherwise it opens its own. To see its page, ask it to display it (activate).
Firefox only installs extensions signed by Mozilla permanently. "Unlisted" signing is free and does not publish the extension:
Create keys on addons.mozilla.org/developers/addon/api/key and set them in
.env(WEB_EXT_API_KEY,WEB_EXT_API_SECRET).Run
npm run sign: the signed.xpifile lands inweb-ext-artifacts/. Each new signature requires raising the version inextension/manifest.json. Since 0.3.0, the extension also asks for access to network requests (webRequest), to follow page loading and keep a copy of PDFs: Firefox asks you to accept it on update.Open it in Firefox (drag the file into a window, or
about:addonsthen "Install Add-on From File").
To try it without signing: go to about:debugging, "This Firefox", "Load Temporary Add-on" and choose extension/manifest.json. Loaded this way, the extension behaves as in the dedicated profile: it connects by itself, and disappears when Firefox restarts.
MCP tools
Tool | Role |
| Starts Firefox with the extension if none is connected |
| Autonomous navigation towards a goal: snapshot, Jev's decision, action, in a loop |
| Ranks the page elements with Jev for a goal, without acting |
| Visible interactive elements, each with a ref ( |
|
|
| Drops local files (resume, letter...) into a file field or a drag-and-drop zone |
| Saves to disk the PDF shown in the tab, a link's target or a URL, without overwriting anything |
| Opens a URL or goes back, in the background; |
| Visible page text, iframes included, or the text of the PDF shown in the tab |
| Scrolls by one screen |
| Connection to the extension, presence of the Jev key, tabs (displayed, Claude's), recent PDFs |
browse_goal returns one of these statuses:
done: Jev estimates that the page meets the goal (goalThreshold, 0.85 by default).need_decision: Claude has to decide.reasonexplains why andcandidatesgives the top 5 refs.max_steps: the number of steps was reached (maxSteps, 6 by default).error: a technical incident. The steps already done are kept.
Limitations
Synthetic clicks: Firefox offers extensions no equivalent of Chrome's
debuggerAPI. Events haveisTrusted = false, which some sites (anti-bot, payment, OAuth) ignore.Iframes are explored 3 levels deep, even across origins, and the content of a modal window comes first. An iframe link that targets the whole page (
target="_top") is opened by the tab, because Firefox blocks that navigation without a real click. Open and closed Shadow DOMs are supported.PDFs: Firefox's viewer is closed to extensions, so the extension keeps a copy of the last 10 PDFs received (30 MB each at most, in memory, forgotten when it is turned off).
browser_readextracts their text andbrowser_savesaves them, even when a site serves a document only once or another PDF has replaced it in the tab.Background tabs: Firefox slows pages down there. The extension counts its waits with its background script, which is not slowed down, but a few sites only render their content once visible (load on scroll, render on next frame). In that case show the tab with
activate.At most 1,000 elements per snapshot: on a very long article, the last links are not offered.
One session at a time drives Firefox: the last one to call a tool takes control, and a request in progress in the other session fails.
Planning: Jev excels when the target link is on the page, less so when choosing an intermediate page. It then hands back to Claude.
Language: Jev is mostly trained in English. Goals phrased in English give better results.
Privacy: the URL, title, element labels and the beginning of the text of pages visited by
browse_goalorjev_rankare sent to the TypeSafe API. The/firefoxcommand goes through Jev for all clicks, including in your everyday profile, on pages where you are logged in.
License
MIT, see LICENSE.
Related MCP Connectors
AI-powered browser automation — navigate, click, fill forms, and extract data from any website.
Control a real browser from AI agents: navigate, click, type, screenshot, read the page.
Rove — supervised browser for AI agents. Your agent drives; a human watches, takes over.
Stealth web automation for AI agents. Login, signup, navigate, screenshot.
Related MCP Servers
- MIT
- AlicenseBqualityCmaintenanceEnables Claude to delegate entire browser tasks to TypeSafe's Jev, which performs each click/type/select decision in about 100 ms, allowing fast automated web interactions while Claude handles planning and verification.23MIT
- AlicenseAqualityCmaintenanceEnables AI agents to delegate complex web browsing goals to a real Chrome instance driven by Jev, completing tasks end-to-end in ~300ms per decision and returning only the final result.1114 npm4MIT
- AlicenseNot gradedqualityBmaintenanceEnables Claude Code and Claude Desktop to control your own Chrome browser, with Jev deciding each click, keystroke, and scroll.5MIT