Cette page est affichée en anglais. Une traduction française est en cours.
SkillsMay 4, 2026·6 min de lecture

Chrome MCP Operations Runbook — Iron Rules, Architecture & Troubleshooting

Operations skill for running chrome-devtools-mcp against your real Chrome at scale. Covers the proxy architecture, five iron rules (always-via-proxy, real-browser-only, no-env-proxy, never-kill-current-session, persistent-proxy), Chrome 146+ remote-debug popup workaround, multi-agent isolation guarantees, configuration recipes for ~/.mcp.json and ~/.claude/settings.json (with the 'no glob in permissions' gotcha), step-by-step troubleshooting flow, and four field notes from real incidents — port cleanup heuristics that backfire, protocol-layer hang detection, why 'newest = keep' is wrong, and why heavy pages need filePath-first take_snapshot to avoid 25k token overflow. Pairs with the 'Chrome MCP Background Proxy' script bundle.

Prêt pour agents

Staging sûr pour cet actif

Cet actif est d'abord staged. Le prompt copié demande à l'agent d'inspecter les fichiers staged avant d'activer scripts, config MCP ou config globale.

Stage only · 19/100Policy : staging
Surface agent
Tout agent MCP/CLI
Type
Mcp Config
Installation
Stage only
Confiance
Éditeur vérifié
Point d'entrée
SKILL.md
Commande de staging sûr
npx -y tokrepo@latest install 2080f98d-1be9-4757-8b71-85b296ff6d70 --target codex

Stage les fichiers d'abord; l'activation exige la revue du README et du plan staged.

架构总览

Claude Code (stdio)
  → chrome-mcp-proxy.sh
    → chrome-devtools-mcp (连接 proxy 的 WebSocket)
      → cdp-proxy.mjs v3 (port 9401)
          ├── 持久 WebSocket 连接到 Chrome(弹窗只出现一次)
          ├── 请求 ID 重映射(防多客户端冲突)
          ├── 事件按 sessionId 路由(防多 Agent 互扰)
          └── 拦截抢焦点命令
        → 真实 Chrome (通过 DevToolsActivePort 文件连接)

核心原则:必须通过 proxy 中间层,绝不直连 Chrome。

铁律(绝不可违反)

1. 必须经过 proxy

  • proxy (cdp-proxy.mjs) 拦截 Target.activateTargetPage.bringToFront,防止浏览器抢用户焦点
  • 强制 createTarget 在后台创建 tab(background: true
  • .mcp.json 中 chrome 配置必须用 chrome-mcp-proxy.sh,不能用 chrome-devtools-mcp 直连

2. 必须连接真实浏览器

  • 用户日常使用的 Chrome(有登录态、插件、书签)
  • Chrome 需在 chrome://inspect/#remote-debugging 中开启远程调试(一次性设置)
  • proxy 通过读取 ~/Library/Application Support/Google/Chrome/DevToolsActivePort 文件自动连接
  • 绝对禁止--user-data-dir=/tmp/xxx~/.cache/chrome-devtools-mcp/chrome-profile 启动无状态 Chrome

3. 不走网络代理

  • .mcp.json 中 chrome 服务不配 env 代理变量
  • chrome-mcp-proxy.sh 脚本内部已 unset 所有代理环境变量
  • 本机 zshrc 有全局代理 (http_proxy=127.0.0.1:7897),会拦截本地连接,所以必须 unset

4. 绝不杀当前 session 的 MCP 进程

  • Chrome MCP 是 Claude Code 通过 stdio 管道启动的子进程
  • 进程一死,管道断裂,当前 session 永远无法恢复
  • 清理多实例只用安全脚本: bash ~/scripts/kill-old-chrome-mcp.sh

5. proxy 是持久服务

  • proxy 用 nohup + disown 启动,不随 Claude Code 退出而死
  • 启动时立即建立到 Chrome 的持久 WebSocket 连接
  • 所有 Claude Code 会话共用这一条连接
  • Chrome 断开后自动每 5 秒重连

Chrome 146+ 远程调试弹窗问题

问题

Chrome 146 开始,外部程序通过 WebSocket 连接调试端口时,Chrome 会弹出"要允许远程调试吗?"授权窗口。每次新建 WebSocket 连接都会弹一次。

解决方案:持久连接

cdp-proxy.mjs v3 在启动时就建立一条持久连接到 Chrome,所有客户端共用。弹窗只在以下情况出现:

  • proxy 首次启动时(点一次"允许")
  • Chrome 重启后 proxy 重连时(点一次"允许")

之后新开 Claude Code 窗口不再弹窗,因为复用已有连接。

前置条件

Chrome 地址栏打开 chrome://inspect/#remote-debugging,勾选 Allow remote debugging for this browser instance(一次性设置)。

无效方案(已验证不可行)

方案 结果
--remote-debugging-port=9222 Chrome 146 要求 --user-data-dir 为非默认目录,丢失登录态
--silent-debugger-extension-api 对远程调试弹窗无效
--disable-features=AutomationControlled 对弹窗无效
defaults write com.google.Chrome DevToolsRemoteDebuggingAllowed Chrome 不读取
macOS managed preferences plist Chrome 不读取
.mobileconfig 配置描述文件 Chrome 不读取
devtools.remote_debugging.allowed in Local State 无效
chrome-devtools-mcp --autoConnect 仍然弹窗
锁定 chrome-devtools-mcp 旧版本 (0.19.0) 无效

多 Agent 隔离(v3 新增)

多个 Agent(或 sub-agent)同时操作 Chrome 时,proxy v3 保证互不干扰:

机制 说明
请求 ID 重映射 每个客户端的请求 ID 统一映射为全局唯一 ID,响应精准路由回原客户端
事件按 sessionId 路由 Target.attachToTarget 的 session 归属记录到对应客户端,后续该 session 的事件只发给该客户端
Tab 归属追踪 Target.createTarget 的响应记录 tab 归属,Target 域的全局事件按 targetId 路由
客户端断开清理 客户端断开时清理其 session 归属、未完成请求、tab 记录
空闲自动回收 客户端 idle 超 5min(--idle-timeout 300000)→ 对其全部 session 发 Target.detachFromTarget,WebSocket 保留,下次操作时 chrome-devtools-mcp 自动重新 attach(无感)

架构上,所有 Agent 共享同一个 Chrome、同一个 proxy,各自创建后台 tab,通过不同的 sessionId/targetId 操作,互不干扰。

配置文件

~/.mcp.json(chrome 部分)

"chrome": {
  "command": "bash",
  "args": [
    "/Users/wangkai/scripts/chrome-mcp-proxy.sh",
    "9401",
    "9222"
  ]
}

注意:不要加 env 代理变量!

~/.claude/settings.json(权限)

MCP 工具权限不能用通配符 mcp__chrome__*(会导致整个 settings 文件被跳过),必须逐一列出:

"permissions": {
  "allow": [
    "mcp__chrome__click",
    "mcp__chrome__close_page",
    "mcp__chrome__take_screenshot",
    ...
  ]
}

~/.claude/settings.local.json(MCP 启用)

同样需要逐一列出 MCP 工具名,不能用通配符。

关键脚本

脚本 路径 用途
chrome-mcp-proxy.sh ~/scripts/chrome-mcp-proxy.sh MCP 启动入口:unset 代理 → 启动持久 proxy(nohup+disown) → 启动 chrome-devtools-mcp
cdp-proxy.mjs ~/scripts/cdp-proxy.mjs CDP 持久代理 v3:持久连接 + ID 重映射 + 事件路由 + 拦截抢焦点 + 自动重连
kill-old-chrome-mcp.sh ~/scripts/kill-old-chrome-mcp.sh 安全清理:只杀旧进程,保留最新

关键文件

文件 路径 用途
DevToolsActivePort ~/Library/Application Support/Google/Chrome/DevToolsActivePort Chrome 自动写入,包含调试端口和 WebSocket 路径
proxy 日志 ~/chrome-profiles/logs/proxy-9401.log proxy 运行日志
proxy PID ~/chrome-profiles/pids/proxy-9401.pid proxy 进程 PID

排障流程

症状:Chrome MCP 工具报错 "Could not connect to Chrome"

步骤1: 检查 Chrome 是否在运行

pgrep -x "Google Chrome" && echo "running" || echo "not running"

没运行就启动:open -a "Google Chrome"

步骤2: 检查 DevToolsActivePort 文件

cat ~/Library/Application\ Support/Google/Chrome/DevToolsActivePort

步骤3: 检查 proxy 状态

curl -s --noproxy '*' http://127.0.0.1:9401/proxy/status

应该看到 chromeConnected: true。如果是 false,Chrome 可能需要点一次"允许"弹窗。

步骤4: 用 /mcp 重连

步骤5: 安全清理旧进程

bash ~/scripts/kill-old-chrome-mcp.sh

步骤6: 最后手段 — 退出重启 Claude Code

症状:每次开新 Claude Code 都弹远程调试弹窗

检查 proxy 是否在持久运行:

curl -s --noproxy '*' http://127.0.0.1:9401/proxy/status

如果 proxy 没在运行,说明上次退出时被杀了。手动启动:

unset http_proxy HTTP_PROXY https_proxy HTTPS_PROXY all_proxy ALL_PROXY
nohup node ~/scripts/cdp-proxy.mjs --port 9401 --chrome-port 9222 &>~/chrome-profiles/logs/proxy-9401.log &
disown

然后在 Chrome 点一次"允许",之后就不再弹了。

症状:感觉 "DevTools 协议被占满"(命令变慢/超时)

/proxy/statussessions 数,如果远大于 tabs 总数,说明有客户端 session 泄漏(老 Claude Code 窗口关的时候 chrome-devtools-mcp 没 detach 干净)。

  • v3.1 后 proxy 自带空闲回收:idle > 5min 自动 detach 全部 session
  • 想立即清理:关掉闲置 Claude Code 窗口(触发 clientDisconnect),或在闲置窗口里 /mcp disable chrome
  • 重启 proxy 是最暴力的清理(但所有窗口都要重连)

症状:多 Agent 操作时互相干扰

检查 proxy 版本是否为 v3:

curl -s --noproxy '*' http://127.0.0.1:9401/proxy/status

v3 会返回 sessionsclientDetails 字段。如果没有,需要重启 proxy 加载新版 cdp-proxy.mjs。

历史事故教训

日期 事故 教训
2026-03-15 手动 kill 全部进程导致 session 失效 只用安全脚本清理
2026-03-24 Chrome 更新到 146,远程调试开始弹窗 改用持久连接 proxy,弹窗只出现一次
2026-03-24 settings.json 用 mcp__chrome__* 通配符导致整个文件被跳过 MCP 权限必须逐一列出工具名
2026-03-24 --remote-debugging-port 在 Chrome 146 要求非默认 user-data-dir 不能用此方式,会丢失登录态
2026-03-24 macOS managed preferences / mobileconfig 设置 Chrome 策略 Chrome 不读取这些策略,无效
2026-03-24 proxy v2 多客户端共用连接时请求 ID 冲突 v3 加入 ID 重映射 + sessionId 事件路由

Field Notes — Lessons Learned the Hard Way

Real incidents that shaped the iron rules above. Read these before you reach for pkill or assume a port without LISTEN is an orphan.

Note 1 — Port without LISTEN is not always an orphan

杀 chrome-devtools-mcp 重复进程时,不要假设"目标端口没监听 = 孤儿可杀"。多个 npm exec 实例配不同 --browserUrl(9401/9402/9501),但实际服务本会话 MCP 的可能是其中任意一个 npm exec 链路,且不一定连到正在监听的浏览器端口(mcp 进程可能持有自己的 stdio 通信,与 browserUrl 状态无关)。

Why: 2026-05-04 在 claude.ai 处理 TokRepo YouTube 选题任务时,发现 9401/9402 端口没 LISTEN、9501 有 ESTABLISHED,按"孤儿"判断 pkill 9401/9402 链,结果本会话 mcp__chrome__* 和 mcp__beta__* 全部 disconnected(推测当前 session MCP 走 9401/9402),且会话内无法重新连接(MCP 配置在 session 启动时绑定)。

How to apply:

  1. 杀之前先 lsof -nP -p <pid> 看具体 npm exec / chrome-devtools-mcp 进程的 fd 状态,stdio 上有连接才说明在为某 session 服务。
  2. 更稳妥:只用 pkill 杀超过 24h 的明显僵尸(看 STARTED 时间),近期启动的全部保留。
  3. 最稳妥:在用户明确同意失去当前会话 MCP 能力的前提下再清理;否则把"清理"延后到 session 结束后。
  4. 如果会话中确实必须清理:提前告诉用户"清理可能导致本会话 chrome MCP 失联,需要重启 Claude Code",再动手。
  5. 一旦失联:Arc MCP 是兜底,但若用户限定只能 chrome,则只能切纯文本交付让用户手动操作。

Note 2 — Cleanup safety: 'newest = keep' is wrong

清理 chrome-devtools-mcp 重复进程时,不能仅按启动时间挑"最新"保留——Claude Code session 连接的 PID 不一定是最新启动的那组。

Why: 2026-04-15 C55 按 "每端口留最新 kill 其余" 逻辑清理,结果本 session 连接的 beta+arc MCP 双双掉线,用户被迫 /mcp 重连。

How to apply:

  • 清理前先 lsof -i :9402 -i :9501 -i :9401 | grep ESTABLISHED 找出活跃连接的 PID
  • 或问用户 "我看到 N 组重复,session 现在用的是哪个?" 再动手
  • 若无法确认,只 kill 明显孤儿(无 cdp-proxy 对应端口的 9401 那种)
  • 重启路径:用户 /mcp → 选中掉线的 server → reconnect;或整个 Claude Code 重启
  • cdp-proxy 永远别 kill(72446/26413/26239 是核心桥接,kill 掉 Chrome 调试口直断)

Note 3 — Protocol-layer hang vs. healthy proxy

2026-04-23 01:24 C63 触发 3h cron,准备做 HN/Reddit/GitHub 3 平台,但 mcp__beta__* 全部超时:

  • new_page → "Chrome not connected"
  • navigate_page/reload → "Navigation timeout of 10000/30000 ms exceeded"
  • evaluate_script → "Runtime.evaluate timed out"
  • list_pages / select_page 仍然能响应(只返回 tab 元数据,不调 CDP protocol)

curl http://127.0.0.1:9501/json/version 正常返回:

{"Browser":"Chrome (via CDP Proxy v3)","webSocketDebuggerUrl":"ws://127.0.0.1:9501/devtools/browser/..."}

Why: chrome-devtools-mcp 的 Puppeteer 层或 WebSocket session 卡在一个 pending call 上(可能是之前的长 take_snapshot/大 evaluate_script 没正常断开),但 HTTP proxy 还活着,所以看起来"端口通但操作不通"。这个状态不会自愈 — puppeteer 的 CDP session 僵死后只能重建。

How to apply:

1. 僵死诊断(按顺序)

  • mcp__beta__list_pages 能否返回?→ 能(这是 HTTP 端点,不经 CDP session)
  • mcp__beta__evaluate_script 简单语句(() => document.title)是否 timeout?→ timeout = CDP session 僵死
  • curl http://127.0.0.1:9501/json/version 是否 200?→ 是 = Chrome 自己活着
  • 三个条件都满足 = MCP 协议层 hang,不是 Chrome/页面/网络问题

2. 跳过策略(agent 能做的)

  • 不要伪造/编造任何动作——"假设 HN 发了 comment" 会污染 log
  • 不要试图重建连接(kill chrome-devtools-mcp 进程)—— 可能干扰 user 别处正在用的 session
  • 要做
    1. 更新 social-media-posted-log.md 记录"C63 因 MCP hang 跳过,冷却表保持不变"
    2. 在响应里明确告诉 user "Chrome MCP 协议层 hang,需手动重启 MCP"
    3. 不占用 X/其他平台动作额度
    4. 下次 cron (3h 后) 再试

3. 用户恢复建议(写在响应里)

  • 在 Claude Code 里重新连接 MCP(一般 /mcp 或重启 Claude Code)
  • pkill -f chrome-devtools-mcp && 重新 npx chrome-devtools-mcp --browserUrl http://127.0.0.1:9501
  • 重启后不需要重新登录账号(Chrome cookie/session 都在)

4. 本次 hang 疑似起因

本次 session 从 C60 开始连续做了 9 平台 + Bluesky/Reddit/Medium 重页面 take_snapshot(都走 filePath 落盘)。可能某个 take_snapshot 的 a11y tree 大到让 Puppeteer 内部缓冲卡住。后续考虑:单次 take_snapshot 节点数超 5k 后主动关闭并新开 tab。

5. Hang→Disconnect 升级模式(2026-04-23 补充观察)

Hang 状态 不会自愈,且 Claude Code 会在持续一段时间(本次约 7.5h,从 01:24 到 08:52)后主动把 MCP server 标记为 disconnected:

  • Phase 1 (hang): list_pages 响应但 evaluate_script timeout — 部分工具假装可用
  • Phase 2 (disconnect): 所有 mcp__<server>__* 工具从 tool list 消失,runtime 发 "MCP server disconnected" 通知

两个阶段 agent 的应对都是:跳过 cycle,不伪造动作,提示 user 重启。区别只在响应文案(hang 阶段说"MCP 协议层僵死",disconnect 阶段说"MCP server 已断开")。

Agent 不要主动 pkill chrome-devtools-mcp — 本次 session 多个窗口可能共享 MCP,误伤风险大。建议写在响应里让 user 选择是否执行。

6. Hang 复发模式(2026-04-24 补充 / 3 次复发确认)

同一 session 内 hang 可多次复发,不只"开机一次"。本次序列:

  • 2026-04-23 01:24–13:13 第一次 hang(持续 ~12h,user 重启恢复)
  • 2026-04-23 13:15–13:53 C63 执行期(正常)
  • 2026-04-24 00:34 第二次 hang(C63 完成后 ~10h,触发 C64 时发现)
  • 2026-04-24 00:50–01:16 C64+C65 执行期(正常,user /mcp 重连后)
  • 2026-04-24 04:08 第三次 hang(C65 完成后 ~2.7h,触发 C66 时发现)

复发间隔假设(待验证):最初假设 12h → 10h → 2.7h 间隔递减,但第 3 次 hang 至少持续 17h+(2026-04-24 04:08–21:00+ 仍未重启),所以"间隔递减"结论不成立或不稳定。实际观察:hang 本身不会自愈,user 重启间隔取决于 user 何时注意到 + 何时有空介入,不是 MCP 内在规律。

真正可靠的结论只有两点:

  1. Hang 不会自愈,必须外部重启
  2. 同 session 可多次复发(不只"开机一次")

间隔数据不足以下结论。不要向 user 建议"每 2-3h 预防性重启" — 这过度反应,本次 17h hang 证明复发不稳定。

Agent 应对:每次 cycle 开始先跑 mcp__beta__evaluate_script 简单语句做 health check(() => document.readyState),timeout = hang,立刻停并告知 user。不要硬上 new_page/navigate 等重操作。

Health check 一行:轮转开始第一步,在已有 tab 上 evaluate_script 返回 document.titlelocation.href,1–2 秒内应该返回。超过 3 秒 = hang,跳过 cycle。

User 长期对策建议

  • 考虑定时自动 pkill -f chrome-devtools-mcp 每 2-3h 预防性重启(避免 in-cycle hang 打断)
  • 或减少 beta MCP 的重负载操作(take_snapshot 不超 5k nodes / navigate 之间 close 旧 tabs)
  • tab 数量长期保持 <10(目前 session 10+ tabs 在活)

Note 4 — Heavy pages need filePath-first snapshots

Chrome Beta MCP (mcp__beta__*) 在重 feed 页面上的 inline 响应经常超过 25k token 限制,工具直接报错 "exceeds maximum allowed tokens"。

Why: Bluesky following feed、Reddit subreddit/post page、HN 带长帖正文的页面,单次 a11y tree 可达 70-220k chars。这些工具默认把快照内联到响应,Claude 看到的已经是截断版/错误版,影响判断。

How to apply:

  • take_snapshot: 永远带 filePath: "/tmp/xxx.txt" 参数落盘,用 Grep/Bash sed 按需提取 uid
  • click(uid, includeSnapshot: true): 重页面禁用 includeSnapshot;改为 click → take_snapshot(filePath) → Grep 两步
  • wait_for: 重页面可能也会溢出,用小的 text 数组 + 较短 timeout;若溢出就单独 take_snapshot 到文件
  • 轻量页面(HN item、X compose)可以继续 inline 响应
  • 记住:Bluesky home / Reddit sub / 大 thread = 默认 file-first

Fil de discussion

Connectez-vous pour rejoindre la discussion.
Aucun commentaire pour l'instant. Soyez le premier à partager votre avis.

Graphe d'actifs

Comment cet actif se connecte au reste du registre.

Actifs similaires

Chrome MCP Background Proxy — Fix Popups, Focus Stealing & Multi-Agent Conflicts

Persistent CDP proxy + entry script that lets chrome-devtools-mcp run against your real, logged-in Chrome without the Chrome 146+ consent popup spamming on every connection, without focus stealing (Target.activateTarget / Page.bringToFront are intercepted, createTarget is forced to background), and without request-ID / event collisions when multiple Claude Code windows or sub-agents share one Chrome. Includes the proxy core (cdp-proxy.mjs v3), entry script, safe cleanup, pre-flight healthcheck, and a launchd-style self-healing watchdog with Feishu alerts.

MCP ConfigsScripts
henuwangkai· ⭐ 1

Multi-Browser MCP Proxies — Arc Browser & Chrome Beta Variants

Companion to 'Chrome MCP Background Proxy' for running parallel, isolated MCP fleets against Arc Browser and Chrome Beta on top of the same cdp-proxy.mjs. Arc-specific proxy auto-discovers the WebSocket path from /json/version (Arc doesn't write a DevToolsActivePort file in the standard location); Chrome Beta proxy points at Beta's own DevToolsActivePort. Lets you run mcp__chrome__*, mcp__beta__*, and mcp__arc__* side-by-side with independent client state and no cross-talk.

MCP Configs
henuwangkai

Chrome Fleet — Multi-Agent Browser Pool with Shared Login State

Multi-agent control plane for chrome-devtools-mcp. Two modes: (1) shared main Chrome — N CDP proxies on 9401/9402/9403... all multiplexing onto one logged-in Chrome :9222 so every agent inherits your real cookies/extensions, with focus protection and ID isolation handled by cdp-proxy.mjs; (2) isolated agent Chromes — dedicated Chrome instance per agent on :930N with its own user-data-dir for multi-account / persona-isolation testing. Includes a status tool to inspect the running fleet.

MCP Configs
henuwangkai

Codex Chrome MCP Proxy v3

Sanitized public Chrome MCP bundle for Codex: persistent CDP proxy, real Chrome login-state control, background tabs, focus protection, multi-agent isolation, and cached chrome-devtools-mcp startup fallback.

ScriptsConfigs
henuwangkai