🚀 dev-browser-mcp
dev-browser-mcp 是一个 MCP(模型上下文协议)服务器,它允许 OpenCode(以及其他 MCP 客户端)通过发送 Chrome 开发者工具协议 (CDP) 命令,在本地驱动真实的 Chrome/Chromium 标签页,而无需使用 --remote-debugging-port 启动 Chrome。
它解决了这样的问题:“我希望一个代理能够对现有的本地浏览器会话进行点击、输入、导航和截图操作”,借助轻量级扩展桥接器和本地中继实现。
🚀 快速开始
本项目通过 标准输入输出 运行一个 MCP 服务器。在底层,它与一个本地 中继 进行通信,该中继连接到 Chrome/Chromium 扩展程序。
✨ 主要特性
扩展模式中继 + 端点
中继暴露以下端点:
ws://HOST:PORT/extension
浏览器扩展程序连接到此端点(一次只能有一个连接)。
ws://HOST:PORT/cdp
一个 类似 CDP 的 WebSocket 端点。MCP 服务器连接到此端点并发送 CDP JSON 消息。
像 dev_browser_goto、dev_browser_click 等工具最终会通过 /cdp 发送 CDP 命令(例如 Page.navigate、Runtime.evaluate、Page.captureScreenshot)。中继会将这些命令转发到扩展程序,并将 CDP 事件转发回连接的客户端。
📦 安装指南
前提条件
- Node.js >= 18
- 安装了 dev-browser 扩展程序 的 Chrome/Chromium(扩展程序必须运行并能够连接到
ws://HOST:PORT/extension)
- 安装并配置好 OpenCode 以运行 MCP 服务器
安装步骤
npm install
npm run build
这将生成 dist/ 目录和一个可运行的入口点。
📚 详细文档
OpenCode 配置
OpenCode 支持 全局 配置和 项目 配置。在两种情况下,都需要添加一个名为 dev_browser 的 MCP 服务器条目。
全局配置:~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"dev_browser": {
"type": "local",
"command": ["node", "/Users/<you>/Code/devtools/dev-browser-mcp/dist/index.js"],
"enabled": true,
"environment": {
"HOST": "127.0.0.1",
"PORT": "9222",
"RELAY_MODE": "auto"
}
}
}
}
项目配置:./opencode.json
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"dev_browser": {
"type": "local",
"command": ["node", "./dist/index.js"],
"enabled": true,
"environment": {
"HOST": "127.0.0.1",
"PORT": "9222",
"RELAY_MODE": "auto"
}
}
}
}
注意:
- 不需要任何机密信息或令牌。
- MCP 服务器通过标准输入输出进行通信;OpenCode 将通过
command 数组启动它。
环境变量
HOST(默认值:127.0.0.1)
中继 HTTP/WS 服务器的主机。
PORT(默认值:9222)
中继 HTTP/WS 服务器的端口。
RELAY_MODE(默认值:auto)
控制 MCP 服务器是启动还是连接到中继:
auto:首先探测 http://HOST:PORT/;如果中继已经在运行,则连接。否则启动一个中继。
- 如果启动中继时出现
EADDRINUSE 错误,它会再次探测 http://HOST:PORT/(更长的超时时间)。如果中继可达,则连接;否则重新抛出原始错误。
start:始终启动自己的中继(端口冲突时会失败)。
connect:从不启动;要求在 http://HOST:PORT/ 处有一个现有的中继(如果不可达则抛出错误)。
💻 使用示例
典型流程
确保扩展程序已连接 → 打开/选择一个标签页 → 导航 → 交互 → 快照/截图。
1) 等待扩展程序连接
{
"tool": "dev_browser_ensure_extension_connected",
"input": { "timeoutMs": 30000, "pollIntervalMs": 250 }
}
2) 打开(或重用)一个命名标签页
{
"tool": "dev_browser_page_open",
"input": { "name": "my-tab" }
}
3) 导航
{
"tool": "dev_browser_goto",
"input": {
"url": "https://example.com",
"waitUntil": "load",
"timeoutMs": 30000
}
}
4) 快照(AI 友好的 DOM 大纲)
{
"tool": "dev_browser_snapshot",
"input": {}
}
快照包含 snapshotRef 标识符,可用于点击或输入操作。
5) 点击 / 输入
通过 CSS 选择器点击
{
"tool": "dev_browser_click",
"input": { "selector": "button[type='submit']" }
}
通过 snapshotRef 点击(来自 dev_browser_snapshot 的输出)
{
"tool": "dev_browser_click",
"input": { "snapshotRef": "e123" }
}
通过 CSS 选择器输入
{
"tool": "dev_browser_type",
"input": { "selector": "input[name='q']", "text": "hello", "clearFirst": true }
}
通过 snapshotRef 输入
{
"tool": "dev_browser_type",
"input": { "snapshotRef": "e456", "text": "hello", "clearFirst": true }
}
6) 截图
{
"tool": "dev_browser_screenshot",
"input": { "fullPage": false, "saveToFile": true }
}
如果 saveToFile=true(默认值),它将在以下位置写入一个 PNG 文件:
./.opencode/dev_browser/
并返回 文件路径(以及图像内容)。
工具列表
dev_browser_relay_status — 获取中继状态(wsEndpoint、extensionConnected、mode);在 auto 模式下,它将启动或连接。
dev_browser_ensure_extension_connected — 等待直到 extensionConnected=true(轮询中继 /)。
dev_browser_pages_list — 列出中继中注册的命名页面。
dev_browser_page_open — 通过中继获取或创建一个命名标签页,并选择它以进行后续操作。
dev_browser_page_delete_mapping — 删除中继中的命名页面映射。
dev_browser_goto — 将选定的标签页导航到指定 URL。
dev_browser_click — 通过 CSS 选择器或 snapshotRef(来自 dev_browser_snapshot)点击元素。
dev_browser_type — 通过 CSS 选择器或 snapshotRef(来自 dev_browser_snapshot)在输入框中输入内容。
dev_browser_wait_for_selector — 等待选定标签页上的选择器出现。
dev_browser_evaluate — 在选定标签页的上下文中执行 JavaScript 代码。
dev_browser_screenshot — 拍摄 PNG 截图;保存到 ./.opencode/dev_browser 并返回文件路径。
dev_browser_snapshot — 返回选定标签页的 AI 友好快照(类似 YAML)。
与 dev-browser (SawyerHood/dev-browser) 的关系
本项目旨在将与 SawyerHood/dev-browser 相同的核心思想暴露给 MCP 客户端(OpenCode):驱动具有持久状态的真实浏览器 并提供 对大语言模型友好的 DOM 快照。
复用/对齐的部分
- 扩展模式 CDP 中继概念:dev-browser 有一个“扩展模式”,其中本地中继在扩展程序(
chrome.debugger)和自动化客户端之间桥接 CDP 消息。
- 命名页面:两个系统都提供了
POST /pages 抽象,用于创建/激活命名标签页并返回 targetId。
- 快照引用:dev-browser 的快照方法使用注入的脚本返回一个带有稳定
[ref=eN] 标记的类似 YAML 的大纲。
不同之处
- 协议表面:dev-browser 作为 Claude Code 插件/技能分发;本仓库是一个专为 OpenCode 设计的独立 MCP 服务器。
- 控制路径:本项目不提供“技能客户端” API,而是暴露离散的 MCP 工具(
dev_browser_goto、dev_browser_click 等)来发送 CDP 命令。
- 多 OpenCode 中继所有权:此 MCP 支持
RELAY_MODE=auto,因此多个 OpenCode 实例可以连接到单个中继进程,而不会因 EADDRINUSE 错误而崩溃。
- 确定性标签页目标:操作通过
targetId + Target.attachToTarget 会话作用于特定的 Chrome 标签页,因此不同的 OpenCode 实例可以可靠地控制不同的命名标签页。
🔧 技术细节
故障排除
extensionConnected=false
- 确保 Chrome/Chromium 正在运行,并且 dev-browser 扩展程序已安装并启用。
- 扩展程序必须能够连接到
ws://HOST:PORT/extension。
- 运行
dev_browser_relay_status 以确认中继是否可达,并查看 extensionConnected 状态。
EADDRINUSE / 端口冲突
PORT=9222 通常被其他工具使用(包括 Chrome 远程调试)。
- 通过选择不同的端口来解决:
- 设置
PORT(并确保中继和扩展程序的端口一致)
- 或者,如果您有意在其他地方运行中继并希望连接,请设置
RELAY_MODE=connect。
多个 OpenCode 实例 / 标签页命名
- 建议通过
dev_browser_page_open 使用明确、唯一的标签页名称(例如 "myproject-admin"、"myproject-patient")。
- 如果不向工具传递
pageName,它们将在“最后选择”的页面上操作;为避免冲突,请始终为每个工作区/代理打开/选择一个命名页面。
截图保存位置
- 默认情况下,截图保存到:
- 如果看不到文件,请确认您的当前工作目录(OpenCode 项目根目录),并确保
saveToFile=true。