# jev-ultrafast-mcp

> An MCP server that lets an AI agent hand browser work off instead of paying a turn per click. The
> agent sends a goal; the loop runs server-side, driven by a decision model that picks targets from
> an indexed table of the page's controls and never writes a selector. Actions address those refs
> in batches, assertions — not the model's opinion — decide whether it worked, and a discovered
> path replays with zero model calls. Drive it yourself instead if you prefer: it is the same
> tools. No Playwright, no Selenium, no screenshots in the loop: it speaks CDP directly to a Chrome
> you already have.

Works with any MCP client (WorkBuddy, Claude Code, Claude Desktop, Codex CLI, Cursor, VS Code,
Cline, Windsurf, Gemini CLI). MIT licensed. Requires Python ≥ 3.10 and any Chromium-family browser.

## Docs

- [README](https://github.com/jiawei686/jev-ultrafast-mcp/blob/main/README.md): install, the ten
  tools, configuration, FAQ, and a worked check-in example
- [docs/DESIGN.md](https://github.com/jiawei686/jev-ultrafast-mcp/blob/main/docs/DESIGN.md): the
  seven differentiators and the trade-offs behind them, measured against `browser-use/jev-ultrafast`
- [chrome-extension/README.md](https://github.com/jiawei686/jev-ultrafast-mcp/blob/main/chrome-extension/README.md):
  a Chrome extension that shows the element table for the page you are looking at, rendered by the
  server's own observer and a port of its renderer
- [CHANGELOG.md](https://github.com/jiawei686/jev-ultrafast-mcp/blob/main/CHANGELOG.md)
- [CONTRIBUTING.md](https://github.com/jiawei686/jev-ultrafast-mcp/blob/main/CONTRIBUTING.md): the
  seven checks — `ruff`, `pytest`, `smoke.py`, `mcp_check.py`, `live_check.py`, `turbo_check.py`,
  `extension_check.py`
- [README.zh-CN.md](https://github.com/jiawei686/jev-ultrafast-mcp/blob/main/README.zh-CN.md):
  Chinese translation of the same

## Tools

- `browser_goal(goal, session, max_steps, verify)` — hand the whole goal over: a decision model
  drives the loop server-side, so the caller spends one turn rather than one per action. Reports
  what it cost (`turbo: N decisions · N tokens · Ns model + Ns page · Ns wall`).
- `browser_open(url, session, hint)` — open a URL in a background tab it owns, return the element table
- `browser_observe(session, mode, include_text, include_json)` — re-read the page; `mode=auto` emits a delta
- `browser_act(ops, session, dry_run, stop_on_error, observe_after)` — many ops in one round trip
- `browser_assert(checks, session)` — deterministic PASS/FAIL, no model judgement
- `browser_macro(action, session, name, params, ...)` — record a flow, replay it at zero model cost
- `browser_tabs`, `browser_sessions`, `browser_close`, `browser_doctor` — tabs, sessions, teardown, self-check

## Notes for a reader deciding whether to use this

- The reason to run it is the handoff: a browser flow is a loop, and here the loop can run in the
  server instead of in the calling agent's context. `browser_goal` is one tool call, and `verify`
  is checked by code afterwards — a passing assertion overrules the model's own claim of success.
- `browser_open`, `browser_observe`, `browser_act`, `browser_assert`, `browser_macro` and the
  tab/session tools make **no network calls and need no API key**. Nothing about the page leaves
  the machine.
- `browser_goal` is the one part that calls out, and it is opt-in. It sends the goal and the
  current element table to a decision model, so it needs `TYPESAFE_API_KEY`, or
  `OPENROUTER_API_KEY` with `TYPESAFE_BASE_URL` pointed at
  `https://openrouter.ai/api/alpha/decisions`. Without either it reports `turbo_unavailable:` and
  executes nothing.
- The model never emits a selector, a coordinate or JS. It picks a `ref` from the element table; the
  server turns that into a real click, and refuses with a reason (`occluded`, `detached`,
  `page_changed`, `needs_confirmation`) rather than guessing.
- Destructive-sounding clicks are held back as `needs_confirmation`, `JEVMCP_ALLOW_DOMAINS` pins
  navigation to a set of hosts, and secret-looking fields are redacted from observations.
- It does not look at pixels, so a captcha or a canvas-only app is out of scope by design.
