MCP server by OHIMEOPP
chrome-guide-mcp
最小 PoC:用 Chrome DevTools Protocol (CDP) 讓 AI(Claude)讀取一個 Chrome 分頁的 accessibility tree(文字,不是截圖)、在元素上畫 原生高亮框 + 提示泡泡、並 等待使用者真的操作 —— 拿來做 AI 動態生成的「使用引導」。
不需要寫 Chrome extension、不過商店審查。AI 全程用節點 id(backendDOMNodeId)操作,不碰 CSS selector。
Claude ── MCP (stdio) ── 這個 server ── WebSocket ── Chrome (--remote-debugging-port=9222)
快速啟動(給之後要用的 agent)
要驅動引導,先要有一個「開著 debug port」的 Chrome 可連。三步:
- 裝依賴:
npm install(需 Node ≥18) - 開 debug Chrome(關鍵:
--user-data-dir必須指向非預設資料夾,Chrome 136+ 才會開 port):Start-Process "<chrome.exe 路徑>" -ArgumentList '--remote-debugging-port=9222','--user-data-dir=<你的 debug profile 資料夾>'- 要帶登入狀態:
--user-data-dir指向一份從你日常 profile 複製來的資料夾(複製方式見下方「Chrome 136+ 限制」)。複製出來的是常駐分身,可重複用,不必每次重建。
- 要帶登入狀態:
- 確認連得上:瀏覽器開
http://localhost:9222/json/version有 JSON = OK。然後就能npm run demo或讓已註冊的 MCPchrome-guide來驅動。
本機若已有現成的 debug profile,直接用它啟動即可(路徑見你的私有筆記/記憶,不寫進本公開 repo)。
工具
所有工具吃一個選填的 tabId(從 list_tabs 拿;省略則用第一個/最近使用的分頁)。
| Tool | 作用 |
|------|------|
| list_tabs | 列出所有分頁:[{id, title, url}],拿 id 指定要操作哪個分頁 |
| snapshot | 回傳指定分頁的精簡 AX tree:[{id, role, name, value, states}] |
| highlight | 在頁面內注入高亮框 + 提示泡泡(預設帶 ✕ 關閉鈕;給 nextLabel 再加一顆「下一步」按鈕)+ 把該分頁帶到最前面 |
| wait_for_action | 事件式:注入一次性 listener,阻塞到使用者操作,回三態並自動清高亮 |
| monitor_action | poll 式:每拍輪詢條件(url/selector/gone),跨頁面跳轉也穩,回三態 |
| cancel_guide | 取消:設旗標 + 清高亮,讓任何正在跑的 monitor(含背景 watcher)下一拍自我銷毀 |
| clear_highlight | 移除高亮框 + 泡泡 |
| focus_tab | 把某分頁帶到最前面(不高亮)|
| navigate | 控制分頁跳轉 URL |
| evaluate | 在頁面跑 JS,撈 AX tree 拿不到的任意狀態 |
系列引導:wait_for_action 三態
highlight 預設在泡泡上放一個 ✕ 關閉鈕;wait_for_action 會等到下列任一發生,並回報,讓模型決定系列引導怎麼走:
| 回傳 | 意義 | 系列引導動作 |
|------|------|------------|
| {done:true, event} | 使用者完成了操作(點/輸入該元素)| 推進下一步 |
| {closed:true} | 使用者按了 ✕ | 中止系列(使用者想退出)|
| {timeout:true} | 逾時沒動作 | 重新提示或跳過 |
高亮是注入頁面內的自繪框(非 CDP 原生 overlay),所以 ✕ 關閉鈕與完成偵測都由我們控制、即時生效。
偵測方式:事件式 vs poll 式(兩者並存)
| | 事件式(wait_for_action)| poll 式(monitor_action)|
|---|---|---|
| 機制 | 注入 addEventListener,事件觸發即回 | 每 pollMs 輪詢頁面狀態 |
| 偵測 | 「該元素被點/輸入」的瞬間 | 「頁面狀態到了預期下一步」 |
| 弱點 | ⚠️ 點擊若跳轉頁面,listener 隨舊頁面銷毀 → 競態易掉 | latency 一拍;要給完成條件 |
| 適合 | 不跳轉的互動(開關、輸入、頁內按鈕)| 會換頁/換狀態的步驟(系列引導預設走這個)|
poll 完成條件(任一成立即 done):untilUrl(網址含某段,對付跳轉最常用)、untilSelector(某元素出現,對付彈窗/下一步冒出)、untilGone(被高亮元素離開 DOM);都不給則退回「點該元素」。
「下一步」按鈕(最可靠的推進):highlight 給 nextLabel(如「我已完成」)會在泡泡加一顆按鈕;使用者在真實頁面做完動作後點它 → 回 {done, by:"next"}。這是我們自己的按鈕,偵測 100% 可靠、不用猜完成條件,跟 ✕ 同一套旗標機制。(注意:不要用「複製目標元素到泡泡裡讓人點 clone」——clone 會丟失原本的事件處理器,點了不會真的觸發 app 動作。)
等待方式:阻塞 MCP vs 背景 watcher
| 方式 | 怎麼用 | 適合 |
|------|--------|------|
| 阻塞 MCP:wait_for_action / monitor_action | 同步等到三態才回,佔住該次工具呼叫 | agent 一步步驅動、不介意等待的緊湊迴圈 |
| 背景 watcher:examples/watch-action.js | Bash run_in_background 啟動,使用者一解決就 exit → harness 喚醒 agent | fire-and-forget、中途 agent 想做別的(≈ mailbox-watch.py)|
背景 watcher 跟 mailbox-watch.py 同型:背景盯 → 使用者完成/按 ✕ 就 exit 印一行 JSON → harness 的 background-task 通知喚醒 agent,~0 token、不卡 turn。--mode poll(預設)或 --mode event。
# poll 式:高亮 step-1 並背景監看,點了(跳轉到 /projects/new)/按 ✕/逾時都會喚醒 agent
node examples/watch-action.js --tab <tabId> --node <nodeId> \
--tip "點這裡新增專案" --label step-1 --until-url "/projects/new" --timeout 600000
# 輸出(單行):{"label":"step-1","node":234,"mode":"poll","result":{"done":true,"by":"url","url":"…/projects/new"}}
# {"label":"step-1","node":234,"mode":"poll","result":{"closed":true}} ← 使用者按 ✕
⚠️ git-bash / MSYS 啟動雷:在 git-bash 下,
--until-url "/issues"這種斜線開頭的參數會被 MSYS 自動轉成 Windows 路徑(變成C:/.../issues),條件永遠不匹配 → watcher 空轉到 timeout。前面加MSYS_NO_PATHCONV=1即可(MSYS_NO_PATHCONV=1 node examples/watch-action.js ... --until-url "/issues")。Linux/macOS/PowerShell 無此問題。
取消 / 銷毀
- 使用者按 ✕ 或呼叫
cancel_guide→ 設window.__guideClosed旗標 → 任何 monitor(poll/event、阻塞/背景)下一拍自我銷毀並回{closed}。 - 要硬殺背景 watcher 程序 → 用 harness TaskStop 砍它的 task id。
系列引導 = 每步「重新 snapshot(node id 會隨頁面重繪變動)→ highlight → 背景 watch」→ 被喚醒讀結果 → done 接下一步、closed 中止、timeout 重提示。
安裝
npm install
1) 用 remote-debugging 開 Chrome
開之前先完全關閉既有 Chrome(否則 flag 不生效)。
Windows (PowerShell)
& "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="$env:TEMP\chrome-guide-profile"
macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-guide-profile
--user-data-dir 指向一個臨時 profile,避免汙染你的日常 Chrome。
在這個 Chrome 視窗打開任意網頁(你要引導的那個 app)。
⚠️ Chrome 136+ 重要限制:Google 從 Chrome 136 起,基於安全禁止
--remote-debugging-port用在「預設 profile」。所以你不能直接把日常 Chrome 帶 flag 重開來連——--user-data-dir必須指向一個非預設資料夾,port 才會開。要帶著你的登入狀態,做法是複製 profile:把
%LOCALAPPDATA%\Google\Chrome\User Data複製一份到別的資料夾(複製前先全關 Chrome;建議用robocopy /XD排除Cache/Code Cache/GPUCache等快取夾),再用那份--user-data-dir啟動。複製出來的是分身,登出/改密碼不影響本尊。注意有些站台(如 GitHub)的 session cookie 走 httpOnly+secure,複製後仍可能要重登。🔒 善後:那份複製的 profile 含你的 cookie/登入憑證,且 debug port 無認證。玩完請關掉該 Chrome 並刪除整個複製資料夾。真要做給終端使用者的產品,正解是 Chrome extension(跑在使用者真實瀏覽器內、不開 debug port、不複製 profile)。
2) 冒煙測試(不接 MCP,先驗 CDP 通不通)
npm run demo
會印出前幾個可互動元素、高亮其中一個、並等你在 Chrome 裡點它。
多步系列引導範本:examples/guide-loop.js(npm run guide)——一個泛用 driver loop,把 highlight + wait 串成多步流程。改最上面的 STEPS 陣列即可換成你的流程。範本示範了系列引導必踩的三件事:每步前重新 snapshot(node id 隨頁面重繪變動)、用 role+name 找元素而非寫死 id、依「會不會跳轉」選事件式(waitForAction)或 poll 式(monitorAction + untilUrl),並處理 {done} 推進 / {closed} 中止 / {timeout} 重提三態。
3) 註冊成 Claude Code 的 MCP
claude mcp add chrome-guide -- node "C:/Users/user/Desktop/VSCodeProgram/chrome-guide-mcp/src/server.js"
或在專案 .mcp.json:
{
"mcpServers": {
"chrome-guide": {
"command": "node",
"args": ["C:/Users/user/Desktop/VSCodeProgram/chrome-guide-mcp/src/server.js"]
}
}
}
引導迴圈(AI 端的用法)
snapshot→ AI 看到當前頁面有哪些可互動元素- AI 判斷「下一步該做什麼」→
highlight(id, "點這裡新增專案") wait_for_action(id)→ 等使用者照做- 回到 1,看新頁面狀態,推進下一步
比寫死的 Driver.js tour 強在:AI 看 live DOM 動態生成步驟,頁面改版不用重寫腳本。
已知限制(PoC)
- 預設連到第一個 page target(單分頁夠用;多分頁/iframe 尚未處理)
highlight跟著 viewport 走,頁面捲動後泡泡位置不會自動更新(重畫一次即可)wait_for_action一次綁一個事件、once 觸發- 沒有 auth / 多 client 隔離 —— 純本機 PoC