关于 jev-ultrafast-mcp
jev-ultrafast-mcp 是供 Agent 使用的 MCP 服务,可在服务端执行浏览器任务。它提供带代码验证的目标式操作循环,以及较细粒度的页面检查和操作,并以页面元素表而非截图作为依据。
主要功能
- 01服务端浏览器任务循环
- 02页面元素表与引用标识
- 03代码验证断言
- 04录制并重放宏
- 05MCP 客户端配置安装器
适用场景
- 01提交表单并验证结果
- 02不截取屏幕图像而读取页面文本
- 03重放已记录的浏览器任务
MCP 相关
它向 MCP 客户端提供浏览器自动化工具,包括目标式执行、页面打开与观察、操作、断言和宏。附带的安装器可检测受支持的客户端,并将服务配置合并到现有配置文件中。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
10收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 是 | |
| hint | string | 否 | |
| session | string | 否 |
详细介绍
jev-ultrafast-mcp
English · 简体中文

把浏览器操作交出去——一个为你的 Agent 操控页面的 MCP 服务。
你的 Agent 根本不该打开浏览器。浏览器任务会一次性完整交给服务端——包括 URL、目标和证明任务完成的检查。整个循环都在服务端运行。一次工具调用,而不是二十次。三秒,而不是一分钟。花费一分钱,而不是消耗前沿模型的上下文。而且它绝不会凭空编造目标:它只会从页面实际存在的内容中选择,服务端宁可拒绝,也不会猜测。
花费。 一整天只花一分钱,而这一分钱就是全部花费:

快速开始
运行三条命令,然后重启客户端。
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 会查找 WorkBuddy、Claude Code、Claude Desktop、Codex CLI、Cursor、VS Code、Cline、Windsurf 和 Gemini CLI,并按每个客户端所需的格式写入配置——合并到现有配置中,并先保存一个 .bak 备份。需要 Python ≥ 3.10 和任意 Chromium 系浏览器。
重启客户端,然后直接说出你的需求:
你: 将此表单设为 3 位成人,勾选仅直飞,然后提交。 你的 Agent:
browser_goal(goal=…, url=…, verify=[…])——只需一次调用;页面会被打开,循环在服务端运行,之后由代码检查结果。 (具体花费)
你: 打开 example.com,告诉我页面上写了什么。 你的 Agent:
browser_open→ 读取元素表 → 作答——查看页面不算任务,因此不需要模型。 (一次实际运行)
重启后却看不到这些工具? 有些客户端需要你先批准一次该服务。在 WorkBuddy 中,路径是连接器 → 自定义连接器 → 信任。批准记录会与配置文件本身关联,因此如果你之后编辑配置,系统会再次询问一次。
安装
如果你更愿意将它作为软件包安装,就不需要检出代码仓库。它已发布到 PyPI,只需使用软件包名称:
uvx jev-ultrafast-mcp # run it straight from PyPI, nothing installed
pip install jev-ultrafast-mcp # or install it yourself
客户端配置需要稳定的解释器路径,而不是 uvx 的缓存路径,因此:
python3 -m venv ~/.jev-ultrafast-mcp/venv
~/.jev-ultrafast-mcp/venv/bin/pip install jev-ultrafast-mcp
这样会生成一个 jev-ultrafast-mcp 控制台脚本,以及可写入客户端配置的稳定解释器路径——已在 Python 3.13 上使用最新的 mcp SDK 验证,列出的十种工具均已验证。
scripts/install.py 是安装流程的另一部分:它会查找你的 MCP 客户端,并按每个客户端所需的格式写入配置,合并到现有文件中,并先保存一个 .bak 备份。
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
运行时依赖:mcp、websockets、httpx。不需要 Playwright、Selenium 或 browser-harness。
低成本且快速,账单如下
在真实页面上,通过 browser_goal 完成三步目标。这就是你的 Agent 发送和收到的全部内容——一轮交互,页面从未进入其上下文:
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
第二次运行的成本。 无。第二次运行时会执行录制好的宏,而宏完全不会调用模型——甚至不需要密钥。
耗时。 整个目标耗时 3.3 秒:模型耗时 1.8 秒,页面耗时 1.1 秒。每次运行都会自行打印这行数据,因此这些数字可以核验,而非仅仅用于说服。
这次运行不是模拟。scripts/turbo_check.py 会在真实 Chrome 和真实模型上重现整个过程,然后用代码检查页面,而不是相信模型对自身工作的描述。三项操作——以及它们之间的读取和重新读取——都在服务端完成。你的 Agent 只花了一轮交互,而且从未看到元素表。
分工方式是整个设计的关键,因此你可以针对每项任务自行决定:
| 由 Agent 操作 | 由 browser_goal 操作 | |
|---|---|---|
| 完成三步流程所需的工具调用 | 6 次以上(观察、操作、观察、操作……) | 1 次 |
| 谁在上下文中持有页面 | 你的 Agent | 决策模型,在服务端 |
| 每一步的成本 | 一轮 Agent 交互 | 一条有类型的请求,无需截图 |
| 谁指定目标 | 模型编写选择器 | 模型从页面自身的表格中选择一个 ref |
| 出错时的处理 | 点击错误,通常悄无声息 | 服务端会拒绝,并说明原因 |
| 如何确认操作成功 | 模型的总结 | 经代码检查的断言;若有分歧,以断言为准 |
| 再次运行 | 再运行一次模型 | 重放宏,不调用模型 |
它是什么
浏览器自动化通常让 Agent 来驾驶:读取页面,选中一个元素,执行操作,再次读取以确认是否成功。点击 10 次就要交互 10 轮,页面每次都会经过 Agent 的上下文,而且误点很少会给出提示。
这个服务可以接手这项工作。browser_goal 是 Agent 的一次工具调用;循环在服务端运行,由 Jev(TypeSafe 的决策模型)选择每一步。模型从不编写选择器:它只会从页面实际包含的元素中进行选择,服务端会拒绝任何不在页面上的元素,而不是猜测。停止后,browser_assert 会通过代码检查它留下的页面;断言通过的优先级高于模型自己对操作结果的描述。
由此带来四点:
- 一次调用,而不是每次点击调用一次。 上面的运行在真实页面上完成了一个包含 3 个步骤的目标,经过 4 次决策,14,626 个 token,模型耗时 1.8 秒 + 页面耗时 1.1 秒,实际耗时 3.3 秒——只占用 Agent 上下文的一轮交互。
- 从设计上保证准确。 目标是页面内容编号表中的一个
ref,而不是模型编造的选择器或坐标;操作执行前还会再次根据页面进行检查。 - 首次运行后免费。 记录一次操作路径;回放无需任何模型调用,无需密钥即可运行,并且在页面不再匹配时会拒绝继续。
- 文本,而非像素。 不截取屏幕截图,也不导出 HTML。它直接通过 CDP 与你已有的 Chrome 通信——不需要 Playwright、Selenium 或截图流水线。
从任何 MCP 客户端——WorkBuddy、Claude Code、Codex、Cursor 或 VS Code——都可以使用 browser_goal 以外的所有功能:browser_open、browser_observe、browser_act、browser_assert、browser_macro,这些功能无需密钥、账号,也无需页面本身之外的网络连接。如果你更愿意亲自掌舵,所有这些功能也都可以照常使用。
browser_open → element table → browser_act [refs] → browser_assert
灵感来自 browser-use/jev-ultrafast 和 TypeSafe 的类型化提问 API。这是一个独立项目,与两者均无关联——不同之处及原因请参阅 docs/DESIGN.md。
目录 · 快速开始 · 低成本且快速 · 它是什么 · 会话实际是什么样 · 连接 Agent · 可以让它做什么 · Agent 实际读取的内容 · 为何还需要另一个浏览器 MCP? · 工具 · 配置 · 常见问题 · 不使用 Agent 进行试用 · 另请参阅
会话实际是什么样
你说:
打开 example.com,告诉我页面上写了什么。
你的 Agent 会这样操作,这就是它看到的全部内容:
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)
然后它会给出回答。没有截取屏幕截图,没有导出 HTML,页面也从未进入模型的上下文:你的 Agent 读取了表格并给出回答。
再看一个更贴近实际的例子——搜索一个真实网站,由你的 Agent 驾驶:
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
这是对实时网页进行的原样运行——scripts/live_check.py 可以端到端复现该过程。
连接 Agent
| 客户端 | install.py 写入的配置文件 | 安装后 |
|---|---|---|
| WorkBuddy | ~/.workbuddy-ai/mcp.json(旧版安装:~/.workbuddy/mcp.json) | 重启,然后选择 Connectors → Custom connectors → Trust |
| Claude Code | ~/.claude.json(用户范围) | 或运行 claude mcp add --scope user … |
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json | 完全退出应用后重新打开 |
| Codex CLI | ~/.codex/config.toml | 运行 codex mcp list 以确认 |
| Cursor | ~/.cursor/mcp.json | 重新加载窗口 |
| VS Code (Copilot) | …/Code/User/mcp.json | 仅限 Agent 模式,不适用于 Ask/Edit |
| Cline | …/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json | 重新加载窗口 |
| Windsurf | ~/.codeium/windsurf/mcp_config.json | 重新加载窗口 |
| Gemini CLI | ~/.gemini/settings.json | 运行 gemini mcp list 以确认 |
手动设置 — 如果你不想运行安装程序
以下每个客户端都需要相同的三项信息:解释器的绝对路径、模块和一个环境变量。将 /ABS/PATH 替换为你自己的路径。
WorkBuddy — ~/.workbuddy-ai/mcp.json
WorkBuddy 从 WORKBUDDY_CONFIG_DIR 读取配置目录,否则会回退到 ~/.workbuddy。一台机器上可能同时存在这两个目录——旧版应用和当前版本并存时就是如此。如果写入的配置文件不是应用实际读取的文件,既不会注册,也不会记录日志。install.py 会按照与应用相同的方式解析配置目录,并在需要选择时告知你。
然后,在查找工具之前先重启应用。 只有应用启动时配置文件已存在,它才会监视该文件,因此新创建的配置文件要等到下次启动才会生效。重启后,服务会作为一个新的连接显示出来,你只需批准一次。
{
"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
或者手动编写相同的 mcpServers 对象:用户范围使用 ~/.claude.json,团队范围则使用项目中的 .mcp.json(提交到 git)。
Codex CLI — ~/.codex/config.toml。Codex 使用 TOML,表名是 mcp_servers,而不是 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"
同一条配置也可以通过以下命令添加:codex mcp add jev-ultrafast-mcp --env JEVMCP_HEADLESS=1 -- /ABS/PATH/…/python -m jev_ultrafast_mcp。
Cursor — 所有项目使用 ~/.cursor/mcp.json,单个项目使用 .cursor/mcp.json。与 WorkBuddy 使用相同的 mcpServers 对象。
VS Code (Copilot) — 使用 .vscode/mcp.json,或选择命令面板 → MCP: Open User Configuration,为所有工作区配置。VS Code 有两处与众不同:键名是 servers,并且每个条目都必须声明 "type": "stdio",否则会被静默跳过。
{
"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(Windows 上位于 %APPDATA%\Claude\),使用相同的 mcpServers 对象。请从系统托盘重启应用,而不只是关闭窗口。
浏览器不会在首次调用 browser_open 之前启动;它控制的标签页是它自行拥有的后台标签页——焦点模拟会让动画和菜单持续运行,同时不会抢占你的窗口。
确保你的 Agent 确实完成了交接
让客户端连接到服务只是其中一半。另一半是 Agent 必须知道要交接——而这在所有环境中都不是自动发生的。
客户端连接时,服务会发送一个简短的 instructions 区块,其中的第一条规则是:浏览器任务应通过一次调用发送到 browser_goal,并附上 URL。能读取这条规则的客户端会照做。但并非所有客户端都能做到:WorkBuddy 会将服务的工具提供给模型,却丢弃其
instructions——这是经过测量得出的结论,并非推测:记录的请求载荷中包含工具架构,却没有 instructions 文本。处于这种情况的宿主会采取显而易见的做法,自己操作页面,每次点击都调用一次工具,而这正是此服务旨在替你省去的工作。
有两种方法可以弥补这一差距——任选其一即可:
-
安装技能。
skills/jev-ultrafast-mcp/SKILL.md以客户端可读取的技能形式包含了相同规则,以及那些会浪费一次运行的陷阱。 将它复制到客户端的技能文件夹中(WorkBuddy 的文件夹为~/.workbuddy/skills/):mkdir -p ~/.workbuddy/skills/jev-ultrafast-mcp cp /path/to/jev-ultrafast-mcp/skills/jev-ultrafast-mcp/SKILL.md ~/.workbuddy/skills/jev-ultrafast-mcp/ -
或者说一次就够。 对大多数会话来说,只要说“浏览器任务交给
browser_goal”就够了——Agent 得到这条指示后会一直照做。
如何判断是否生效。 提出一个需要点击的任务。如果 browser_goal 在调用中包含 url,就说明交接已生效。如果 Agent 打开页面后开始替你遍历元素表,那就说明它没有收到这条规则——安装技能,或者说一次就够。
可以让它做什么
| 这样说 | 会发生什么 |
|---|---|
| “填写并提交这份表单” | 整个任务都会交接——一次 browser_goal 调用携带 URL、目标和检查项;循环在服务端运行 |
| “在预发布环境中走一遍这个流程,并告诉我是否成功” | 同样只需一次调用——verify 通过代码判定 PASS/FAIL,优先于模型自己的判断 |
| “明天再做一遍同样的事” | 录制一个 宏;重放不消耗模型调用,也完全不需要密钥 |
| “打开这个页面,告诉我上面写了什么” | 只是查看,不是任务:读取可见文本和控件——不需要模型,也不需要密钥 |
| “部署真的发布了吗?” | browser_assert 返回 PASS/FAIL,而不是主观判断 |
| “登录并下载上个月的发票” | 你只需手动登录一次;配置文件会持久保留 |
| “在预发布环境中点击完成结账” | 类似支付的按钮会返回 needs_confirmation |
它不是什么
说清楚这一点可以为所有人节省时间:
- 它不会查看像素。 验证码、图表、仅使用画布的应用——任何需要真实视觉判断的内容——都不在支持范围内。处理这类内容请使用截图和视觉 Agent,或者在此处使用
screenshot操作,为人工查看采集证据。 - 它不是网页抓取框架。 一次只运行一个浏览器会话。不支持代理轮换、并发或大规模爬取。
- 它不是供人使用的录制器。 没有点击录制界面;宏由执行任务的 Agent 在正常操作过程中录制。
Agent 实际读取的内容
不是 DOM 转储,也不是屏幕截图,而是一张列出它可以操作的控件的表格。每一行包含一个 ref
(元素编号)、角色代码、标记和可访问名称;可编辑项会显示当前值,可选项会显示其选项:
[obs#1] http://127.0.0.1:54409/fixture.html "Ultrafast Fixture" scroll=0/860 reachable=16/16
e1 lnk Home
e2 lnk About
e3 lnk Open popup
e4 inp* Where from? ▸ ""
e5 cmb* Where to? ▸ ""
e6 cmb Passengers ▸ 1 adult opts{1 adult=1 | 2 adults=2 | 3 adults=3 | 4 adults=4}
e7 chk· Nonstop only
e8 btn Search
e10 inp* Password ▸ ""
e11 file CV accept=.pdf,.txt
e12 btn Delete account
标记:* 可编辑 · » 屏幕外(服务会将其滚动到视野内) · ⊘ 被其他内容覆盖 ·
⊗ 存在但已禁用 · ⋮ 可打开菜单,先将鼠标悬停其上 · ▾ 已展开 · ✓/· 选中
状态。reachable=16/19 表示有三个控件存在,但当前被覆盖、位于屏幕外或已禁用——禁用项仍会列出,以便你看到表单正在等待什么;它绝不会被当作可供点击的选项交给你。
执行操作后,它只报告发生变化的内容——这是长循环中最大的节省:
[delta#2] http://127.0.0.1:54409/fixture.html "Ultrafast Fixture" reachable=16/16
~ e4 inp* Where from? ▸ "Zurich" (was "")
~ e7 chk✓ Nonstop only
2 changed, 0 new, 0 gone
在 Agent 循环中,未能完成任何操作的操作代价最高,因为模型会重试。因此,它会用一行明确说明:
[delta#3] … 16 elements
= no change (16 elements)
新增的行以 + 标记,消失的行以 - 标记。如果两个控件名称相同,该行会附带用于区分它们的上下文:
+ e17 btn Select @Zurich → Anywhere Option 1 · 1 adult · nonstop Select
+ e18 btn Select @Zurich → Anywhere Option 2 · 1 adult · nonstop Select
如果某个 ref 已不再指向任何内容,系统会拒绝操作并说明原因,而不是误点:
[{"op": "click", "ok": false, "ref": "e999", "error": "detached"}]
查看你自己页面上的表格
chrome-extension/
中的扩展程序就是查看该表格的窗口。以未打包的方式加载它,在任意页面上点击它,你就会看到与模型相同的行——这些行由同一个观察器绘制,并由同一渲染器的移植版本生成,因此弹出窗口中的 ref 与会话中的含义相同。页面的第二次读取会以差异形式渲染,这样你就能看到页面的变化。
它还能在循环中不使用模型的情况下运行宏——解析器、分发器和报告编写器都移植自服务本身的代码,因此在那里重放的内容与这里相同。
这两点也是它只请求四项权限、完全不请求主机访问权限的原因:activeTab(仅限你点击扩展程序时所在的标签页,不涉及其他内容)、scripting、storage 和 debugger。最后一项是重放的代价,并非捷径:element.click() 产生的事件会带有 isTrusted: false,网站有权忽略此类事件,因此要让重放的点击可信,就必须通过 DevTools 协议执行。扩展程序自己的
README 说明了这些权限带来的好处、代价,以及它拒绝执行的四种操作——这些操作会超出你指定的标签页范围。
为什么还需要另一个浏览器 MCP?
有两点不同,第一点正是它诞生的原因。
驾驭浏览器不是 Agent 的工作。 浏览器流程是一个循环,而在大多数服务中,这个循环都在调用方 Agent 中运行:读取页面,指出一个元素,等待,再次读取。两步还好,二十步就荒唐了——要用昂贵的上下文进行二十轮交互,只为完成一个小模型一次调用就能做到的事。在这里,循环在服务端运行:一次 browser_goal 调用就包含 URL、目标和检查,Agent 自始至终都不会亲自打开浏览器。手动工具仍然适用于两种情况——读取页面(这不是一项任务,不应该为此调用模型),以及未配置模型密钥时的备用方案。
模型永远不会凭空编造目标。 大多数浏览器 MCP 服务都会提供 CDP 基元——click_at_xy、CSS 选择器、evaluate。灵活性最大,安全性最低:错误的选择器可能悄无声息地失败,更糟的是,还可能点中错误的元素。在这里,目标是页面元素编号表中的一个 ref,如何将该 ref 转换为实际点击由服务端负责;服务端会拒绝操作,而不是猜测。这也让交接变得安全:无论由谁来驱动,都只能从页面实际存在的选项中选择,因此准确性不依赖它是否足够谨慎。
| 基于基元的浏览器 MCP | jev-ultrafast-mcp | |
|---|---|---|
| 谁运行循环 | 调用方 Agent,每一步都运行 | 服务端——一次 browser_goal 调用 |
| 如何指定目标 | 模型编写的选择器/坐标/JS | 元素表中的一个 ref |
| 额外的模型调用 | 无 | 每一步调用一个小型决策模型,且仅在 browser_goal 内调用 |
| 是否需要 API 密钥 | 无 | 浏览器工具无需密钥;只有 browser_goal 需要决策模型密钥 |
| Ref 的生命周期 | 不适用(Agent 每一步都要重新指定) | 在多次观察之间保持稳定 |
| 重新读取页面 | 每次都完整转储 | 增量——新增项为 +,更改项为 ~,移除项为 -,无更改为 = no change |
| 往返次数 | 每次操作一次 | 批处理——每次调用可执行多项操作 |
| 目标不明确时 | Agent 猜测 | 服务端会说明原因并拒绝操作 |
| Shadow DOM/iframe | 通常不支持 | 支持遍历,并能感知 frame 偏移量进行滚动 |
| 延迟渲染的页面 | 取决于 Agent 是否等待 | 限时等待元素出现 |
| 重复执行流程 | 重新运行模型 | 宏回放,无模型调用成本 |
| 如何确认操作成功 | 模型目测页面 | 使用确定性的 browser_assert,结果优先于模型判断 |
| 具有破坏性的点击 | 由模型自行决定 | needs_confirmation、域名范围限制、机密信息脱敏 |
批处理和增量变化并非只是表面功夫。在随附的端到端运行中,29 项操作及其后续观察共消耗 15.4 KB 上下文,其中 13.6 KB 为增量内容,1.8 KB 为完整表格——模型只需重新读取页面中发生变化的部分。
工具
共 10 个工具。大多数会话只需其中 4 个。
| 工具 | 描述 |
|---|---|
browser_open | 在独立标签页中打开 URL,并返回元素表 |
browser_observe | 重新读取页面:返回增量内容,或按需返回完整表格 |
browser_act | 在一次往返中执行一组操作,然后返回增量内容 |
browser_assert | 对页面执行确定性检查,不需要模型判断 |
browser_macro | 录制一次流程,然后回放,无需调用模型 |
browser_goal | 将整个任务交给决策模型,由它驱动页面 |
browser_tabs | 列出、打开、切换和关闭标签页 |
browser_sessions | 列出当前运行的浏览器会话 |
browser_close | 关闭会话 |
browser_doctor | 自检:找到的是哪个浏览器,以及浏览器是否有响应 |
browser_open(url, session="default", hint="")
在独立标签页中打开 URL,并返回完整的元素表。hint 用一行文字重述你的目标,并会原样回显。
browser_observe(session="default", mode="auto", include_text=True, include_json=False)
重新读取页面。auto 输出增量;full 强制输出完整表格,delta 强制输出差异。
= no change 表示上一个操作没有产生任何效果——更改策略,不要重试。
browser_act(ops, session="default", dry_run=False, stop_on_error=True, observe_after=True)
按顺序执行操作,在一次往返中完成,然后返回增量。
| 操作 | 字段 |
|---|---|
click | ref |
type | ref、text、clear=true、submit=false、slow |
select | ref、value(选项值或标签) |
toggle | ref、state(省略则切换状态) |
hover / upload | ref / ref、path |
keys | key("Enter"、"Meta+A"、"ArrowDown"),或 keys(列表)——单个裸字符属于文本,而非按键,因此会输入到当前获得焦点的控件中;如果是值不得离开页面的字段,则会被拒绝 |
scroll | dir、amount、ref |
nav / back / forward / reload | url(用于 nav) |
wait / wait_for_ref / wait_for_text / wait_for_load | ms / ref、timeout_ms / text / timeout_ms |
screenshot | path(shots 目录中的文件名)、full、format(jpeg 或 png) |
tab | action=list|new|switch|close、target_id、index、url |
eval | js——仅当 JEVMCP_ALLOW_JS=1 时可用 |
{"ops": [
{"op": "type", "ref": "e4", "text": "Zurich"},
{"op": "select", "ref": "e6", "value": "3 adults"},
{"op": "toggle", "ref": "e7"},
{"op": "click", "ref": "e8"}
]}
操作失败时会说明原因:occluded、detached、target_changed、page_changed、
needs_confirmation、blocked_by_policy。请使用 browser_observe,不要重试。
可访问名称符合确认规则(buy now、delete account、
unsubscribe 等)的控件,在操作携带 "confirm": true 之前会返回 needs_confirmation。这适用于所有会点击控件的操作,而不只是名为 click 的操作——toggle 也会按下控件。判断名称是否属于操作名称的角色(例如,标记为“Delete account”的复选框不会被此规则拦截,但按钮会)取自服务观察到的元素,而非操作本身,因此请求中的 "role" 无法绕过限制。type 也遵循同一规则:如果页面将字段标记为敏感,或其名称和角色表明它是敏感字段,该字段就属于敏感字段——也就是观察结果进行遮蔽时采用的并集,因此表格中值被隐藏的字段正是 type 会询问的字段。
对于标签页,优先使用 target_id,而非 index。索引是位置性的,每当标签页列表发生变化时都会重新编号,因此上次调用时读取的索引可能会指向另一个标签页。
browser_assert(checks, session="default")
确定性检查——不依赖模型判断是否成功。
{"checks": [
{"type": "url_matches", "pattern": "*/checkout*"},
{"type": "text_contains", "text": "Order confirmed"},
{"type": "element_exists", "role": "button", "name": "Continue"},
{"type": "value_equals", "ref": "e4", "value": "Zurich"},
{"type": "count_at_least", "role": "link", "min": 3}
]}
browser_macro(action, session="default", name="", params={}, ...)
record_start → 执行任务 → record_stop → run。回放不消耗模型调用:它会返回任务开始时所在的位置,并通过角色 + 可访问名称重新解析每个步骤;如果匹配不够可靠或存在歧义,就会拒绝操作,而不会误点。params 用于填充输入文本和 URL 中的 {{placeholders}}。
browser_goal(goal, url="", session="default", max_steps=20, verify=[...])
将整个任务交由其处理。传入 url 和目标后,页面便会在服务端通过 TypeSafe 推测式扇出(每一步发送一个请求)打开并操作直至完成——一次调用,一个轮次。若要从会话当前显示的页面继续操作,请省略 url。决策模型需要密钥:使用 Jev 自有 API 时需设置 TYPESAFE_API_KEY;或使用 JEV_PROVIDER=openrouter 时需设置 OPENROUTER_API_KEY(等效做法是将 TYPESAFE_BASE_URL 指向 OpenRouter 的决策路由)。如果提供了 verify 检查项,则返回 verified: PASS/FAIL。
读取页面不算任务:browser_open、browser_observe 和 browser_assert 都是直接、免费且无需密钥的,因此查看页面成本很低。只有需要更改页面时才交由其处理。
每次运行都会报告自身的费用——turbo: 4 decisions · 14,626 tokens · 1.8s model + 1.1s page · 3.3s wall——因此答案会显示交接所花的费用,以及总耗时中模型和页面分别占了多少。
决策模型出现的任何故障——缺少密钥、额度不足、无法访问、答案格式错误,或响应正文不是 JSON——都会返回 turbo_unavailable:,且不会执行任何操作。已执行步骤的跟踪记录会保留,因此即使运行在第五步失败,也仍会报告第一至第四步执行了什么。
status 主要是模型自己的总结,但循环也会写入该字段,其中值得留意的值包括:连续三次操作均未产生任何变化后出现 stopped: no progress——页面已无法再继续推进,因此运行会在此停止,而不会耗尽剩余的 max_steps 才发现这一点;以及预算耗尽时出现 stopped: hit max_steps。这两种状态刻意有所区别:前者表示已无事可做,后者则表示可能还有事可做。
verify 由代码检查,因此当总结与页面不一致时,以断言为准:如果页面通过了你的检查,运行就会报告 status: done,无论模型怎么说;跟踪记录也会注明代码推翻了模型的判断。目标的最后一步会移除其操作对象时,通常就会出现这种情况——点击签到按钮后,按钮消失,模型发现已无事可做,于是在目标实际上已成功的情况下报告 BLOCKED。
browser_tabs · browser_sessions · browser_close · browser_doctor
管理标签页(列出/新建/切换/关闭)、列出会话、拆除会话,以及执行自检,报告找到的浏览器及其是否可访问。
Configuration
所有选项均为可选;默认值才是重点。
| Variable | Required | Default | Description |
|---|---|---|---|
| 否 | JEVMCP_CHROME | 自动检测 | Chrome/Chromium/Edge/Brave 可执行文件 |
| 否 | JEVMCP_MODE | launch | launch 启动浏览器,或 attach 连接到正在运行的 CDP 端点 |
| 否 | JEVMCP_CDP_URL | — | 当 mode=attach 时使用 http://127.0.0.1:9222,或使用 ws:// URL 跳过发现步骤 |
| 否 | JEVMCP_ATTACH_PROFILE_DIR | (浏览器默认值) | 要连接的浏览器的数据目录;如果未自动找到 DevToolsActivePort,则使用此目录 |
| 否 | JEVMCP_HEADLESS | 1 | 设为 0 可显示窗口 |
| 否 | JEVMCP_FOREGROUND | 0 | 设为 1 可激活受管理的标签页 |
| 否 | JEVMCP_SANDBOX | auto | auto 会在浏览器启动时中止的情况下,使用 --no-sandbox 重试 |
| 否 | JEVMCP_WINDOW | 1280x860 | 浏览器窗口大小 |
| 否 | JEVMCP_PROFILE_DIR | ~/.jev-ultrafast-mcp/chrome-profile | 持久化配置文件——登录一次,保持登录状态 |
| 否 | JEVMCP_ALLOW_DOMAINS | (全部) | 逗号分隔;拒绝导航到其他位置 |
| 否 | JEVMCP_DENY_DOMAINS | (无) | 逗号分隔的屏蔽列表 |
| 否 | JEVMCP_CONFIRM_PATTERNS | pay / delete / unsubscribe … | 点击匹配项时需要设置 "confirm": true |
| 否 | JEVMCP_ALLOW_JS | 0 | 启用 eval 和 js 断言 |
| 否 | JEVMCP_ALLOW_UPLOADS | 1 | 控制 upload 操作是否可用 |
| 否 | JEVMCP_MAX_ACTIONS | 250 | 元素表上限,按实用性筛选 |
| 否 | JEVMCP_MAX_TEXT | 6000 | 每次观察的可见文本上限 |
| 否 | JEVMCP_SETTLE_TIMEOUT | 4.0 | 打开 URL 后,等待页面停止获取内容且元素表不再变化的时长 |
| 否 | JEVMCP_SETTLE_POLL_MS | 120 | 等待期间重新读取的频率 |
| 否 | JEVMCP_STATE_DIR | ~/.jev-ultrafast-mcp | 配置文件、宏和屏幕截图 |
| 否 | JEV_PROVIDER | typesafe | 为决策模型付费的 API:typesafe(Jev 自有)或 openrouter |
| 否 | TYPESAFE_API_KEY | — | Jev 自有 API 的密钥 |
| 否 | TYPESAFE_BASE_URL | https://api.typesafe.ai/v1/systemone | 决策模型所在位置;自定义端点;未设置 JEV_PROVIDER 时据此推断提供商 |
| 否 | OPENROUTER_API_KEY | — | 当 JEV_PROVIDER=openrouter 时,用于 OpenRouter 决策路由的密钥 |
| 否 | TYPESAFE_MODEL | jev-latest | 决策模型标识 |
| 否 | TEXT_MODEL_API_KEY | — | 可选;仅供 browser_goal 使用的小型文本辅助工具使用,用于在字段中输入值。未设置时,该辅助工具会沿用决策模型的提供商 |
| 否 | TEXT_MODEL_BASE_URL | https://api.deepseek.com/v1 | 该辅助工具的端点;设置此项 或 TEXT_MODEL_API_KEY,即可选择不沿用决策模型的提供商 |
| 否 | TEXT_MODEL | deepseek-chat | 该辅助工具使用的模型;辅助工具沿用提供商时必须设置,因为 deepseek-chat 不是 OpenRouter 标识 |
JEVMCP_MODE=attach 是“使用我已打开的浏览器”的方式——当所需的登录状态已保存在你自己的配置文件中时,应选择这种方式。Chrome 144+ 通过 chrome://inspect/#remote-debugging 提供此功能;其服务会按设计对 /json/version 返回 404;jev 会改用 DevToolsActivePort,而不会将其视为“没有服务在监听”。连接模式只会操作它打开的标签页:browser_close 会断开连接,而不会退出浏览器;服务器退出时也一样。你的其他窗口及其中的会话绝不会被关闭。
上表中最后八行之前的所有设置都在本地使用:用于配置你计算机上的浏览器。只有决策模型相关设置会与网络通信,而且仅在实际运行 browser_goal 时才会通信。
这个决策模型有两种路由,JEV_PROVIDER 用于标明你使用的是哪一种。typesafe 是 Jev 自有的 API。openrouter 则是通过 OpenRouter 的决策路由使用同一个模型,无需 TypeSafe 账号,也是早于该变量存在的路由:无论使用哪种路由,TYPESAFE_BASE_URL 仍会覆盖 URL;如果未设置 JEV_PROVIDER,系统会根据这个 URL 推断提供方,因此在该变量出现前编写的配置仍可原样使用。
只有 OpenRouter 路由还提供聊天 API,因此只有该路由能让文本助手继承配置。设置 JEV_PROVIDER=openrouter,并通过 TEXT_MODEL 指定聊天模型后,一个 OPENROUTER_API_KEY 就能同时用于两者。Jev 自有 API 只回答类型化问题,从不撰写散文,因此在该路由下使用 TYPE_TEXT 需要通过 TEXT_MODEL_API_KEY 单独配置聊天提供方。无论哪种情况,密钥和 URL 始终取自同一个提供方——借用其他提供方的密钥只会得到一条指出你未调用的公司的 401 错误,而根据错误信息来自错误提供方来诊断运行结果,就等于没人能诊断这次运行。
在让 Agent 访问你自己的账号之前,值得先设置以下两项:
JEVMCP_ALLOW_DOMAINS 将浏览器限制在指定的主机集合内,拒绝访问其他所有主机;设置持久化的 JEVMCP_PROFILE_DIR,则意味着你只需手动登录一次,而不必把密码教给模型。
常见问题
所以这只是另一个替你做事的模型?谁来做主?
由你做主,并由你为每项任务做选择。browser_goal 会让 Jev——一个小型决策模型——负责一个目标:逐步选择要操作页面上的哪个元素。它不是通用 Agent,不会在不同目标之间保留记忆,也不会编写代码或选择器,只会从服务提供的选项中进行选择。你的 Agent 仍决定要它做什么,而 verify 会判断操作是否真的成功。如果你希望每一步都亲自参与,就不要调用这个工具——除此之外,什么也不会被发送到任何地方。
我需要 API 密钥或账号吗?
使用浏览器工具不需要。browser_open、browser_observe、browser_act、browser_assert、browser_macro 以及标签页/会话工具都不会向外部发起调用——没有遥测,不会回传任何信息,任何内容都不会离开你的电脑。browser_goal 是例外,而且需要主动选择使用:它会将你的目标和当前元素表发送给决策模型,因此需要密钥。不使用这个工具,页面上的任何信息都不会被发送到任何地方。
浏览器窗口会弹出来并占用我的屏幕吗?
不会。默认情况下,它会在无头模式下运行,并操作由它控制的后台标签页——动画和菜单仍能正常使用,但不会抢占焦点。如果你想观察运行过程,可以使用 --headed(或 JEVMCP_HEADLESS=0)显示窗口。
如何在已登录的网站上使用它?
将 JEVMCP_PROFILE_DIR 设置为持久化目录,手动打开一次浏览器并登录,会话就会被记住。这比把密码教给 Agent 好得多——而且,当你输入密码时,观察结果中的密码字段会被隐藏。
它能直接使用我已经打开、且已登录的浏览器吗?
可以。使用 JEVMCP_MODE=attach 加上 JEVMCP_CDP_URL=http://127.0.0.1:9222,即可操作你自己的 Chrome。在 Chrome 144+ 中,你可以通过 chrome://inspect/#remote-debugging 启用调试——无需重启,因此标签页和登录状态都会保留——然后 Chrome 会要求你批准客户端。首次连接会等待你点击批准,因此请稍等片刻再判断是否失败。
每次操作都要批准这次点击吗?
不用。批准是针对整个浏览器会话,而不是针对每个连接或每次操作。批准一次后,之后的所有操作都会通过同一个已打开的 WebSocket 进行,不会再弹出提示——即便是新启动的进程也一样(实测:点击后 20 分钟,三个新进程连接后均获准,且没有提示)。因此,每个浏览器会话只需点击一次,而不是每次操作都要点击。若想连这一次点击也省掉,请使用默认的 JEVMCP_MODE=launch:它会在真实调试端口上启动自己的浏览器,完全不会弹出批准对话框,但需要在该配置文件中登录一次。
curl http://127.0.0.1:9222/json/version 返回 404。调试功能真的开启了吗?
很可能开启了。chrome://inspect/#remote-debugging 背后的服务仅支持 WebSocket,并且有意不提供 HTTP 发现端点,因此这里返回 404 是文档所述的行为,并不表示配置有问题(虽然两者都会显示端口 9222,但它与 --remote-debugging-port=9222 并不是一回事)。jev 不依赖该端点:当 /json/version 没有响应时,它会从 Chrome 的 DevToolsActivePort 文件中读取端口和浏览器 WebSocket 路径。如果浏览器将数据目录放在了不常见的位置,请将 JEVMCP_ATTACH_PROFILE_DIR 指向该目录。
什么都没发生,页面看起来是空的。
由 JavaScript 渲染的页面可能会短暂显示为空白。打开 URL 后,服务会等待页面停止获取数据,且元素表不再变化(最长等待 JEVMCP_SETTLE_TIMEOUT),然后才将页面交给模型——仅等待页面静止还不够,因为尚未获取程序包的应用只是一个空壳,而空壳完全可以保持静止。如果网站被 Cookie 墙或同意对话框挡住,元素表会显示出来——请留意观察结果标题中的遮罩警告。
有验证码。它能解决吗? 不能,这是有意为之——它不会查看像素。请使用能截图并进行视觉识别的 Agent 来处理。
它在 PyPI 上吗?在 MCP 注册表中吗?
在 PyPI 上,是的——使用 pip install jev-ultrafast-mcp 安装,或使用 uvx jev-ultrafast-mcp 运行,无需安装任何内容。目前还不在注册表中,但无需再手动处理任何事项:
server.json 已通过注册表的架构验证,发布工作流会在每个标签发布时通过 OIDC 提交,因此它会随下一次发布进入注册表。有关详情,请参阅
发布。
它与 Playwright MCP 有什么不同? Playwright 的服务会暴露页面原语;Agent 负责编写选择器和坐标。这个工具会暴露带编号的控件表,并拒绝有歧义的目标。如果你需要像素级控制或成熟的录制测试生态,请使用 Playwright。如果你希望 Agent 不会在毫无察觉的情况下点错按钮,请使用这个工具。
它是 browser-use 的替代方案吗?
两者从相反的方向解决同一个问题。browser-use
是一个在进程内运行 Agent 循环的库;这是一个 MCP 服务,让你现有的 Agent 拥有同类操作能力。这里的可选 turbo 路径移植自
browser-use/jev-ultrafast,它会针对每个步骤向决策模型提出一个有类型的问题,而不是使用自由格式文本。
把它放开来操作我的账户安全吗?
它的设计前提是不能盲目信任它。听起来具有破坏性的点击会返回 needs_confirmation,而不会执行;JEVMCP_ALLOW_DOMAINS 会拒绝导航到你未列出的域名;敏感字段会被隐藏;除非你主动启用,否则 eval 处于关闭状态。建议先设置域名允许列表,并使用一个即便弄坏了也无所谓的账户。
某个值不得离开页面的字段会在表格中打码,输入时需要设置 "confirm": true,写入宏时会记作 {{secret}},而非明文。有两个操作可以向其中输入文本,第二个很容易被忽略:keys 搭配单个字符({"op": "keys", "keys": "a"})会发送 Input.insertText,而不是按下按键,因此会在当前获得焦点的位置输入文本。敏感字段会拒绝这个操作,而不是要求确认——它不带 ref,宏记录的是字符序列,因此没有可供回放时重新填入的占位符。请使用带字段 ref 的 type。
这里唯一一个默认启用且不受限制的功能是 upload:它会把这台机器上任何已有文件或目录交给页面,而信封允许访问的主机上的页面随后就能接收它。如果任务不需要附加任何内容,请设置 JEVMCP_ALLOW_UPLOADS=0。截图则恰好相反,受到限制——只能写入状态目录。
不使用 Agent 试用
.venv/bin/python scripts/smoke.py # headless, 61 checks
.venv/bin/python scripts/smoke.py --headed # watch it drive
这会启动 Chrome,提供 tests/fixture.html,并驱动真实代码路径:批量执行、自动补全、覆盖式模态框、shadow DOM、同源 iframe、文件上传、密码字段、危险点击防护、过期 ref、宏录制/回放、标签页交接、截图,以及一个在 readyState 已经显示为 "complete" 后才渲染内容的页面。
1. Observation — one atomic read, indexed refs
[ok ] element table is not empty — 16 elements
[ok ] shadow DOM element indexed — Shadow action -> e14
...
5. Occlusion — precomputed, not discovered by a failed click
[ok ] covered control flagged before any click — e8 occluded=True
[ok ] click on a covered control is refused with a reason — occluded
...
61/61 checks passed
如需在真实网页而非测试页面上测试:
.venv/bin/python scripts/live_check.py # Bing + DuckDuckGo + tabs + screenshots
.venv/bin/python scripts/live_check.py --headed # watch it happen
这项测试需要网络和第三方网站,因此特意不纳入 CI。无法访问的网站会报告为已跳过,摘要也会明确说明,因此全都被跳过的运行不会被误认为通过。
如果要证明 turbo mode 本身可用——这是唯一会产生费用的路径,也因此是唯一没有其他测试能端到端覆盖的路径:
.venv/bin/python scripts/turbo_check.py # the model drives: dropdown, checkbox, submit
.venv/bin/python scripts/turbo_check.py --headed # watch it decide
它会提供同一个测试页面,将真实 Chrome 指向该页面,并让 Jev 执行目标,随后通过代码验证模型留下的页面状态,而不是相信模型声称成功。没有密钥时,它会打印 skipped 并以 0 退出,因此退出码和输出文字一致。
一次签到何时不再值得花费
examples/checkin.html 是人们实际会自动化的任务的替身:每日签到按钮。
scripts/checkin.py 分三个阶段驱动它,按成本从低到高排列——重点是,只有第一次运行需要付费。
.venv/bin/python scripts/checkin.py --port 8901 # learn once, then never again
.venv/bin/python scripts/checkin.py --port 8901 --record # re-learn, ignoring the saved macro
1. 已完成。 读取页面。如果今天已经签到,就停止——不点击、不调用模型,也无需撤销任何操作。
2. 回放。 运行第一次记录的宏:不调用模型,只需几百毫秒;如果页面已发生变化,它会拒绝执行,而不是猜测。这是普通日子里每次都会运行的阶段,完全不需要密钥。
3. 探索。 仅在没有宏,或保存的宏已不再匹配时运行。决策模型会弄清楚页面的操作方式,并将执行内容记录为宏,以便第二天由阶段 2 接手。只有页面证明确实成功后,才会保存这条执行路径。
演示中固定 --port 很重要:页面的 origin 包含端口,因此第二次运行若使用不同端口,浏览器会将其视为不同的网站,localStorage 为空,也不会记得之前签到过。
用于真实网站时:
.venv/bin/python scripts/checkin.py --url https://example.com/rewards \
--goal "Click the daily check-in button" --expect "已签到"
.venv/bin/python scripts/checkin.py --url https://example.com/rewards --replay-only
目标和验证刻意设为两个独立参数。--goal 是要求模型完成的操作;--expect 是页面之后必须显示的文本,由代码检查——因此,运行结果依据页面判定,而不是模型对自身工作的总结。使用 --headed --wait 120 登录一次;浏览器配置文件会持久保存,因此之后的运行会复用该会话。--replay-only 绝不会调用模型,这正是定时任务所需的标志。
目录结构
jev_ultrafast_mcp/
js/observer.js in-page observer: stable refs, shadow/frame traversal, verify/resolve
cdp.py synchronous CDP client + Chrome launch (no wrapper library)
browser.py sessions, guarded execution, op dispatch, macro recording
observe.py element model, compact renderer, delta computation
macros.py semantic descriptors, scored re-resolution, storage
assertions.py deterministic checks
policy.py optional TypeSafe turbo policy (speculative fan-out)
safety.py domain envelope, redaction, confirmation rules
config.py environment-driven configuration
server.py the MCP surface
scripts/
install.py writes the right config for each MCP client on this machine
smoke.py end-to-end proof against a real browser
mcp_check.py drives the server over real stdio MCP
live_check.py the same, against real websites (needs the network)
turbo_check.py lets the decision model drive a real browser (needs a key)
extension_check.py the extension in a real Chrome: its table, and a macro it replayed
checkin.py a real check-in: learn once with the model, then replay for free
chrome-extension/
lib/observer.js a byte-identical copy of jev_ultrafast_mcp/js/observer.js
lib/render.js a port of observe.py, held to the real renderer by generated fixtures
lib/macro.js a port of macros.py, held to the real resolver by generated fixtures
lib/session.js a port of browser.py's op dispatcher, held to the real one by generated fixtures
lib/report.js a port of server.py's report writers, so a report reads the same anywhere
lib/store.js macros in chrome.storage.local, under the server's own {{placeholder}} rules
background.js the service worker, and the only file that calls the debugger API
examples/
checkin.html the daily-button page checkin.py drives
assets/
social-preview.png the card GitHub shows when this repository is shared
make_social_preview.py renders it, so the words on it are placed rather than generated
llms.txt what this server is, for agents that read before recommending it
server.json the MCP registry entry, submitted by the release workflow
开发
.venv/bin/pip install -e ".[dev]"
.venv/bin/ruff check .
.venv/bin/python -m pytest -q
.venv/bin/python scripts/smoke.py # 61 checks, real browser
.venv/bin/python scripts/mcp_check.py # 17 checks, real stdio MCP
所有测试都会在 CI 中使用 Python 3.10、3.12 和 3.13,针对无头 Chrome 运行。更改目标解析方式前,请阅读
CONTRIBUTING.md——这部分逻辑正是本项目的核心。
另请参阅
browser-use/jev-ultrafast— 可选的 turbo 路径移植自该项目:每个步骤提出一个类型化问题,由决策模型作答。- TypeSafe —
browser_goal背后的类型化问题决策 API。 - Model Context Protocol — 此服务使用的协议。
- 官方 MCP registry — 客户端会在这里寻找此类服务。
- Chrome DevTools Protocol — 驱动浏览器所用的协议,未经过任何封装库。
许可证
MIT — 参见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。