返回 MCP 目录
public公开dns本地运行

dev-browser-mcp

一个基于MCP协议的服务器,通过Chrome DevTools Protocol(CDP)驱动本地Chrome/Chromium浏览器标签页,实现自动化点击、导航、截图等功能,无需开启远程调试端口。

article

README

🚀 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_gotodev_browser_click 等工具最终会通过 /cdp 发送 CDP 命令(例如 Page.navigateRuntime.evaluatePage.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 — 获取中继状态(wsEndpointextensionConnectedmode);在 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_gotodev_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/dev_browser/
  • 如果看不到文件,请确认您的当前工作目录(OpenCode 项目根目录),并确保 saveToFile=true
help

运行方式说明

cloud

托管运行

托管运行通常表示这个 MCP Server 由服务方环境承载,用户一般按页面提供的连接方式或授权流程接入,不需要在本地长期启动一个 MCP 进程

  1. 打开服务方连接页
  2. 完成授权或复制端点
  3. 在 MCP 客户端中连接
terminal

本地运行 / 其它方式

本地运行通常需要用户在自己的电脑或服务器上安装依赖,把 server_config 复制到 MCP 客户端,并按 env_schema 补齐环境变量、密钥或其它配置

  1. 复制 server_config
  2. 安装所需依赖
  3. 补齐环境变量后重启客户端