内容
# chrome-mcp
通过Claude(或任何MCP主机)驱动一个**真正的Chrome浏览器**。一个可插拔的`执行器`接口,两个后端:
- **扩展(主要):** 一个MV3扩展驱动你的真正Chrome — 真实的登录,真实的cookie — 通过`chrome.scripting`/`chrome.tabs`。CLI运行一个本地WebSocket服务器;扩展程序连接进来。
- **CDP备用:** 当没有配对扩展时,CLI启动/附加一个由Playwright驱动的Chromium,用于脚本化/无头使用。
作为一个`npx` CLI(MCP服务器)加一个加载解包的扩展进行发布。
> **完整设计:** [`docs/BLUEPRINT.md`](docs/BLUEPRINT.md) — 架构,线路协议,完整的工具界面,扩展清单,安全模型和分阶段构建计划。
## 快速入门
**1. 注册MCP服务器** 与您的主机(例如Claude Desktop / Code):
```jsonc
{
"mcpServers": {
"chrome-mcp": {
"command": "npx",
"args": ["-y", "@mehmoodqureshi/chrome-mcp", "--allow-domain", "example.com", "--enable-mutations"]
}
}
}
```
默认情况下,所有内容都是**拒绝所有**(无域名,无eval,无变异)。授予确切需要的内容 `--allow-domain <glob>` (可重复), `--enable-mutations` , `--enable-downloads` , `--enable-uploads` , `--unsafe-enable-eval` 或 `--unsafe-all-domains` 。
> `--enable-uploads` 允许 `upload_file` (在页面的文件 `<input>` 上设置本地文件(s))。默认情况下它是 **关闭的** ,因为将本地文件发送到页面存在数据泄露风险;它还受到目标域允许列表的限制。将其与 `--uploads-dir <path>` 结合使用,以将上传限制在该目录内的文件(阻止 `..` 遍历)- 强烈建议在无人值守使用时使用。
**仅驱动您的真实Chrome(建议使用扩展)。** 添加 `--no-cdp-fallback` ,这样服务器永远不会启动单独的Chromium,并且 `--persist-token` 这样配对令牌在重启后存活下来 - **一次配对,永不再次**:
```jsonc
{
"mcpServers": {
"chrome-mcp": {
"command": "npx",
"args": ["-y", "@mehmoodqureshi/chrome-mcp",
"--allow-domain", "example.com", "--enable-mutations",
"--no-cdp-fallback", "--persist-token"]
}
}
}
```
如果没有 `--persist-token` ,每次启动都会生成一个新的令牌(安全的默认设置),这意味着每次重启都需要重新配对扩展程序。有了它,令牌存储在 `~/.chrome-mcp/token` 中,并被重用;扩展程序的keepalive自动重新连接,无需手动步骤。 `CHROME_MCP_TOKEN` 显式固定令牌(并且从不写入磁盘)。
**2. 加载扩展** (驱动您的**真实** Chrome):构建它,然后 `chrome://extensions` → 启用开发者模式 → **加载解包** → 选择 `extension-dist/` 。
**3. 配对它:** 运行 `npx chrome-mcp --print-pairing` 以写入握手并打印其路径,打开扩展的**选项**页面,并粘贴 `port` + `token` 从 `~/.chrome-mcp/handshake.json` 。 (如果没有扩展,CLI会自动回退到由Playwright驱动的Chromium。)
工具涵盖标签页,导航,交互( `click` / `type` / `press` / `hover` / `scroll` / `select_option` ),读取( `get_text` / `get_html` / `screenshot` / `eval` / `wait_for` ),无障碍 `snapshot` (具有稳定 `ref` 的交互元素,模型可以定位而不是猜测CSS选择器),会话访问( `get_cookies` / `storage` ),帮助程序( `extract_links` / `read_as_markdown` / `fill_form` / `download_file` / `upload_file` )和 `chrome_status` 。 `upload_file` 在文件 `<input>` 上设置本地文件(s),无需操作系统对话框(需要 `--enable-uploads` )。
`click` / `type` 接受 `trusted: true` 以获得真正的OS级输入(适用于React / Vue受控输入);交互自动等待目标出现。
### 同时驱动多个标签页 - `batch`
`batch` 在**一个**请求中运行许多工具调用 - `parallel` (默认)或 `serial` (带有可选的 `stopOnError` )。每个子操作都经过**相同的**策略门,速率限制和错误处理(无绕过,无嵌套)。使用它将工作分散到各个标签页:
```jsonc
// 打开三个产品页面(后台,这样它们不会争夺焦点)…
{ "name": "batch", "arguments": { "ops": [
{ "tool": "tab_new", "args": { "url": "https://a.example/p" } },
{ "tool": "tab_new", "args": { "url": "https://b.example/p" } },
{ "tool": "tab_new", "args": { "url": "https://c.example/p" } }
]}}
// …然后一次性读取它们(壁钟≈最慢的那个,而不是总和)
{ "name": "batch", "arguments": { "ops": [
{ "tool": "get_text", "args": { "tabId": "<a tabId>" } },
{ "tool": "get_text", "args": { "tabId": "<b tabId>" } },
{ "tool": "get_text", "args": { "tabId": "<c tabId>" } }
]}}
```
在 `parallel` 模式下,作用域为标签页的操作**必须**传递显式的 `tabId` - 活动标签页的默认设置在并发下是不安全的,因此会拒绝而不是静默错误路由。 ( `tab_new` , `tabs_list` , `chrome_status` 豁免。)
> **`tab_new` 默认情况下会聚焦新标签页** (所以“打开X”表现得像打开链接一样,而不是替换当前页面 - 使用 `tab_new` 而不是 `navigate` 来打开而不丢失当前标签页)。传递 `active: false` 以在后台打开;并行批次会自动执行此操作。
## 状态
v0.5.0 - **安全的多标签页并发。** 添加了 `batch` 分发工具,使并行标签页自动化无竞争(显式 `tabId` 保护;每个标签页的 `chrome.debugger` 序列化;无冲突的 `tab_new` ),通过 `chrome.debugger` 捕获截图(特定标签页,无需抢占焦点 - 以及真正的全页和元素捕获),并默认聚焦新打开的标签页。 111个自动化测试 + 一个有门控的头部扩展烟雾测试。
v0.2.0 - 所有六个构建阶段完成且绿色。端到端工作: `npx chrome-mcp` ⇄ 桥 ⇄ 扩展 ⇄ 您真正的Chrome,具有Playwright CDP备用。 v0.2添加了无障碍 `snapshot` + 元素引用,自动等待,cookie / storage / `select_option` ,受信任的输入( `chrome.debugger` ),工具栏状态徽章和稳定的配对令牌( `--persist-token` )。
- [x] **第0阶段 - 合同和骨架:** `shared/protocol.ts` (线路合同), `src/executor/types.ts` (执行器接口), `src/security/policy.ts` (默认拒绝策略 + 能力门控), `src/config.ts` (CLI / env /策略解析),构建 + 测试工具。
- [x] **第1阶段 - MCP服务器+ StubExecutor:** `mcp/server.ts` (干净的stdout stdio), `mcp/tools.ts` (28工具目录 + 永不抛出调度 + 漂移检查),验证器/信封/帮助器, `ExecutorManager` + `StubExecutor` , `cli.ts` 。今天将MCP主机指向 `node dist/src/cli.js` 。
- [x] **第2阶段 - WebSocket桥+身份验证:** `bridge/server.ts` (环回WS,hello-token门控,欢迎/未经授权,位移), `bridge/auth.ts` (每次启动256位令牌,原子0600握手,SHA-256 `timingSafeEqual` ), `bridge/connection.ts` (ID相关,方法感知超时,背压,关闭时全部拒绝,心跳)。
- [x] **第3阶段 - ExtensionExecutor + CdpExecutor +选择:** `executor/extension-executor.ts` (桥上的执行器), `executor/cdp-executor.ts` (Playwright连接/启动+恢复锁定+标签页解析), `executor/select.ts` (如果响应ping则扩展,否则CDP)。 CLI现在启动桥,写入0600握手,并提供真正的后端。 添加 `playwright` 。
- [x] **第4阶段 - MV3扩展:** `extension/` - `manifest.json` , `sw/ws-client.ts` (拨号+问候/欢迎+pong), `sw/executor.ts` (chrome.scripting/chrome.tabs命令实现), `sw/router.ts` (永不抛出+漂移), `sw/background.ts` (顶级监听器+25秒keepalive/重新连接),选项页面(手动配对),esbuild构建→ `extension-dist/` 。通过实时 `--load-extension` 烟雾验证(配对→导航→ `get_text` )。添加 `esbuild` + `@types/chrome` 。
- [x] **第5阶段 - 帮助程序,下载,HITL:** 强化 `download_file` ( `shared/download.ts` - 路径遍历/危险扩展清理+大小上限,与两个后端连接),更丰富的 `read_as_markdown` ,以及人类在环路中的套件( `hitl/` - `npm run test:hitl [-- --include-mutating]` )具有纯粹,单元测试的门控。 50个自动化测试。
- [x] **第6阶段 - 打包和文档:** `files` 白名单(运输 `dist/src` , `dist/shared` , `extension-dist` ,LICENSE,蓝图 - 不是源代码/测试), `prepack` 构建, `bin` ,快速启动 + `.mcp.json` 代码段。通过压缩烟雾验证( `npm pack` → 安装 → MCP `tools/list` )。
## 安全姿态(默认)
**拒绝所有安全模式。** 如果没有配置策略:空域名允许列表, `eval` 关闭,下载关闭,变异工具关闭。显式选择加入:
```
chrome-mcp --allow-domain example.com --enable-mutations
chrome-mcp --policy ./policy.json # see policy.example.json
chrome-mcp --unsafe-all-domains # loud footgun
```
每次启动的256位令牌在 `~/.chrome-mcp/handshake.json` (模式0600)中是唯一的信任边界;它永远不会被写入stdout / stderr。
## 开发
```
npm install
npm run typecheck # server/test sources
npm run typecheck:ext # extension sources (@types/chrome)
npm run build:ext # bundle the extension → extension-dist/
npm test # builds, then runs node --test on dist/test
RUN_EXT_SMOKE=1 node --test dist/test/extension-smoke.test.js # live, headed
```
## 扩展
`extension/` 构建(esbuild)到 `extension-dist/` ,通过 `chrome://extensions` → **加载解包** → 选择 `extension-dist/` 加载。 从扩展的**选项**页面使用 `~/.chrome-mcp/handshake.json` 中的 `port` + `token` 配对它(运行 `npx chrome-mcp --print-pairing` 获取路径)。
> **读取/交互使用 `chrome.scripting` / `chrome.tabs`** - 没有“正在调试”的横幅,CSP安全读取(隔离世界),可在Playwright下测试。 `chrome.debugger` 仅在需要时使用,并且值得使用: `trusted: true` 输入(真正的OS级事件在React / Vue输入上)和 `screenshot` (捕获特定的标签页 **不** 激活它 - 在并行 `batch` 下安全,具有真正的全页和元素捕获)。这些操作在附加时会出现调试横幅。