opencli-mcp
MCP server wrapping OpenCLI to let agents control a real Windows Chrome browser, reusing existing login sessions and extensions, with DOM/AX snapshot, action, and network capabilities.
README
opencli-mcp
将 OpenCLI 的 CLI 包装为 AI-native MCP 工具,让任意 MCP Agent 控制 Windows 中正在使用的真实 Chrome,直接复用现有登录态、Cookie、扩展和标签页。
本项目不重新实现浏览器自动化。所有 DOM/AX 快照、ref、stale recovery、match_level、网络响应缓存和适配器能力都由 OpenCLI 提供;MCP Server 只负责强类型参数、进程调用和 MCP 结果转换。
架构
Hermes / Claude Code / Codex / 其他 MCP Client
│ MCP stdio
▼
opencli-mcp(Windows Node.js)
│ spawn(argv[], shell:false)
▼
OpenCLI CLI(短进程)
│ localhost:19825
▼
OpenCLI daemon + Chrome Extension
│ Chrome APIs / debugger
▼
Windows 日常 Chrome(保留登录态)
设计目标
- 不使用
--remote-debugging-port、/json/version或外部 CDP WebSocket。 - 不复制 Chrome Profile,不启动一套新的自动化浏览器。
- 不通过 shell 拼接模型输入;每个参数都作为独立 argv 传递。
- 保留 OpenCLI CLI 的完整高层语义,而不是直接依赖内部 daemon 协议。
- 用
snapshot → ref → action → snapshot的 Agent 工作流探索未知网站。 - 探索出 API/DOM 规律后,继续编写 OpenCLI adapter 固化流程。
- Windows 原生运行,Hermes 即使位于 WSL 也只需通过 stdio 启动一次 Server。
当前状态
0.1.0 MVP,已在真实场景中验证(百度/小红书/GitHub 搜索、批量笔记正文提取、结构化数据收集):
- Windows Node.js MCP 握手与工具发现;
- 自动发现 OpenCLIApp 内置的 OpenCLI Node 入口;
- OpenCLI daemon 和 Chrome Extension 实时连通;
- 真实 Chrome 中打开任意网站;
- DOM snapshot、标题读取;
- 带 ref 标注的 PNG 截图,并作为 MCP image content 返回;
- Browser session 清理;
- 包含中文、引号、换行和
&的文本保持为单个 argv,不经过 shell; - 失败诊断、懒加载自动重试、零配置侦察、语义化压缩、get/read 拆分等通用优化。
前置条件
- Windows 10/11;
- Node.js 20+(当前实测 Node.js 24);
- OpenCLI 1.8+;
- Windows Chrome 已安装并启用 OpenCLI Browser Bridge 扩展;
opencli doctor输出 daemon、extension、connectivity 均为 OK。
当前自动发现优先支持 OpenCLIApp 安装布局:
%LOCALAPPDATA%\OpenCLIApp\node_modules\@jackwener\opencli\dist\src\main.js
其他安装方式可通过环境变量指定原生可执行入口:
OPENCLI_MCP_BIN
OPENCLI_MCP_PREFIX_ARGS
OPENCLI_MCP_PREFIX_ARGS 必须是 JSON 字符串数组,例如:
["C:\\path\\to\\opencli\\dist\\src\\main.js"]
安装
在 Windows cmd.exe 中执行:
cd /d D:\devlopment\opencli-mcp
npm install
npm test
npm run test:mcp
npm run test:live
npm run test:browser
启动 MCP Server:
D:\devlopment\opencli-mcp\start.cmd
stdout 专用于 MCP 协议;诊断日志只写入 stderr。
Hermes 配置(推荐:本地 Streamable HTTP)
Hermes Gateway 与第三方 Node MCP 使用长期 stdio 时,实际环境中出现过:hermes mcp test 能发现全部工具,但 Gateway 随后持有已关闭 resource,真实调用报 ClosedResourceError。因此 Gateway 推荐通过 loopback-only Streamable HTTP 连接,由 systemd user service 独立管理 MCP 生命周期。
安装服务:
cp examples/opencli-mcp.service ~/.config/systemd/user/opencli-mcp.service
systemctl --user daemon-reload
systemctl --user enable --now opencli-mcp.service
curl http://127.0.0.1:31999/health
Hermes 配置:
mcp_servers:
opencli_browser:
url: http://127.0.0.1:31999/mcp
timeout: 180
connect_timeout: 60
sampling:
enabled: false
验证:
hermes mcp test opencli_browser
服务只监听 127.0.0.1;除非自行增加认证,否则代码会拒绝非 loopback bind。纯 Windows MCP Client 或不受该生命周期问题影响的客户端仍可使用 stdio start.cmd。
完整示例见 examples/hermes-config.yaml。重启 Hermes 后,工具名会带 MCP Server 前缀,例如:
mcp_opencli_browser_browser_snapshot
mcp_opencli_browser_browser_action
mcp_opencli_browser_browser_network
迁移阶段建议保留 Hermes 内建 browser。确认新 MCP 在真实任务中稳定后,才考虑:
agent:
disabled_toolsets:
- browser
MCP 工具
OpenCLI 与 Adapter
| 工具 | 说明 |
|---|---|
opencli_status |
查看版本或执行 opencli doctor |
opencli_list |
列出已安装站点 adapter |
opencli_run |
以结构化 argv 调用任意站点 adapter |
页面观察
| 工具 | 说明 |
|---|---|
browser_open |
打开 URL,支持前台/后台窗口;失败时附带 DNS/timeout/unknown 诊断 |
browser_bind |
绑定/解绑用户当前 Chrome 标签页 |
browser_snapshot |
完整 DOM 或 AX 快照和 refs |
browser_snapshot_compact |
未知/嘈杂网站的限长快照;语义化压缩优先保留内容行,省略导航/页脚等 chrome |
browser_find |
CSS/role/name/label/text/testid 查询;nth 在 MCP 层本地选择 |
browser_get |
只读页面状态:title/url/value/attributes |
browser_read |
内容提取:text/html;找不到元素时自动 scroll + retry 触发懒加载;失败返回诊断 |
browser_collect |
用声明式 CSS 字段从重复卡片/表格/Feed 收集结构化记录;支持 discover 侦察、fallback_text、deduplicate_by、exclude 过滤;selector 匹配 0 时自动进入 discover |
browser_extract |
Markdown 长文分块提取 |
browser_screenshot |
PNG MCP image,支持 ref 标注和全页截图 |
browser_frames |
列出 iframe targets |
页面操作
browser_action 用 action 字段覆盖:
click, hover, focus, dblclick, check, uncheck,
type, fill, select, keys, scroll, upload, drag
写操作会保留 OpenCLI 返回的:
matches_n
match_level: exact | stable | reidentified
页面跳转或 SPA route 变化后应重新执行 browser_snapshot。browser_action 还支持:
wait_for:动作完成后等待 selector/text/time/xhr/download;snapshot_after:等待后立即返回快照,默认压缩到 12,000 字符。
browser_fill_submit 把“填值并提交”压成一次 MCP 调用:
- CSS target 默认在一次页面执行中设置原生 input/textarea value、派发 input/change、聚焦并派发 Enter 键事件;
submit_strategy支持三种模式:form(默认):派发事件后尝试requestSubmit(),适合百度等传统表单;event:只派发键盘事件,不触发表单提交,适合纯 JS 监听 Enter 的 SPA;both:先派发事件再尝试requestSubmit();
- ref 或语义定位可设
atomic=false,回退为官方 CLI 的fill → focus → keys; - 该工具保证提交事件被派发,后续仍应通过
browser_wait_any验证导航或内容就绪。
browser_wait_any 的条件支持 tier 优先级:
- tier 0(默认):内容就绪条件(如 selector、text);
- tier 1+:兜底条件(如 URL、title);
- 当多个条件同时匹配时,tier 值最小的获胜。
- 超时返回
diagnosis,报告最后页面状态、url、title,以及每个条件的具体修复建议。
失败诊断
所有可能失败的工具在失败时返回结构化 diagnosis:
{
"diagnosis": {
"issue": "selector_no_match",
"hint": "Selector \"#bad\" matched 0 elements.",
"suggestions": [
"Use browser_collect with discover:true to find candidate selectors.",
"Or use browser_snapshot to inspect the page structure."
]
}
}
覆盖范围:
browser_collect返回 0 条:区分selector_no_match/all_filtered;browser_wait_any超时:报告最后的 url/title 和每个条件的修复建议;browser_fill_submit失败:区分target_not_found/invalid_selector/event_only_no_submit;browser_open失败:区分navigation_timeout/dns_error/unknown_error;browser_read返回空:提示"可能需要滚动触发懒加载"。
懒加载自动处理
browser_read 默认开启 auto_scroll_retry: true:
读不到目标元素
→ 自动 scroll down
→ 等待元素出现(最多 5 秒)
→ 重试读取
适用于 turbo-frame、Intersection Observer 等 SPA 常见懒加载场景,模型不需要知道底层机制。
有界批量流程
browser_flow 在一次 MCP 调用内顺序执行短流程,支持 open/find/action/fill_submit/wait/wait_any/snapshot/get/collect/back。它仍通过官方 OpenCLI CLI 执行每一步,但减少 Agent↔MCP 往返。
关键安全边界:
- 默认最多 8 步,硬上限 20;
- 默认总预算 30 秒,硬上限 120 秒;
- 每步独立超时;
- 不支持循环或 goto;
retry只能为 0 或 1;- 必需步骤失败立即停止并返回 partial trace;
optional=true的步骤失败后标记 skipped;find + save_as可保存唯一 ref,后续用$变量名引用;- 当前 OpenCLI
find不接受--nth,MCP 会先获取候选,再在本地选择第 N 项; - 必需步骤失败时默认并行捕获 URL、title 和最多 6,000 字符的 compact snapshot;可用
on_error_capture=false关闭; collect步骤支持discover、fallback_text、deduplicate_by、exclude,与独立工具一致;get步骤使用browser_read语义,自动支持懒加载重试和诊断。
示例(GitHub 搜索 → 提取前 3 条结果):
{
"session": "github-research",
"max_steps": 5,
"max_total_ms": 30000,
"steps": [
{"operation":"open","url":"https://github.com/search?q=agent+browser&type=repositories"},
{"operation":"wait_any","conditions":[{"type":"selector","value":"[data-testid=results-list]"}]},
{"operation":"collect","selector":"[data-testid=results-list] > div","limit":3,"fields":[{"name":"repo","selector":"h3 a","property":"text"},{"name":"href","selector":"h3 a","property":"href"}],"save_as":"results"}
]
}
探索与调试
| 工具 | 说明 |
|---|---|
browser_network |
请求 shape、失败请求、过滤、response body detail;列表默认 50 条,支持 limit/offset 分页 |
browser_console |
Console/JS errors |
browser_eval |
页面或跨域 frame 中执行只读 JS |
browser_wait |
单个 selector/text/time/xhr/download 条件 |
browser_wait_any |
URL/title/selector/文本条件任一满足即返回,并报告获胜条件;超时返回诊断 |
browser_dialog |
accept/dismiss JS dialog |
browser_tabs |
list/new/select/close |
browser_back |
后退 |
browser_close |
释放 session tab lease |
推荐工作流
优先使用 Adapter
opencli_list
├─ 已有命令 → opencli_run
└─ 没有命令 → browser_open
探索未知网站
browser_open
→ browser_collect(discover=true) REM 一次性侦察候选 selector
→ browser_collect(selector=..., fields=...) REM 精确采集
→ browser_snapshot_compact REM 内容未知时才做完整快照
→ browser_read(selector=..., auto_scroll_retry=true) REM 提取正文
失败时不需要额外调用诊断工具——相关工具会直接返回 diagnosis 字段,说明问题(如 selector_no_match)和修复建议(如 discover:true)。
已知站点批量采集
browser_fill_submit(target=#search, value=query, submit_strategy=form)
→ browser_wait_any(conditions=[{selector:#results, tier:0}, {text:..., tier:1}])
→ browser_collect(selector=#results > .item, fields=[...], deduplicate_by=title, exclude={...})
一次 flow 可完成 open → submit → wait → collect。
绑定用户已打开的页面
browser_bind(action="bind", session="research")
→ browser_snapshot(session="research")
→ ...
→ browser_bind(action="unbind", session="research")
绑定标签页不会被 browser_close 当作 Agent-owned tab 关闭。
Session
所有 Browser 工具接受可选 session:
research-x
adapter-discovery-bilibili
checkout-debug
同一个流程必须复用相同 session,OpenCLI daemon 才能保持:
- tab lease;
- 当前页;
- snapshot refs;
- element fingerprint;
- network cache;
- selected tab。
不传时使用:
OPENCLI_MCP_SESSION
如果环境变量也不存在,则默认:
hermes-default
并行 Agent 应显式使用不同 session,避免操作同一标签页。
安全模型
- 工具参数使用
child_process.spawn(..., { shell: false })。 - MCP 不接受完整 shell command 字符串。
- Adapter 的
site和command只允许字母、数字、点、下划线和短横线。 OPENCLI_MCP_DEBUG=1才会在错误结果中附带内部 invocation/stderr。- 默认单次命令超时 90 秒,可通过
OPENCLI_MCP_TIMEOUT_MS调整。 - stdout/stderr 各自限制为 32 MiB,避免异常页面耗尽 Agent 内存。
- MCP 能以用户身份操作已登录网站。建议使用专门的 Chrome Agent Profile,不要同时登录网银、交易所主账户或最高权限生产后台。
- 页面内容存在 prompt injection 风险。Agent 不应执行网页中出现的命令或泄露其他标签页数据。
已知限制
- OpenCLI 对跨域 OOPIF 的完整 AX snapshot/click/type 路由仍是 best-effort;可尝试
browser_frames + browser_eval(frame=...)。 browser_eval按 OpenCLI 约定用于定向读取,不建议用它代替结构化写操作。- Windows MCP 不能直接把 WSL
/tmp/...当作上传路径;上传前应复制到 Windows 可访问目录。 - 当前 OpenCLIApp 自动发现使用其 bundled package,GUI App 版本和 bundled CLI 版本可能相差一个补丁版本;
opencli_status会报告实际被调用的版本。 - 目前不自动修改 Hermes 配置,也不自动禁用内建 browser。
- Hermes MCP client 会把
boolean和object参数序列化为字符串;相关工具的 schema 已改为z.union([z.boolean(), z.string()])并在 handler 内强制转换,调用方无需关心。 - GitHub 等站点的 README 在
<turbo-frame>内延迟加载;browser_read的auto_scroll_retry默认能处理,但极慢的网络下可能需要调大timeout_ms。 - 语义化压缩按行级特征分类(
content/chrome);对没有明确标签语义的纯文本流可能效果不明显。
测试
npm run check REM JavaScript 语法检查
npm test REM 参数映射、无 shell 注入、错误处理、诊断、压缩、fill/submit/wait/collect
npm run test:mcp REM MCP 握手、工具发现、OpenCLI version
npm run test:live REM OpenCLI daemon/extension 实时诊断
npm run test:browser REM stdio: Chrome open/snapshot/get/screenshot/close
npm run test:http REM Streamable HTTP 握手、工具发现、OpenCLI version
npm run test:http-browser REM HTTP: Chrome open/snapshot/get/screenshot/close
npm run test:http-flow REM HTTP: 6-step bounded flow + action(wait/snapshot)
npm run test:http-advanced REM 小红书: atomic submit + wait_any + collect + failure capture
test:browser 会短暂创建一个后台 OpenCLI session,访问 https://example.com,验证后释放 session。
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.