Multi-Browser MCP Proxies — Arc & Chrome Beta
Companion bundle to Chrome MCP Background Proxy. Same cdp-proxy.mjs
backbone, repointed at Arc Browser and Chrome Beta so you can run independent,
isolated MCP fleets for each browser without losing focus protection or popup
suppression.
Why a separate proxy per browser
- Independent login state — your work Chrome stays untouched while Arc drives experiments, or vice versa.
- Independent debug ports — Arc and Chrome Beta both write their own
DevToolsActivePortfiles; the proxy reads each browser's file via--devtools-port-file. - No cross-talk — each proxy has its own
clientState,sessionOwners, andpendingRequestsmap. A Chrome Beta sub-agent can't accidentally hijack Arc tabs.
Files
| File | Default ports | Reads DevToolsActivePort from |
|---|---|---|
arc-mcp-proxy.sh |
proxy 9501 → Arc 9223 |
~/chrome-profiles/arc-DevToolsActivePort (auto-built from /json/version on each launch) |
chrome-beta-mcp-proxy.sh |
proxy 9402 → Chrome Beta 9222 |
~/Library/Application Support/Google Chrome Beta/DevToolsActivePort |
Both wrap the same cdp-proxy.mjs from the parent bundle (Chrome MCP Background Proxy). Drop that file into ~/scripts/ first.
Arc setup
Arc doesn't write DevToolsActivePort to a standard location. Launch it with
an explicit debug port and the proxy script will discover the WebSocket path
on its own:
open -a "Arc" --args --remote-debugging-port=9223
bash ~/scripts/arc-mcp-proxy.sh # proxy :9501 → Arc :9223.mcp.json:
"arc": {
"command": "bash",
"args": ["/Users/<you>/scripts/arc-mcp-proxy.sh", "9501", "9223"]
}Chrome Beta setup
Chrome Beta writes its own DevToolsActivePort file under
~/Library/Application Support/Google Chrome Beta/. Once Beta is running with
remote debugging enabled (chrome://inspect/#remote-debugging → Allow), the
proxy auto-discovers it.
"beta": {
"command": "bash",
"args": ["/Users/<you>/scripts/chrome-beta-mcp-proxy.sh", "9402", "9222"]
}Running all three side by side
Claude Code window A → mcp__chrome__* → :9401 → Chrome stable :9222
Claude Code window B → mcp__beta__* → :9402 → Chrome Beta :9222
Claude Code window C → mcp__arc__* → :9501 → Arc :9223Three independent proxies, three independent browsers, three sets of MCP tool namespaces. They never collide.
Caveat — don't kill cross-session
Heuristics like "kill 9401/9402 because they're not LISTEN" will tear down a
sibling session's MCP. Always check lsof -nP -p <pid> for live stdio before
killing anything. See the Chrome MCP Operations Runbook skill for the full
cleanup protocol.
#!/bin/bash
Arc MCP + 持久 Proxy
用法: arc-mcp-proxy.sh [proxy端口] [arc调试端口]
复用 cdp-proxy.mjs,但连接 Arc 浏览器(固定端口 9223)
Arc 需要用 open -a "Arc" --args --remote-debugging-port=9223 启动
PROXY_PORT=${1:-9501} ARC_DEBUG_PORT=${2:-9223} PROXY_SCRIPT="/Users/wangkai/scripts/cdp-proxy.mjs" PID_DIR="/Users/wangkai/chrome-profiles/pids" LOG_DIR="/Users/wangkai/chrome-profiles/logs" ARC_DEVTOOLS_PORT_FILE="/Users/wangkai/chrome-profiles/arc-DevToolsActivePort"
mkdir -p "$PID_DIR" "$LOG_DIR"
本地连接绕过代理
unset http_proxy HTTP_PROXY https_proxy HTTPS_PROXY all_proxy ALL_PROXY export no_proxy="127.0.0.1,localhost" export NO_PROXY="127.0.0.1,localhost"
从 Arc 调试端口的 /json/version 获取 wsPath,写入 DevToolsActivePort 格式文件
WS_URL=$(curl -s --noproxy '*' "http://127.0.0.1:${ARC_DEBUG_PORT}/json/version" 2>/dev/null
| python3 -c "import sys,json; print(json.load(sys.stdin)['webSocketDebuggerUrl'])" 2>/dev/null)
if [ -n "$WS_URL" ]; then # 从 ws://127.0.0.1:9223/devtools/browser/xxx 中提取路径部分 WS_PATH=$(echo "$WS_URL" | sed 's|ws://[^/]*||') printf '%s\n%s\n' "${ARC_DEBUG_PORT}" "${WS_PATH}" > "${ARC_DEVTOOLS_PORT_FILE}" fi
如果 Proxy 没跑,启动它(持久运行,不随 Claude Code 退出而死)
if ! lsof -i :${PROXY_PORT} >/dev/null 2>&1; then
nohup node "${PROXY_SCRIPT}"
--port ${PROXY_PORT}
--chrome-port ${ARC_DEBUG_PORT}
--devtools-port-file "${ARC_DEVTOOLS_PORT_FILE}"
&>"${LOG_DIR}/proxy-${PROXY_PORT}.log" &
echo $! > "${PID_DIR}/proxy-${PROXY_PORT}.pid"
disown
sleep 2
fi
启动 chrome-devtools-mcp,连接到 Proxy
exec npx -y chrome-devtools-mcp@latest --browserUrl "http://127.0.0.1:${PROXY_PORT}"
#!/bin/bash
Chrome Beta MCP + 持久 Proxy
用法: chrome-beta-mcp-proxy.sh [proxy端口] [chrome端口]
与普通 Chrome proxy 完全独立,互不干扰
PROXY_PORT=${1:-9402} CHROME_PORT=${2:-9222} PROXY_SCRIPT="/Users/wangkai/scripts/cdp-proxy.mjs" PID_DIR="/Users/wangkai/chrome-profiles/pids" LOG_DIR="/Users/wangkai/chrome-profiles/logs" DEVTOOLS_PORT_FILE="$HOME/Library/Application Support/Google/Chrome Beta/DevToolsActivePort"
mkdir -p "$PID_DIR" "$LOG_DIR"
本地连接绕过代理
unset http_proxy HTTP_PROXY https_proxy HTTPS_PROXY all_proxy ALL_PROXY export no_proxy="127.0.0.1,localhost" export NO_PROXY="127.0.0.1,localhost"
如果 Proxy 没跑,启动它(持久运行,不随 Claude Code 退出而死)
if ! lsof -i :${PROXY_PORT} >/dev/null 2>&1; then
nohup node "${PROXY_SCRIPT}"
--port ${PROXY_PORT}
--chrome-port ${CHROME_PORT}
--devtools-port-file "${DEVTOOLS_PORT_FILE}"
&>"${LOG_DIR}/proxy-${PROXY_PORT}.log" &
echo $! > "${PID_DIR}/proxy-${PROXY_PORT}.pid"
disown
sleep 2
fi
启动 chrome-devtools-mcp,连接到 Proxy
exec npx -y chrome-devtools-mcp@latest --browserUrl "http://127.0.0.1:${PROXY_PORT}"