内容
# Chrome 浏览器控制
用于 stdio MCP 主机的本地 Chrome 配置文件控制。
该项目通过一个 Manifest V3 Chrome 扩展程序,将浏览器控制 MCP 工具暴露给一个环回 WebSocket 代理。配置您的 MCP 主机以启动 stdio 适配器,并使用与您在扩展程序中输入的相同的配对令牌。
仓库:https://github.com/vkongv/chrome-browser-control
## 先决条件
- Node.js 18+
- Google Chrome
## 安装和设置
1. 克隆仓库:
```bash
git clone https://github.com/vkongv/chrome-browser-control.git
cd chrome-browser-control
```
2. 安装依赖项并运行设置:
```bash
npm install
npm run setup
```
`npm run setup` 会写入 `.env.local` 文件,包含 `CHROME_BROWSER_CONTROL_TOKEN` 和 `CHROME_BROWSER_CONTROL_PORT`,打印扩展程序文件夹路径,并显示复制粘贴的 MCP 配置代码片段。该文件被 git 忽略 - 请勿提交它。
3. 继续执行 [加载扩展程序](#加载扩展程序),然后添加 MCP 配置并验证连接。
要手动生成配对令牌,而不是使用 `npm run setup`:
```bash
node -e "console.log(crypto.randomBytes(32).toString('base64url'))"
```
### 环境变量
- `CHROME_BROWSER_CONTROL_TOKEN` - 必需。由代理、MCP 适配器和扩展程序弹出窗口共享的高熵配对令牌。
- `CHROME_BROWSER_CONTROL_PORT` - WebSocket 代理端口(默认 `8765`)。
- `CHROME_BROWSER_CONTROL_HOST` - 代理的环回主机(默认 `127.0.0.1`)。
- `CHROME_BROWSER_CONTROL_EXTENSION_ID` - 可选。将代理固定到一个已安装的扩展程序 ID。
- `CHROME_BROWSER_CONTROL_DISABLE_LOCAL_ENV` - 可选。设置为 `1` 以跳过加载 `.env.local`。
用于 MCP 主机以外的手动操作:
```bash
CHROME_BROWSER_CONTROL_TOKEN='<生成的令牌>' npm run broker
CHROME_BROWSER_CONTROL_TOKEN='<生成的令牌>' npm run mcp
```
`npm start` 是 `npm run mcp` 的别名。
## 加载扩展程序
1. 打开 Chrome,并使用您要控制 MCP 工具的配置文件。
2. 进入 `chrome://extensions`。
3. 启用开发者模式。
4. 点击“加载解压的扩展程序”。
5. 选择 `/path/to/chrome-browser-control/extension`。
6. 打开 Chrome 浏览器控制扩展程序的弹出窗口。
7. 将桥接 URL 保留为 `ws://127.0.0.1:8765`,除非您更改了本地端口。
8. 粘贴生成的配对令牌。
9. 添加允许的来源,例如 `https://example.com`、`http://localhost:3000` 或 `*` 以允许所有正常的 `http://` 和 `https://` 页面。
10. 点击“保存并重新连接”。
扩展程序可能会要求允许来源的主机权限。拒绝该请求会阻止这些来源的页面操作。
使用 `*` 在本地开发中很方便,但它会使当前 Chrome 配置文件中的每个正常网页都暴露给 MCP 工具。当您只需要几个站点时,请优先使用明确的来源。通配符模式还会要求可选的 `<all_urls>` 主机权限,以便 Chrome 允许通过 `chrome.tabs.captureVisibleTab` 进行可见视口截图;后台仍然会在捕获之前阻止非 http(s) URL 和不允许的来源。
## MCP 主机配置
将 `npm run setup` 的代码片段粘贴到 Cursor、Claude Desktop、Codex 或另一个 stdio MCP 主机中。要稍后打印主机特定的配置:
```bash
npm run --silent mcp-config -- --host cursor
npm run --silent mcp-config -- --host claude
npm run --silent mcp-config -- --host codex
npm run --silent mcp-config -- --host yaml
```
使用绝对路径,因为许多 MCP 主机不应用每个服务器的工作目录。确切的键名因主机而异,但 Claude Desktop、Codex、Cursor 和类似的 MCP 主机通常需要一个命令、参数和环境块,用于 stdio MCP 服务器。该项目应与任何 stdio MCP 主机一起使用;请在该主机的文档中验证主机特定的配置语法。
YAML 样式示例:
```yaml
mcp_servers:
chrome_browser_control:
command: "/path/to/chrome-browser-control/node_modules/.bin/tsx"
args: ["/path/to/chrome-browser-control/server/index.ts"]
env:
CHROME_BROWSER_CONTROL_TOKEN: "<生成的令牌>"
CHROME_BROWSER_CONTROL_PORT: "8765"
timeout: 60
connect_timeout: 30
```
JSON 样式示例:
```json
{
"mcpServers": {
"chrome_browser_control": {
"command": "/path/to/chrome-browser-control/node_modules/.bin/tsx",
"args": ["/path/to/chrome-browser-control/server/index.ts"],
"env": {
"CHROME_BROWSER_CONTROL_TOKEN": "<生成的令牌>",
"CHROME_BROWSER_CONTROL_PORT": "8765"
}
}
}
}
```
如果您的 MCP 主机使用配置文件,请将其保存在存储库之外并保持私密。
## 验证
运行设置检查器:
```bash
npm run doctor
```
然后通过调用 `browser_status` 工具从您的 MCP 主机确认。当准备就绪时,`extension.status` 和 `ping.status` 应反映实时桥接连接,并且 `extension.allowedOrigins` 应显示您的配置范围。
## 工具
- `browser_status`:检查 MCP 适配器是否可以到达代理以及 Chrome 扩展程序是否回答 `ping`。当准备就绪时,`extension.status` 和 `ping.status` 反射实时桥接连接(不是陈旧的断开连接默认值),`extension.allowedOrigins` 显示配置范围(包括启用通配符模式时的 `* (所有 http/https 网络来源)`),`extension.session` 显示会话名称/声称的选项卡,并且 `protocolVersion` / `features` 确认加载的解压扩展程序代码。协议版本 `4` 包括 `act-observe` 功能。
- `name_session`:为状态/调试设置人类可读的会话名称。
- `list_tabs`:列出扩展程序弹出窗口中允许的 URL 来源的选项卡。当所有打开的选项卡都被过滤掉时,返回 `{ tabs: [], detail, hiddenTabCount, allowedOrigins? }` 而不是一个简单的 `[]`。通配符模式在 `allowedOrigins` 中有明确的标签。
- `claim_tab`:为此浏览器控制会话声明一个允许的选项卡并返回一个 `sessionTabId`。声明是路由状态,而不是独占浏览器锁。
- `release_tab`:通过 `sessionTabId` 或 `tabId` 释放声明而不关闭选项卡。
- `finalize_tabs`:释放会话的声明状态而不关闭选项卡。传递 `keep` 条目以保留交接/可交付的声明。
- `snapshot`:返回允许的选项卡的简化 DOM 快照。默认情况下,这是包括简洁的可操作元素、文本预览(500 个字符)、省略计数和区域摘要的紧凑自动化快照。传递 `mode: "full"` 以获取详细的元素元数据和 `text` 字段(默认为 4000 个字符)。传递 `mode: "visible"` 以获取视口/交集感知元素及其边界和滚动元数据。传递 `textLimit`(高达 `100000`)当您需要更多页面正文文本时 - 检查 `textBytesOmitted` 以查看内容是否被截断。
- `visible_snapshot`:`snapshot({ mode: "visible" })` 的便捷工具。
- `navigate`:将活动选项卡或指定的 `tabId` 导航到允许的 URL,然后在可能的情况下等待选项卡完成加载。如果加载超时,结果将包括 `pending: true` 和一个 `warning`。支持加载后观察。
- `click`:通过快照引用在允许的选项卡上单击元素。支持加载后观察。
- `type`:在允许的选项卡上的元素中输入。密码类字段被阻止,除非 `force=true`。支持加载后观察。
- `scroll`:通过 `deltaX` 和 `deltaY` 滚动允许的选项卡。可选的 `x`/`y` 视口坐标滚动一个可滚动元素在该点下找到的元素。滚动不会分页快照文本 - 快照使用完整的 `document.body` innerText。提高 `textLimit` 而不是滚动拼接,除非页面延迟加载内容。支持加载后观察。
- `query_elements`:返回通过 CSS 选择器、角色、文本和可见性过滤的元素的有界引用/角色/标签/边界。
- `extract_elements`:从 CSS 选择器中提取有界文本/HTML/链接/时间数据。HTML 提取会编辑密码/OTP/隐藏令牌属性值并标记敏感项,而不是泄漏秘密值。这是原始 JavaScript 评估的支持替代方法。
- `screenshot`:捕获允许的选项卡的可见视口作为数据 URL。MV3 捕获仅限于视口;非活动目标选项卡可能会在捕获前激活。Chrome 需要 `<all_urls>` 或 `activeTab` 用于 `captureVisibleTab`;此扩展程序仅在通配符模式下请求可选的 `<all_urls>` 作为主机权限,因此通配符截图需要该弹出窗口授予。
- `keypress`:将常见的 DOM 键盘事件调度到页面。浏览器/OS 级快捷键在 MV3 下不保证。支持加载后观察。
- `click_at`:在视口坐标处调度鼠标事件。支持加载后观察。
- `wait_for`:等待有界选择器/文本/URL 子字符串条件并返回匹配/超时证据。
- `page_status`:返回标题、URL、就绪/可见性状态、视口/滚动状态和资源计数,按发起者类型划分。它不暴露请求头或响应正文。
- `console_logs`:返回注入内容脚本后捕获的限定控制台日志。它无法看到旧的页面控制台历史记录。
- `collect_scroll`:滚动限定数量的步骤,提取每个步骤的选择元素,应用聚合项目上限(默认为 100),并可选地根据文本或 href 进行重复数据删除以适用于延迟馈送。结果包括省略/截断的计数。支持加载后观察。
## 操作后观察
操作工具 `navigate`、`click`、`type`、`scroll`、`keypress`、`click_at` 和 `collect_scroll` 接受一个可选的 `after` 对象。扩展程序在将基本操作发送到内容脚本之前删除 `after`,然后按固定顺序运行请求的观察:`waitFor`、`snapshot`、`pageStatus`。响应是基本操作结果加上包含观察结果的 `after` 对象。
```json
{
"ref": "h12",
"after": {
"waitFor": { "selector": ".results", "timeoutMs": 5000 },
"snapshot": { "mode": "visible", "limit": 40 },
"pageStatus": true
}
}
```
`after.waitFor` 必须至少包含 `text`、`selector` 或 `urlIncludes` 之一;`timeoutMs` 是可选的,最高可达 `20000`,因此整个操作-观察链仍在默认代理请求超时内。`after.snapshot` 可以是 `true` 以获取默认快照选项,也可以是一个包含 `mode`、`textLimit` 和/或 `limit` 的对象。无效的 `after` 请求在基本操作运行之前被拒绝。
如果基本操作成功但 `after` 观察失败,响应仍包括基本操作结果并将 `after` 设置为 `{ "ok": false, "error": "..." }`。
## 快照模式和引用
默认紧凑快照旨在减少模型上下文使用量同时保留浏览器自动化。紧凑快照如下所示:
```json
{
"title": "示例域名",
"url": "https://example.com/",
"mode": "compact",
"elements": [{ "ref": "h1", "role": "link", "label": "了解更多" }],
"omittedElements": 0,
"textPreview": "示例域名 ...",
"textBytesOmitted": 0,
"regions": []
}
```
仅在需要旧的详细元素元数据时才使用完整模式:
```json
{ "mode": "full", "tabId": 123 }
```
使用可见模式获取视口绑定工作、虚拟化页面和点击坐标规划:
```json
{ "mode": "visible", "sessionTabId": "tab-1" }
```
要读取长页面内容(例如 API 文档),请提高 `textLimit` 而不是使用代理脚本或 CDP 解决方法:
```json
{ "mode": "full", "textLimit": 100000, "tabId": 123 }
```
紧凑模式也遵循 `textLimit`;正文文本在 `textPreview` 中返回(紧凑模式中没有 `text` 字段)。当 `textBytesOmitted` 大于零时,增加 `textLimit` 或滚动页面并再次快照,仅当内容延迟加载到页面下方时。
引用是每个文档的内存 ID(`h...`)从元素标识符分配,而不是输出顺序。它们在同一个文档中的 DOM 插入/重新排序保持稳定,并且 `click` / `type` 通过内容脚本的引用存储解析。通过导航到不同页面加载新文档,因此旧引用预计会干净地失败;在导航或主要页面更改后获取新的快照。
## 标签会话
在多步骤浏览器工作之前,请优先使用 `claim_tab`:
```json
{ "tabId": 123 }
```
返回的 `sessionTabId` 可以传递给 `snapshot`、`navigate`、`click`、`type`、`scroll`、`query_elements`、`extract_elements`、`screenshot`、`wait_for` 和相关页面工具。如果会话有当前声明,则没有明确 `tabId` 或 `sessionTabId` 的页面操作会路由到该声明。如果不存在声明,则保留旧的活动选项卡备用。
声明是建议性的 MCP 路由状态。它们不会阻止用户更改、关闭或导航选项卡。使用 `release_tab` 或 `finalize_tabs` 完成任务;这两个工具都不会关闭浏览器选项卡。
## 开发检查
```bash
npm test
npm run build
npm run doctor
npm run benchmark:compact-snapshots
npm audit
```
`npm run benchmark:snapshots` 是紧凑与完整基准测试的别名。基准测试会打印紧凑字节、完整字节和减少百分比;紧凑模式在密集的固定装置上应至少小 50%。
编辑 `extension/` 下的文件后,请在 `chrome://extensions` 上重新加载解压的扩展程序,然后运行浏览器端到端检查。陈旧的加载后台服务工作线程可以继续提供旧行为;`browser_status` 应该在 Chrome 加载最新扩展程序代码时显示当前的 `protocolVersion` 和 `features` 标记。
## 限制
- 这是一个具有共享本地令牌的原型,而不是多用户身份验证。
- 浏览器工具调用在代理上全局序列化。
- 内容脚本使用 DOM 快照,而不是完整的 Chrome 可访问性树。
- 引用是文档范围的内存句柄。运行 `snapshot` 后导航、重新加载、主要 DOM 更改或过期引用错误后,请再次获取快照。
- 可见截图仅限于视口。捕获非活动选项卡可能会激活它,因为 Chrome MV3 捕获窗口中的可见选项卡。
- Chrome 截图捕获需要 `<all_urls>` 或 `activeTab`。该项目仅在通配符模式下请求可选的 `<all_urls>` 作为主机权限用于通配符截图。如果 `screenshot` 报告缺少此权限,请在清单更新后重新加载扩展程序,打开弹出窗口,保存设置,并授予提示。
- `keypress` 和 `click_at` 使用 DOM 事件,而不是 CDP 输入调度。它们对于页面处理程序很有用,但可能不会触发特权浏览器快捷键或每个框架特定的输入路径。
- 控制台日志仅在内容脚本注入后捕获,并且是有限的。
- 资源摘要仅来自性能 API 的计数;请求头、响应正文、cookie、存储、历史记录、书签和下载故意不暴露。
- 浏览器历史记录、书签、下载和 cookie 工具故意不暴露。
- `server/cdp.ts` 仅作为未使用的开发参考,不连接到 MCP 适配器。
## 安全
- 不接受默认令牌。 为代理和 MCP 适配器设置高熵 URL 安全值,然后将相同的值粘贴到扩展程序弹出窗口中。
- 代理仅绑定到环回主机:`127.0.0.1`、`localhost` 或 `::1`。
- 扩展程序仅连接到 `ws://127.0.0.1`、`ws://localhost` 或 `ws://[::1]`,并带有可选端口。
- 页面访问权限由弹出窗口中配置的允许来源限制。使用明确的条目,例如 `https://example.com`,或输入 `*` 以允许所有正常的 `http://` 和 `https://` 网页。 配置范围外的选项卡和页面操作被阻止。
- 密码类和 OTP 字段通过输入类型、自动完成、名称、ID、标签和占位符进行检测。 `type` 阻止它们,除非 `force=true`。
- 可选的 `CHROME_BROWSER_CONTROL_EXTENSION_ID` 将代理固定到一个已安装的扩展程序 ID。
- 由于扩展程序配对,MCP 适配器不支持 CDP 回落。