Install
$ agentstack add mcp-jiawei686-jev-ultrafast-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
jev-ultrafast-mcp
[](https://github.com/jiawei686/jev-ultrafast-mcp/actions/workflows/ci.yml) [](https://github.com/jiawei686/jev-ultrafast-mcp/blob/main/LICENSE) [](https://github.com/jiawei686/jev-ultrafast-mcp/blob/main/pyproject.toml)
English · 简体中文
Hand the browser work off — an MCP server that drives the page for your agent.
Your agent should not be opening the browser at all. A browser task goes over whole — the URL, the goal, and the check that proves it — and the loop runs on the server. One tool call instead of twenty. Three seconds instead of a minute. A cent instead of a frontier model's context. And it never invents a target: it picks from what the page actually has, and the server refuses rather than guesses.
What it cost. A cent for the whole day, and a cent is all of it:
Quick start
Three commands, then restart your client.
git clone https://github.com/jiawei686/jev-ultrafast-mcp.git
cd jev-ultrafast-mcp
python3 -m venv .venv
.venv/bin/pip install -e . # Windows: .venv\Scripts\pip install -e .
python scripts/install.py # finds your MCP clients and writes their config
install.py looks for WorkBuddy, Claude Code, Claude Desktop, Codex CLI, Cursor, VS Code, Cline, Windsurf and Gemini CLI, and writes the format each one expects — merging into your existing config and saving a .bak first. Needs Python ≥ 3.10 and any Chromium-family browser.
Restart the client, and then just say what you want:
> You: Set this form to 3 adults, tick Nonstop only, then submit it. > Your agent: browser_goal(goal=…, url=…, verify=[…]) — one call; the page is opened and the > loop runs server-side, and the result is checked by code afterwards. > ([what that costs](#cheap-and-fast-and-here-is-the-bill))
> You: Open example.com and tell me what the page says. > Your agent: browser_open → reads the element table → answers — a look is not a task, so it > does not need the model. > ([verbatim run](#what-a-session-actually-looks-like))
Restarted and the tools are not there? Some clients make you approve the server once. In WorkBuddy that is Connectors → Custom connectors → Trust. The approval is remembered against the config itself, so if you later edit the config it asks once more.
Installation
No checkout needed if you would rather install it as a package. It is on PyPI, so the name is enough:
uvx jev-ultrafast-mcp # run it straight from PyPI, nothing installed
pip install jev-ultrafast-mcp # or install it yourself
A client config wants a stable interpreter path rather than uvx's cache, so:
python3 -m venv ~/.jev-ultrafast-mcp/venv
~/.jev-ultrafast-mcp/venv/bin/pip install jev-ultrafast-mcp
That gives you a jev-ultrafast-mcp console script and a stable interpreter path to put in a client config — verified against the latest mcp SDK on Python 3.13, every one of the ten tools listed.
scripts/install.py is the other half: it finds your MCP clients and writes the config each one expects, merging into the existing file and saving a .bak first.
python scripts/install.py --list # what is installed, and the file each one reads
python scripts/install.py --print # show the config it would write, change nothing
python scripts/install.py -c cursor,codex # only these two
python scripts/install.py --headed # keep a visible browser window
python scripts/install.py --allow-domains example.com,*.example.org
python scripts/install.py --uninstall # take the entry back out
Runtime dependencies: mcp, websockets, httpx. No Playwright, no Selenium, no browser-harness.
Cheap and fast, and here is the bill
A three-step goal on a real page, driven by browser_goal. This is everything your agent sent and everything it got back — one turn, and the page never entered its context:
browser_goal(
goal="On this flight search form: set Passengers to 3 adults, tick the 'Nonstop only' "
"checkbox, then submit the search. Do not type into any city field.",
verify=[{"type": "text_contains", "text": "3 adults · nonstop"}],
)
goal: On this flight search form: set Passengers to 3 adults, …
status: done
steps: 3
turbo: 4 decisions · 14,626 tokens · 1.8s model + 1.1s page · 3.3s wall
trace:
1. SELECT e6 Passengers → ok (759ms model / 30ms browser)
2. TOGGLE e7 Nonstop only → ok (336ms model / 692ms browser)
3. CLICK e8 Search → ok (370ms model / 410ms browser)
4. DONE (conf 0.93)
verified: PASS
ok text_contains: '3 adults · nonstop' found in page text
What the second time costs. Nothing. The second time is a recorded macro, and a macro makes no model calls at all — it does not even need a key.
How long it took. 3.3 s wall for the whole goal: 1.8 s of model, 1.1 s of page. Every run prints that line itself, so the numbers are checkable rather than persuasive.
That run is not a mock-up. scripts/turbo_check.py reproduces it against a real Chrome and the real model, and then checks the page with code rather than trusting the model's account of its own work. The three actions — plus the reading and re-reading between them — all happened on the server. Your agent spent one turn and never saw an element table.
The division of labour is the whole design decision, so it is yours to make per task:
| | agent drives | browser_goal drives | |---|---|---| | Tool calls for a 3-step flow | 6+ (observe, act, observe, act…) | 1 | | Who holds the page in context | your agent | the decision model, server-side | | Per-step cost | one agent turn | one typed request, no screenshot | | Who names the target | the model writes a selector | the model picks a ref from the page's own table | | If it goes wrong | a wrong click, usually silent | the server refuses, with the reason | | Knowing it worked | the model's summary | code-checked assertion, which wins the disagreement | | Second time around | run the model again | macro replay, zero model calls |
What it is
Browser automation usually makes the agent do the driving: read the page, pick one element, act, read again to see whether that worked. Ten clicks is ten turns, the page passes through the agent's context every time, and a mis-click rarely announces itself.
This server can take that job instead. browser_goal is one tool call from your agent; the loop runs here, server-side, with Jev — TypeSafe's decision model — choosing each step. The model never writes a selector: it picks among the elements the page actually has, and the server refuses anything that is not on the page rather than guessing. When it stops, browser_assert checks the page it left behind in code, and a passing assertion outranks the model's own account of what it did.
Four things follow from that:
- One call, not one per click. The run above took a 3-step goal on a real page through
4 decisions, 14,626 tokens, 1.8 s model + 1.1 s page, 3.3 s wall — for one turn of your agent's context.
- Accurate by construction. A target is a
reffrom a numbered table of what is on the page,
not a selector or a coordinate the model invented, and the action is re-checked against the page before it runs.
- Free after the first run. Record the path once; replay costs zero model calls, works with no
key at all, and refuses to proceed when the page no longer matches.
- Text, not pixels. No screenshots, no HTML dumps. It speaks CDP straight to a Chrome you
already have — no Playwright, no Selenium, no screenshot pipeline.
Everything except browser_goal — browser_open, browser_observe, browser_act, browser_assert, browser_macro — needs no key, no account, and no network beyond the page itself, from any MCP client: WorkBuddy, Claude Code, Codex, Cursor or VS Code. If you would rather keep your hands on the wheel, that whole surface is still here.
browser_open → element table → browser_act [refs] → browser_assert
Inspired by browser-use/jev-ultrafast and TypeSafe's typed-question API. Independent project, not affiliated with either — see docs/DESIGN.md for what is different and why.
Contents · [Quick start](#quick-start) · [Cheap and fast](#cheap-and-fast-and-here-is-the-bill) · [What it is](#what-it-is) · [What a session looks like](#what-a-session-actually-looks-like) · [Connecting an agent](#connecting-an-agent) · [What you can ask it to do](#what-you-can-ask-it-to-do) · [What the agent reads](#what-the-agent-actually-reads) · [Why another browser MCP?](#why-another-browser-mcp) · [Tools](#tools) · [Configuration](#configuration) · [FAQ](#faq) · [Try it without an agent](#try-it-without-an-agent) · [See also](#see-also)
What a session actually looks like
You say:
> Open example.com and tell me what the page says.
Your agent does this, and this is everything it sees:
browser_open("https://example.com")
[obs#1] https://example.com/ "Example Domain" scroll=0/216 reachable=1/1
e1 lnk More information...
browser_observe()
[delta#2] … 1 element
= no change (1 element)
Then it answers. No screenshot was taken, no HTML was dumped, and the page never entered a model's context: your agent read the table and answered.
A more realistic one — searching a real site, with your agent doing the driving:
browser_open("https://duckduckgo.com")
e4 cmb* Search with DuckDuckGo ▸ ""
browser_act([{type, ref: "e4", text: "python asyncio tutorial"}, {keys, key: "Enter"}])
→ 2/2 ops ok, one round trip, page navigated
browser_observe()
[delta#3] https://duckduckgo.com/?…&q=python+asyncio+tutorial reachable=9/59
+ e5 lnk Python Asyncio Tutorial
+ e6 lnk Async IO in Python: A Complete Walkthrough
…
43 new, 0 changed, 0 gone
browser_assert([{url_contains, text: "q="}, {count_at_least, role: "link", min: 5}])
PASS
That is a verbatim run against the live web — scripts/live_check.py reproduces it end to end.
Connecting an agent
| Client | Config file install.py writes | After installing | |---|---|---| | WorkBuddy | ~/.workbuddy-ai/mcp.json (older installs: ~/.workbuddy/mcp.json) | restart, then Connectors → Custom connectors → Trust | | Claude Code | ~/.claude.json (user scope) | or claude mcp add --scope user … | | Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json | quit the app fully and reopen | | Codex CLI | ~/.codex/config.toml | codex mcp list to confirm | | Cursor | ~/.cursor/mcp.json | reload the window | | VS Code (Copilot) | …/Code/User/mcp.json | Agent mode only — not Ask/Edit | | Cline | …/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json | reload the window | | Windsurf | ~/.codeium/windsurf/mcp_config.json | reload the window | | Gemini CLI | ~/.gemini/settings.json | gemini mcp list to confirm |
Manual setup — if you would rather not run the installer
Every client below needs the same three facts: an absolute interpreter path, the module, and one environment variable. Substitute your own path for /ABS/PATH.
WorkBuddy — ~/.workbuddy-ai/mcp.json
WorkBuddy reads its config directory from WORKBUDDY_CONFIG_DIR and otherwise falls back to ~/.workbuddy. A machine can carry both — an older app alongside the current one — and writing the one the app is not reading registers nothing and logs nothing. install.py resolves this the same way the app does and tells you when it had to choose.
Then restart the app before looking for the tools. The config file is only watched if it already existed when the app launched, so a freshly created one is invisible until the next start. After the restart the server appears as a first connection, and you approve it once.
{
"mcpServers": {
"jev-ultrafast-mcp": {
"command": "/ABS/PATH/jev-ultrafast-mcp/.venv/bin/python",
"args": ["-m", "jev_ultrafast_mcp"],
"env": { "JEVMCP_HEADLESS": "1" }
}
}
}
Claude Code
claude mcp add --scope user jev-ultrafast-mcp \
--env JEVMCP_HEADLESS=1 \
-- /ABS/PATH/jev-ultrafast-mcp/.venv/bin/python -m jev_ultrafast_mcp
Or write the same mcpServers object by hand: ~/.claude.json for user scope, .mcp.json in a project for team scope (committed to git).
Codex CLI — ~/.codex/config.toml. Codex uses TOML, and the table is mcp_servers, not mcpServers:
[mcp_servers.jev-ultrafast-mcp]
command = "/ABS/PATH/jev-ultrafast-mcp/.venv/bin/python"
args = ["-m", "jev_ultrafast_mcp"]
startup_timeout_sec = 20
[mcp_servers.jev-ultrafast-mcp.env]
JEVMCP_HEADLESS = "1"
The same entry works as codex mcp add jev-ultrafast-mcp --env JEVMCP_HEADLESS=1 -- /ABS/PATH/…/python -m jev_ultrafast_mcp.
Cursor — ~/.cursor/mcp.json for every project, .cursor/mcp.json for one. Same mcpServers object as WorkBuddy.
VS Code (Copilot) — .vscode/mcp.json, or Command Palette → MCP: Open User Configuration for all workspaces. VS Code is the odd one out twice over: the key is servers, and every entry must declare "type": "stdio" or it is silently skipped.
{
"servers": {
"jev-ultrafast-mcp": {
"type": "stdio",
"command": "/ABS/PATH/jev-ultrafast-mcp/.venv/bin/python",
"args": ["-m", "jev_ultrafast_mcp"],
"env": { "JEVMCP_HEADLESS": "1" }
}
}
}
Claude Desktop — claude_desktop_config.json (%APPDATA%\Claude\ on Windows), same mcpServers object. Restart the app from the tray, not just the window.
The browser does not start until the first browser_open, and the tab it drives is a background tab it owns — focus emulation keeps animations and menus running without stealing your window.
Making sure your agent actually hands it over
Pointing the client at the server is half of it. The other half is that the agent has to know to hand over — and that part is not automatic everywhere.
A server sends a short instructions block when a client connects, and this one's first rule is that a browser task goes to browser_goal, in one call, with the URL. Clients that read it behave. Not all of them do: WorkBuddy delivers a server's tools to the model and drops its instructions — measured, not assumed: the tool schemas are in the recorded request payload, the instructions text is not. A host in that position does the obvious thing and drives the page itself, one call per click, which is exactly the work this server exists to take away.
Two ways to close that gap — either is enough:
- Install the skill.
skills/jev-ultrafast-mcp/SKILL.md
carries the same rule in the form a client reads as a skill, plus the traps that waste a run. Copy it into your client's skills folder (~/.workbuddy/skills/ for WorkBuddy):
``bash mkdir -p ~/.workbuddy/skills/jev-ultrafast-mcp cp /path/to/jev-ultrafast-mcp/skills/jev-ultrafast-mcp/SKILL.md ~/.workbuddy/skills/jev-ultrafast-mcp/ ``
- Or say it once. "Browser tasks go to
browser_goal" is enough for most sessions — an agent
told that keeps doing it.
How to tell it took. Ask for something that needs a click. If browser_goal comes back with a url inside the call, the handoff is live. If the agent opens the page and starts walking the element table for you instead, the rule did not arrive — install the skill, or say it once.
What you can ask it to do
| Say this | What happens | |---|---| | "Fill in this form and submit it" | handed over whole —
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: jiawei686
- Source: jiawei686/jev-ultrafast-mcp
- License: MIT
- Homepage: https://pypi.org/project/jev-ultrafast-mcp/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.