npm.io
0.1.0 • Published yesterdayCLI

jev-browser-mcp

Licence
MIT
Version
0.1.0
Deps
3
Size
237 kB
Vulns
0
Weekly
0
Stars
1

jev-browser-mcp

A browser for your agent that keeps the page out of its context.

Your model says what it wants. A tiny typed-decision model clicks, a cheap model reads,
and only the answer comes back — never the DOM.

License: MIT Node 20+ MCP Playwright

94× less context than Playwright MCP when reading · $0 replays · self-healing recipes · exports plain Playwright tests


claude mcp add --scope user jev-browser -- npx -y jev-browser-mcp

Then ask Claude something like "on the Ada Lovelace Wikipedia page, when and where was she born?". Claude gets back 266 tokens. The same question through Playwright MCP costs 108,726.

Why

Browser MCP servers hand the page to your model. A real page is 10k–100k tokens, and whatever lands in the conversation is paid for again on every later message. Twenty steps on a real site and the context is mostly DOM.

This server splits the work between three models, and the expensive one does the least:

flowchart LR
    A["🧠 Your model<br/>(Claude, GPT…)"] -- "intent:<br/>'find the price'" --> S["jev-browser-mcp"]
    S -- "answer · 300 tokens" --> A
    S -- "compressed state" --> J["⚡ Jev<br/>which element? which op?<br/>~$0.04 / 1M tokens"]
    S -- "page text" --> F["📖 Gemini Flash<br/>reads the page,<br/>writes field values"]
    S <--> P["🌐 Chrome<br/>(Playwright)"]
who job sees the page?
your model states the intent, reads the result no
Jev decides each step: which element, which operation, is it done a compressed state
Gemini Flash answers questions about the page, writes values into fields yes, on the server

What it's good at

Knowing something without reading the page

browse_ask reads the page on the server and returns the answer, optionally as JSON. Measured on four live pages, all answers correct:

page Playwright MCP jev-browser
Wikipedia · Ada Lovelace 108,726 tokens 266 409×
GitHub · microsoft/playwright 14,531 399 36×
MDN · Array.prototype.at 13,918 519 27×
Hacker News · top 3 as JSON 13,478 418 32×
total 150,653 1,603 94×

Each read costs $0.0004–$0.003 in Flash tokens.

Record once, replay for free, heal when the site changes
browse_goal  saveAs=checkout.json     → Jev drives it once       ~$0.0005
browse_replay checkout.json           → no model at all          $0 · ~2 s
  … the site is redesigned: ids renamed, labels changed …
browse_replay checkout.json heal=true → only the broken step     ~$0.0001
browse_replay checkout.json           → free again               $0
browse_replay export=playwright       → a plain @playwright/test spec

Each step is recorded with several locators, strongest first: role and name, label, field name, id, and the stable tail of a framework-generated id. When every locator misses, only that step goes to Jev, and the repaired step is written back into the recipe.

Measured on six hard cases (calendar, autocomplete, dependent dropdown, ordered form, delayed dialog, form inside an iframe): each page was redesigned so every recorded locator missed. The old recipe broke, healed 6/6, and the exported specs pass on plain Playwright with this server not running.

Enterprise screens that break other tools

It was hardened against a live JSF/PrimeFaces admin console, not only demo pages:

  • generated j_idt… ids
  • ViewState fields that must never be touched
  • buttons drawn as <span>s
  • disabled state expressed only as a CSS class
  • iframes
  • modals that appear seconds late

A three-step search recorded there replays in 4.4–4.9 s at $0. The replay passed 3/3 even when the session started with a different search already in the box.

Cheap actions too
task Playwright MCP, used well browse_act browse_goal
4-field form + submit 360 tokens · 4 calls 252 · 3 527 · 1
dependent dropdown 321 · 4 208 · 2 340 · 1
Wikipedia search, live 18,875 · 3 405 · 3 456 · 1

On a toy page there is nothing to save. The saving grows with the size of the page.

What it is not

This is not an autonomous open-web agent. Left alone on 30 live WebVoyager tasks, it completes 30%. Agents where a large model reasons about every step report far more. Jev picks the right control on the screen; it does not reason across ten criteria on a page. That reasoning is your model's job.

It is built to be the hands under a strong model, and that is how it is measured.

How it compares

All results below were measured live and are reproducible. Methodology, raw results and grading reasons are in docs/BENCHMARKS.md.

vs jev-ultrafast: both run autonomously, 30 WebVoyager tasks, same text model.

passed median time cost / task
jev-browser 9 / 30 18 s $0.0009
jev-ultrafast 6 / 30 16 s $0.0046

About 5× cheaper on every task. The success difference is not significant (McNemar p = 0.51). ultrafast passes Google Flights; this server does not.

vs Playwright MCP, with the same GPT-5 driver on both. Four tasks, so this is an observation, not a statistic:

passed driver tokens list price
Playwright MCP 0.0.82 1 / 4 1.15 M $1.54
jev-browser 1 / 4 verified + 2 unverified¹ 0.76 M $1.15

On the Apple task the driver made 1 browse_goal call and 1 browse_ask call: 3 steps and 11k tokens, against 16 steps and 88k through Playwright MCP.

¹ A harness bug left the final page unread. Those runs were graded on the driver's answer alone, so they are not counted as passes.

The first version lost this comparison. The driver ignored browse_goal and browse_ask, went step by step, and spent more tokens than Playwright MCP (486k vs 340k). The advantage only exists when the model uses the tools that keep the page out of its context. Two changes fixed it: action results got smaller, and the server now sends MCP instructions that tell the model when to use those tools.

When to use it

use it for use something else for
self-healing regression tests: record, replay free, export to Playwright "go do anything on the internet" with no model on top
repetitive work in internal tools and admin panels single clicks on small pages: no saving there
reading big pages without blowing up your context bot-protected consumer sites like Google Flights
legacy JSF / PrimeFaces / iframe-heavy apps
capturing a legacy screen's behaviour and checking the rewrite against it

Tools

Thirteen tools cover Playwright MCP's capabilities (20/20 probes, checked on the page: node bench/coverage.mjs). Their definitions take about 3.8k tokens; Playwright MCP's defaults take about 5.6k.

tool what it does
browse_goal drive toward a plain-language goal; optionally record it (saveAs)
browse_ask a question about the page, answered on the server, optionally as JSON
browse_replay replay a recipe with no model; heal broken steps; export=playwright
browse_act click · type · fill (a whole form by label) · select · hover · drag · upload · key · scroll · wait
browse_verify exact checks in code (free), or a plain-language claim judged by Jev
browse_navigate · browse_observe open a URL · the compressed element list, with find
browse_tabs · browse_dialog_policy tabs · decide alert/confirm before they block
browse_eval · browse_console · browse_screenshot look under the hood
browse_page pdf · resize · media · network requests · tracing · save session · close

A run ends as done, blocked, escalate or max_steps. escalate is a normal outcome: Jev would not commit, so the final page comes back and your model takes the next step itself.

Setup

Requirements:

  • Node 20+
  • Chromium: npx playwright install chromium, or attach to your own Chrome
  • one Vercel AI Gateway key, which reaches both Jev and Gemini

The server reads the key from AI_GATEWAY_API_KEY, JEV_KEY_FILE, or ~/.config/jev/key. Keep it out of the MCP registration so it never lands in shell history. On the free tier, Flash allows 5 requests a minute; the server retries through that limit instead of failing.

Pages behind a login

A profile directory alone is not enough. Server-rendered logins issue session cookies with no Expires, and Chrome drops those when it closes. Sign in by hand once and capture the live session:

npx jev-browser-login https://example.com/login   # sign in, then press ENTER
export JEV_BROWSER_STORAGE=~/.config/jev/session.json

For a session that never expires, run ./chrome-cdp.sh <url> from a checkout and set JEV_BROWSER_CDP=http://localhost:9222. You can watch every step and take the window back at any time.

You type your own password into your own window. The server never reads, stores or forwards it, and it refuses to type into password fields unless JEV_ALLOW_SECURE_FIELDS=1. A web page cannot set that variable.

Environment variables
variable effect
JEV_BROWSER_STORAGE session captured from a manual login
JEV_BROWSER_PROFILE persistent profile directory
JEV_BROWSER_CDP attach to your own Chrome, e.g. http://localhost:9222
JEV_BROWSER_HEADED show the window
JEV_BROWSER_IGNORE_HTTPS_ERRORS accept a corporate TLS interception certificate
JEV_ALLOW_SECURE_FIELDS allow typing into password fields (off by default)
JEV_TEXT_MODEL text model (default google/gemini-2.5-flash)
JEV_TEXT_THINKING its thinking budget (default 0; thinking was 90% of the cost)
JEV_OBSERVE_LIMIT elements per observation (default 120)
JEV_DONE_BAR how sure the completion check must be (default 0.7)
JEV_IFRAMES=0 do not walk embedded documents
JEV_OUTPUT_DIR downloads, PDFs, traces, large response bodies
JEV_VIEWPORT_WIDTH / _HEIGHT default 1600×900 (admin consoles hide controls at 1280)
JEV_REPLAY_WAIT_MS wait before a replay step is healed (default 8000)
JEV_SETTLE_MS / JEV_SETTLE_QUIET_MS settle budgets for parsing (15 s) and restless (4 s) pages
JEV_DEBUG=1 print every offered operation, page class and field value

Known limits

  • Google Flights fails, and fails differently each time.
  • 30% autonomous success on the open web. See What it is not.
  • Borderline completion: one SPA case lands done or escalate depending on the run.
  • Tested on macOS only. No CI; the benchmarks cost real money, so they are run by hand.

Under the hood

docs/ENGINEERING.md explains why the loop owns progress, waiting, click correction and the completion check, and how a decision went from 7,226 tokens to ~1,500. It also lists the four fixes a real JSF console forced. Almost every rule in it exists because the simpler version failed on a real page first.

npm test                                   # 14 capability probes
node bench/hard/run.mjs                    # 6 hard cases
node bench/heal.mjs                        # record → replay → redesign → heal → exported specs
node bench/context.mjs                     # reading cost vs Playwright MCP, live pages
node bench/competitors/webvoyager.mjs A    # vs jev-ultrafast on WebVoyager

License

MIT

Keywords