開源 · MIT 授權 · MCP

讓 AI 直接除錯使用者手機裡的 WebView

在 H5 頁面或 App 的 WebView 裡加一段指令碼。使用者報出一個短短的裝置碼,Claude Code、Codex、Cursor 或任何 MCP 用戶端就能看頁面、查 console 和網路請求,親手點一遍把問題重現出來——整個過程使用者看得見,也隨時可以接管。

  • 不用傳輸線
  • 不開遠端除錯連接埠
  • App 只需注入一段指令碼
  • 問題發生之後再接入也來得及

01線上示範親手體驗

一個真實的 bug,在「真實」的手機上查出來用你自己的 agent 來試一次

示範裡的手機上,商城頁面載入的就是真正的頁面 SDK。閘道在你的瀏覽器裡模擬,任何資料都不會離開這個分頁;但下面每一次快照、點擊、console 輸出和即時修補都是真實的。

這裡是真的:demo.debugger.site 上有一個公開的示範閘道,和其他服務完全隔離,每天清空。手機裡的商城就是從那裡載入的——取得一把金鑰,把 agent 接上去,就在這裡看它做事。

準備就緒
等待商城上線…
demo.debugger.site

AI agent

已連線 rwd MCP 伺服器

看 agent 接入手機、重現結帳頁的 bug、找出根本原因,並在手機上當場驗證修復。

  1. 取得一把自己的金鑰

    點一下就好,不用註冊。這把金鑰只能用於示範閘道,示範每天清空時失效。

    取得後會自動填進下面的指令裡。

  2. 把示範閘道加給你的 agent

    在終端機裡執行一次指令,或者寫進 MCP 用戶端的設定。金鑰已經填好了。

    terminal
    claude mcp add --transport http rwd-demo https://demo.debugger.site/v1/mcp \
      --header "Authorization: Bearer rwd_sk_live_…"
  3. 給 agent 下指令

    手機裡商城的裝置碼已經填進指令裡。agent 要求接入時,在商城裡點 允許,然後看它操作;隨時可以 接管 或 結束。

    指令
    用 rwd-demo 這個 MCP 伺服器連接裝置 XXXX-XXXX。在商城裡給一件商品選上禮盒包裝,去結帳,找出總價顯示「--」的原因。

    把 XXXX-XXXX 換成商城裡顯示的裝置碼。

示範的限制

  • 每位訪客一把金鑰:你的 agent 只能接入你告訴它裝置碼的頁面,而且要你點「允許」
  • 只有 interact 等級:不能執行指令碼,不能讀請求內容和儲存資料
  • 每個 agent 最多佔用頁面 15 分鐘(閒置 5 分鐘即釋放)
  • 每個 IP 每分鐘最多 120 次 MCP 請求
  • 每天 04:00(UTC+8)清空,請不要輸入真實的個人資料

使用者的手機K7Q2-9M4X

示範商城,真實線上····-····

等待商城上線…

用手機掃描 QR 碼開啟
在新分頁開啟

這就是 demo.debugger.site 本身,跑著真實的 SDK。也可以掃描 QR 碼,在手機上開啟。

完全在瀏覽器裡執行:iframe 裡是真實的 SDK(sdk.js),WebSocket 墊片把它的連線透過 postMessage 轉給頁面裡的模擬閘道,再由一個照腳本執行的 agent 發出真實的 RPC。agent 的話跟隨頁面語言;工具結果使用閘道語言(英文或中文)。

02運作原理

從「我手機上打不開」到找出根本原因,只要三步

  1. 頁面接入 SDK

    在 <head> 裡盡早加一段指令碼,console 和網路從第一行就開始記錄。App 裡則在頁面開始載入時注入同一段指令碼。

  2. 使用者報出裝置碼

    每台手機都有一個固定的裝置碼,例如 K7Q2-9M4X,顯示在一個小膠囊裡。使用者點一下 請求協助,這台裝置就會排到 agent 清單的最前面。

  3. agent 透過 MCP 接入

    用 API 金鑰把閘道的託管 MCP 位址加進你的 agent,然後直接描述問題。agent 會自己找到裝置、請求使用者同意,然後開始追查。

index.html
<!-- 放在 <head> 里,越早越好;生产环境请锁定版本号 -->
<script src="https://cdn.jsdelivr.net/npm/remote-webview-debugger/dist/sdk.js"></script>
<script>
  RemoteWebviewDebugger.run("https://rwd.example.com/v1", "rwd_pk_…", {
    userId: currentUser?.id ?? null, // 可选:按用户查找设备
    helpButton: true,                // 显示「请求协助」按钮
  })
</script>

正式環境請鎖定版本號,或者直接用你閘道自帶的 /v1/sdk.js(主控台提供 SRI 校驗值)。

terminal
claude mcp add --transport http rwd https://rwd.example.com/v1/mcp \
  --header "Authorization: Bearer rwd_sk_live_…"
裝置 K7Q2-9M4X 結不了帳,合計顯示「--」,幫我查一下原因。

03agent 能做什麼

你熟悉的 DevTools 那一套,透過 MCP 用在別人的手機上

  • 無障礙快照

    Playwright 風格的 YAML,元素帶 ref。agent 依結構理解頁面,而不是盯著像素,再用 ref 精準操作。

  • 真實的互動

    點擊、填入、輸入、按鍵、下拉選擇、游標停留、捲動、拖曳,都帶可操作性檢查,React、Vue 的受控元件也認。

  • console 與網路

    從頁面載入起就記錄在有上限的緩衝區裡,agent 接入之前的錯誤也查得到;需要時還能看請求和回應內容。

  • 跨頁面工作階段

    列表頁 → 商品頁 → 結帳頁,或者新開的 WebView,同一台裝置的所有頁面組成一個工作階段,附跨頁面時間軸。

  • 變化自動推送

    每個工具結果最後都會附上發生了什麼:新頁面、跳轉、錯誤、使用者接管。agent 不用輪詢。

  • 手機上的任務卡片

    agent 把計畫和進度顯示在裝置頂端,使用者隨時知道 AI 在做什麼、做到哪一步。

  • 螢幕截圖

    App 提供原生截圖橋接時是真實畫面,否則用 DOM 重新繪製。兩種方式都會遮蔽敏感資訊。

  • 裝置端工作階段記錄

    從 App 啟動起,頁面、點擊、console 和每個請求都冷存在手機的 IndexedDB 裡,事後也能回看。

  • 即時修補

    advanced 等級下,agent 可以用 evaluate_script 為執行中的頁面打上修補,當場驗證修復。

  • 網路不佳也能用

    輕量心跳加上指數退避;連續 3 次失敗後改為每分鐘輪詢一次,需要時由閘道喚醒頁面。

  • 11 種語言

    手機端介面、主控台和 agent 看到的文字都有 11 種語言,含由右至左的阿拉伯文。也支援自訂語言包和用詞。

  • 任何 MCP 用戶端

    /v1/mcp 是 Streamable HTTP,Claude Code、Codex、Cursor 直接可用;只支援 stdio 的用戶端用一個很小的橋接指令。

全部工具 34

  • list_devices
  • connect_device
  • wait_for_device
  • list_pages
  • select_page
  • wait_for_page
  • take_snapshot
  • find_elements
  • take_screenshot
  • click
  • fill
  • type_text
  • press_key
  • select_option
  • hover
  • scroll
  • drag
  • batch_actions
  • navigate_page
  • go_back
  • reload_page
  • wait_for
  • list_console_messages
  • list_network_requests
  • get_network_request
  • get_storage
  • evaluate_script
  • set_task
  • get_session_timeline
  • get_session_overview
  • get_session_log
  • wait_for_event
  • wait_for_control
  • disconnect_device

04亮點

專為那些「只在使用者那裡出現」的 bug 而生

傳輸線、遠端除錯連接埠和螢幕錄影都給不了的三樣東西。

工作階段記錄 · 冷存在裝置端

bug 已經發生過了?記錄還在手機裡。

從 App 啟動那一刻起,SDK 就把工作階段記錄寫進裝置的 IndexedDB:造訪過的頁面、使用者的點擊和輸入、console 輸出、每一個請求——失敗的請求連標頭和內容一起留下。這些資料不會流向任何地方;它們按同樣的遮蔽規則留在手機上,直到使用者核准的 agent 用 get_session_overview 和 get_session_log 來讀。保留最近 3 次啟動,每次最多 10 MB。

即時修補 · evaluate_script

上線之前,先在使用者手機上驗證修復。

使用者授予 advanced 等級後,evaluate_script 直接在頁面裡執行——agent 可以修正錯誤的狀態、覆寫一個函式、重新繪製畫面,然後在真實裝置上看結果:一個用來證明診斷的即時修補。它只存在於那個頁面的記憶體裡,不會留存;敏感點擊仍然需要使用者點頭。

面向 agent · MCP

為 agent 而設計,而不是給拿著 DevTools 的人用。

每個工具結果最後都附上上次呼叫以來裝置上的變化,agent 永遠不用輪詢。頁面內容作為不可信的資料交給模型。手機上的任務卡片展示 agent 的計畫,閘道也說 agent 的語言——工具說明和結果都有 11 種語言。

05隱私與控制

使用者的手機,始終由使用者做主

遠端除錯的前提是信任。每一次接入都看得見、要同意、能隨時打斷。

  • 先同意,再接入

    agent 要求接入時,使用者在手機上看到是誰、要什麼權限,自己選擇等級。只認真實的點擊,指令碼沒辦法替使用者點「允許」。

  • 隨時接管或結束

    AI 操作時頁面邊緣亮起光暈,使用者的輸入被鎖定。點一下 接管 AI 立刻暫停,點 結束 直接斷線。

  • 預設遮蔽敏感資訊

    密碼欄位和帶 data-rwd-mask 的內容,在快照、螢幕截圖、console、網路資料和工作階段記錄裡都顯示為 ••••。還可以按專案設定選擇器和規則運算式。

  • 敏感操作要使用者點頭

    給「送出訂單」「刪除帳號」這類按鈕加上 data-rwd-confirm,agent 每次點擊前都要使用者確認。

  • 權限分級

    observe 只看,interact 可操作,advanced 還能執行指令碼、讀請求內容和儲存資料。按 API 金鑰和專案分別設上限。

  • 稽核記錄

    每次接入、核准、RPC 呼叫和接管都會記下誰、做了什麼、什麼時候——但不記錄頁面內容和參數值。

06App 原生整合

在 App 裡,就是一段注入的指令碼

下載一次 SDK,在頁面開始載入時注入:iOS 用 WKUserScript,Android 用 addDocumentStartJavaScript。網頁本身一行都不用改。

  • 一台手機一個裝置碼

    傳入固定的 deviceId(並保存 deviceToken),裝置碼跨 WebView、跨網域都不變。

  • 原生控制按鈕

    用 nativeControl() 做自己的接管 / 交還 / 結束按鈕,頁面指令碼呼叫不了。

  • 原生核准對話框

    nativeApproval: true 把接入核准和敏感操作確認交給 App 自己的介面。

  • 真實畫面截圖

    一個很小的橋接(WKWebView 快照、Android 位圖),agent 拿到的是真實畫面而不是 DOM 重新繪製。

RemoteDebugger.swift
import WebKit

/// 在 webView.load(…) 之前调用:下载一次 SDK,在 documentStart 注入。
func installRemoteDebugger(into controller: WKUserContentController,
                           userId: String?, done: @escaping () -> Void) {
    let gateway = "https://rwd.example.com/v1"
    URLSession.shared.dataTask(with: URL(string: gateway + "/sdk.js")!) { data, _, _ in
        DispatchQueue.main.async {
            defer { done() }
            guard let data, let sdk = String(data: data, encoding: .utf8) else { return }
            let options: [String: Any] = [
                "deviceId": stableDeviceId, // 存在 UserDefaults 里的 UUID
                "userId": userId ?? NSNull(),
                "helpButton": true,
            ]
            let json = String(data: try! JSONSerialization.data(withJSONObject: options), encoding: .utf8)!
            let boot = sdk + "\n;RemoteWebviewDebugger.run(\"\(gateway)\", \"rwd_pk_…\", \(json));"
            controller.addUserScript(WKUserScript(source: boot,
                                                  injectionTime: .atDocumentStart,
                                                  forMainFrameOnly: true))
        }
    }.resume()
}

07自行架設

一個 Go 執行檔,跑在你自己的伺服器上

閘道內嵌了 Web 主控台和頁面 SDK。預設用 SQLite,需要時換成 Postgres;Docker Compose 加 Caddy 負責 HTTPS。

  • 主控台

    裝置、API 金鑰、成員與角色、QR 碼邀請、安全原則、稽核記錄,還有一份填好你自己金鑰的整合指南。

  • 資料庫

    預設是一個 SQLite 檔案;設定 RWD_DATABASE_URL=postgres://… 即可改用 Postgres。

  • 維運

    /v1/metrics 提供 Prometheus 指標,SDK 有帶版本號和 SRI 校驗的位址,/v1/healthz 用於健康檢查。

部署說明

快速開始
# 一個容器:主控台 + 閘道 + SDK
docker run -d --name rwd -p 8080:8080 -v rwd-data:/data \
  -e RWD_ADMIN_PASSWORD='change-me' \
  ghcr.io/zanel1u/remote-webview-debugger:latest

# 或者自己建置、上傳,由 Caddy 提供 HTTPS
git clone https://github.com/ZaneL1u/remote-webview-debugger
RWD_DOMAIN=rwd.example.com \
  remote-webview-debugger/deploy/platform/deploy.sh you@your-server amd64
# → 主控台  https://rwd.example.com
# → 閘道    https://rwd.example.com/v1(MCP 在 /v1/mcp)

伺服器上只需要 Docker;從原始碼建置需要 Go 和 Node。

08常見問題

大家常問的問題

使用者需要安裝什麼嗎?

不需要。H5 頁面裡 SDK 就是頁面的一部分;App 裡由原生程式碼注入。使用者只會看到一個顯示裝置碼的小膠囊,以及 agent 要求接入時的確認對話框。

agent 能看到什麼、做什麼?

只限使用者核准的範圍:這台裝置上的 WebView 頁面,依授予的權限等級。WebView 之外的 App 介面和系統一概碰不到。遮蔽的欄位始終是遮蔽的,頁面內容也會作為不可信的資料交給模型。

bug 在 agent 接入之前就發生了,還查得到嗎?

查得到。SDK 從 App 啟動起就在裝置上寫工作階段記錄——頁面、點擊、console 和請求——之後接入的 agent 用 get_session_log 就能把通往 bug 的整條路徑讀出來。除此之外,記錄不會離開手機。

agent 能直接在手機上把 bug 修好嗎?

它能驗證修復:在 advanced 等級下,evaluate_script 在記憶體裡為執行中的頁面打上修補——修正狀態、覆寫函式、重新繪製——agent 就能看到問題是否消失。真正的修復仍然走你正常的發布流程;裝置上不會留下任何東西。

支援哪些 agent?

任何 MCP 用戶端。Claude Code、Codex、Cursor 直接連託管的 Streamable HTTP 位址;只支援 stdio 的用戶端用 rwd mcp,它只是把 stdio 轉送到同一個位址。

支援哪些平台?

主流的行動裝置 WebView 和瀏覽器都可以:iOS 的 WKWebView、Android System WebView、各類 App 內建瀏覽器,以及手機上的 Safari、Chrome。桌面瀏覽器也能用。

網路很差或者 WebSocket 被擋下怎麼辦?

頁面只維持一條輕量的心跳 WebSocket,斷線後以指數退避重連。連續 3 次連不上,就改成每分鐘輪詢一次;agent 要接入時,閘道會通知它立即重連。

會拖慢頁面嗎?

只是一段指令碼。console 和網路記錄放在有上限的環形緩衝區裡(各 500 筆,回應內容總共不超過 5MB),工作階段記錄在背景寫入,閒置時連線上只有心跳。

能和 eruda、vConsole、PageSpy 一起用嗎?

可以。快照和命中測試會跳過它們的節點,SDK 自己的流量也不會出現在它們的網路面板裡,甚至可以作為一個分頁收進 eruda。

上面的示範是真的嗎?

SDK 是真實的,沒有任何改動;只有閘道是在你瀏覽器裡模擬的。一個 WebSocket 墊片透過 postMessage 把 SDK 的連線轉給它,再由照腳本執行的 agent 發出和真實閘道一樣的 RPC。想完整體驗真實鏈路,可以用你自己的 agent 試一次。