Chrome Fleet — Multi-Agent Browser Pool with Shared Login State
Run several MCP-driven sub-agents against one main Chrome — preserving
your real login state — without focus stealing, ID collisions, or "agents
stomping each other's tabs". This is the multi-agent control plane built on
top of cdp-proxy.mjs from the Chrome MCP Background Proxy bundle.
Two modes
Mode 1: Shared main Chrome (chrome-fleet.sh)
Agent 1 → CDP Proxy :9401 ─┐
Agent 2 → CDP Proxy :9402 ─┼→ main Chrome :9222 (shared login state)
Agent 3 → CDP Proxy :9403 ─┘Every agent gets its own proxy and its own client-state bucket inside
cdp-proxy.mjs, but they all multiplex onto the same Chrome — so all your
existing sessions, cookies, and extensions are available to every agent.
bash ~/scripts/chrome-fleet.sh start 3 # launches proxies on 9401/9402/9403
bash ~/scripts/chrome-fleet.sh status # show which proxies are alive
bash ~/scripts/chrome-fleet.sh stop # stop all proxies (Chrome stays up).mcp.json per agent:
"chrome": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest", "--browserUrl", "http://127.0.0.1:9401"]
}Bump the port (9402, 9403, …) for each additional agent.
Mode 2: Isolated agent Chromes (chrome-agent.sh / chrome-agent-status.sh)
When you actually want separate browser profiles per agent (e.g. testing N independent logins), spin one Chrome instance per agent on its own profile
- debug port:
bash ~/scripts/chrome-agent.sh 1 # → Chrome :9301, profile agent-1
bash ~/scripts/chrome-agent.sh 2 # → Chrome :9302, profile agent-2
bash ~/scripts/chrome-agent-status.sh # list running agent Chromes (9301-9310)Each agent's Chrome window is positioned with a slight offset so you can see
which is which. .mcp.json per agent points at its own browser URL.
When to use which
| Use case | Mode |
|---|---|
| Multiple agents driving the same logged-in user (parallel research, batch automation, social-media operations) | Shared main Chrome |
| Multiple agents simulating different users (multi-account testing, persona isolation) | Isolated agent Chromes |
| One agent, one session | Just chrome-mcp-proxy.sh from the parent bundle |
Files
| File | Role |
|---|---|
chrome-fleet.sh |
Launch / stop / status for N proxies on 940X against shared main Chrome :9222 |
chrome-agent.sh <N> |
Boot a dedicated Chrome on :930N with profile ~/chrome-profiles/agent-N |
chrome-agent-status.sh |
Show all running agent Chromes (ports 9301–9310) plus the default 9222 |
Dependencies
cdp-proxy.mjsfrom the Chrome MCP Background Proxy bundle in~/scripts/cdp-proxy.mjs.chrome-mcp-proxy.shif you also want the popup-suppression layer for the shared-Chrome mode (chrome-fleet.sh startalready wires the proxy in).
#!/bin/bash
═══════════════════════════════════════════════════════
Chrome Fleet — 多 Agent 共享主浏览器(保留登录态)
架构:
Agent 1 → Proxy :9401 ─┐
Agent 2 → Proxy :9402 ─┼→ 主 Chrome :9222 (共享登录态)
Agent 3 → Proxy :9403 ─┘
每个 Proxy 独立连 Chrome,互不干扰,不抢焦点
用法:
bash ~/scripts/chrome-fleet.sh start [数量] # 启动 (默认3)
bash ~/scripts/chrome-fleet.sh stop # 停止所有 proxy
bash ~/scripts/chrome-fleet.sh status # 查看状态
═══════════════════════════════════════════════════════
PROXY_SCRIPT="/Users/wangkai/scripts/cdp-proxy.mjs" LOG_DIR="/Users/wangkai/chrome-profiles/logs" PID_DIR="/Users/wangkai/chrome-profiles/pids" CHROME_PORT=9222
mkdir -p "$LOG_DIR" "$PID_DIR"
─── 检查主浏览器 ───
check_chrome() { if ! lsof -i :${CHROME_PORT} >/dev/null 2>&1; then echo "" echo " ⚠️ 主浏览器未开启调试端口 ${CHROME_PORT}" echo "" echo " 方法 1 (推荐): Chrome 地址栏打开 chrome://inspect/#remote-debugging" echo " 勾选 'Allow remote debugging for this browser instance'" echo "" echo " 方法 2: 命令行启动 Chrome" echo " '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' --remote-debugging-port=${CHROME_PORT} &" echo "" return 1 fi return 0 }
─── 启动单个 CDP Proxy ───
start_proxy() { local num=$1 local proxy_port=$((9400 + num))
if lsof -i :${proxy_port} >/dev/null 2>&1; then
echo " Proxy ${num}: 已在运行 (端口 ${proxy_port})"
return 0
fi
node "${PROXY_SCRIPT}" \
--port ${proxy_port} \
--chrome-port ${CHROME_PORT} \
&>"${LOG_DIR}/proxy-${num}.log" &
echo $! > "${PID_DIR}/proxy-${num}.pid"
echo " Proxy ${num}: 已启动 (端口 ${proxy_port} → Chrome :${CHROME_PORT})"}
─── START ───
do_start() { local count=${1:-3} echo "" echo "╔══════════════════════════════════════════╗" echo "║ Chrome Fleet 启动中 ║" echo "║ 所有 Agent 共享主浏览器登录态 ║" echo "╚══════════════════════════════════════════╝" echo ""
check_chrome || exit 1
echo " 主浏览器已就绪 (端口 ${CHROME_PORT})"
echo ""
for i in $(seq 1 ${count}); do
start_proxy ${i}
done
echo ""
echo " ┌─────────┬──────────────┬─────────────────────┐"
echo " │ Agent │ Proxy 端口 │ Chrome │"
echo " ├─────────┼──────────────┼─────────────────────┤"
for i in $(seq 1 ${count}); do
printf " │ Agent %-1s │ :%-11s │ :${CHROME_PORT} (主浏览器) │\n" "$i" "$((9400 + i))"
done
echo " └─────────┴──────────────┴─────────────────────┘"
echo ""
echo " 全部共享登录态, Proxy 自动拦截焦点切换"
echo ""
echo " 项目 .mcp.json 配置示例:"
echo ' "chrome": {'
echo ' "command": "npx",'
echo ' "args": ["-y", "chrome-devtools-mcp@latest", "--browserUrl", "http://127.0.0.1:940X"]'
echo ' }'
echo ' X = Agent 编号 (1/2/3)'
echo ""}
─── STOP ───
do_stop() { echo "" echo "停止所有 Proxy..."
for f in "${PID_DIR}"/proxy-*.pid; do
[ -f "$f" ] || continue
pid=$(cat "$f")
if kill -0 "$pid" 2>/dev/null; then
kill "$pid"
num=$(basename "$f" .pid | sed 's/proxy-//')
echo " 停止 Proxy ${num} (PID ${pid})"
fi
rm -f "$f"
done
echo " 完成 (主浏览器保持运行)"
echo ""}
─── STATUS ───
do_status() { echo "" echo "╔══════════════════════════════════════════╗" echo "║ Chrome Fleet 状态 ║" echo "╚══════════════════════════════════════════╝" echo ""
# 主浏览器
pid=$(lsof -ti :${CHROME_PORT} 2>/dev/null | head -1)
if [ -n "$pid" ]; then
echo " 主浏览器: ✅ 运行中 (端口 ${CHROME_PORT})"
else
echo " 主浏览器: ❌ 未运行 (端口 ${CHROME_PORT})"
fi
echo ""
# Proxy
local found=0
for port in $(seq 9401 9410); do
pid=$(lsof -ti :${port} 2>/dev/null | head -1)
if [ -n "$pid" ]; then
num=$((port - 9400))
echo " Proxy ${num}: ✅ 运行中 (端口 ${port}, PID ${pid})"
found=1
fi
done
if [ "$found" -eq 0 ]; then
echo " 无 Proxy 运行"
fi
echo ""}
─── 主入口 ───
case "${1:-status}" in start) do_start "${2:-3}" ;; stop) do_stop ;; status) do_status ;; *) echo "用法: $0 {start [数量] | stop | status}" exit 1 ;; esac
#!/bin/bash
为 Agent 启动独立的 Chrome 实例(独立 Profile + 独立调试端口)
用法: chrome-agent.sh [agent编号]
示例: chrome-agent.sh 1 → 端口 9301, Profile agent-1
chrome-agent.sh 2 → 端口 9302, Profile agent-2
AGENT_NUM=${1:-1} PORT=$((9300 + AGENT_NUM)) PROFILE_DIR="/Users/wangkai/chrome-profiles/agent-${AGENT_NUM}" CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
检查端口是否已占用
if lsof -i :${PORT} >/dev/null 2>&1; then echo "Agent ${AGENT_NUM} 的 Chrome 已在运行 (端口 ${PORT})" exit 0 fi
echo "启动 Agent ${AGENT_NUM} 的 Chrome..." echo " 端口: ${PORT}" echo " Profile: ${PROFILE_DIR}"
--no-first-run: 跳过首次运行向导
--no-default-browser-check: 跳过默认浏览器检查
--window-position: 不同 agent 窗口错开位置
WINDOW_X=$((100 + (AGENT_NUM - 1) * 50)) WINDOW_Y=$((100 + (AGENT_NUM - 1) * 50))
"${CHROME}"
--remote-debugging-port=${PORT}
--user-data-dir="${PROFILE_DIR}"
--no-first-run
--no-default-browser-check
--window-position=${WINDOW_X},${WINDOW_Y}
--window-size=1280,900
&>/dev/null &
echo "Chrome 已启动, PID: $!" echo "" echo "在 .mcp.json 中使用:" echo ' "chrome-agent-'${AGENT_NUM}'": {' echo ' "command": "npx",' echo ' "args": ["-y", "chrome-devtools-mcp@latest", "--browserUrl", "http://127.0.0.1:'${PORT}'"]' echo ' }'
#!/bin/bash
查看所有 Agent Chrome 实例的状态
echo "=== Agent Chrome 实例状态 ===" echo ""
for port in $(seq 9301 9310); do pid=$(lsof -ti :${port} 2>/dev/null | head -1) if [ -n "$pid" ]; then agent_num=$((port - 9300)) echo "Agent ${agent_num}: 运行中 (端口 ${port}, PID ${pid})" fi done
也检查默认的 9222 端口
pid=$(lsof -ti :9222 2>/dev/null | head -1) if [ -n "$pid" ]; then echo "默认 Chrome: 运行中 (端口 9222, PID ${pid})" fi
echo "" echo "=== 用法 ===" echo "启动: bash ~/scripts/chrome-agent.sh [编号]" echo "关闭: kill $(lsof -ti :[端口])"