Открытый код · MIT · MCP

Пусть ваш ИИ-агент отладит WebView на телефоне вашего пользователя.

Добавьте один скрипт на H5-страницу или в WebView приложения. Пользователь называет короткий код устройства — и Claude Code, Codex, Cursor или любой MCP-клиент видит страницу, читает console и сетевые запросы и проходит по багу своими нажатиями, пока пользователь всё видит и может в любой момент взять управление.

  • Без USB-кабеля
  • Без порта удалённой отладки
  • В приложении — только один скрипт
  • Работает и после того, как баг случился

01Онлайн-демоНа практике

Настоящий баг, найденный на «настоящем» телефонеА теперь попробуйте со своим агентом

Телефон в этом демо запускает настоящий SDK страницы внутри демо-магазина. Его шлюз смоделирован в вашем браузере, поэтому из этой вкладки ничего не уходит — но каждый снимок, нажатие, строка console и живой патч ниже настоящие.

Это — настоящее: публичный демо-шлюз на demo.debugger.site, отделённый от всего остального и очищаемый каждый день. Магазин в телефоне загружен оттуда: получите ключ, направьте на него своего агента и смотрите, как он работает прямо здесь.

Готово к запуску
Ждём, когда магазин выйдет в сеть…
demo.debugger.site

ИИ-агент

подключён к MCP-серверу rwd

Посмотрите, как агент подключается к телефону, воспроизводит баг на оформлении заказа, находит первопричину и проверяет исправление вживую.

  1. Получите свой собственный ключ

    Один клик, без регистрации. Ключ работает только на демо-шлюзе и действует до следующей очистки демо.

    Получите ключ — и он подставится в команду ниже.

  2. Добавьте демо-шлюз своему агенту

    Выполните команду один раз в терминале или добавьте её в настройки своего MCP-клиента. Ключ уже подставлен.

    terminal
    claude mcp add --transport http rwd-demo https://demo.debugger.site/v1/mcp \
      --header "Authorization: Bearer rwd_sk_live_…"
  3. Дайте агенту задание

    Код устройства магазина в телефоне уже подставлен в запрос. Когда агент попросит подключиться, нажмите Разрешить в магазине и смотрите, как он работает; в любой момент можно нажать Перехватить или Завершить.

    Запрос
    Используй MCP-сервер rwd-demo и подключись к устройству XXXX-XXXX. В магазине выбери для товара подарочную упаковку, перейди к оформлению заказа и выясни, почему итог показывается как «--».

    Замените XXXX-XXXX кодом, который показан в магазине.

Ограничения демо

  • По одному ключу на посетителя: ваш агент дойдёт только до той страницы, код которой вы ему дали, и только после того, как вы разрешите
  • Только уровень interact: без скриптов, тел запросов и хранилища
  • Агент держит страницу не дольше 15 минут (5 при простое)
  • 120 MCP-запросов в минуту на один IP
  • Очистка каждый день в 04:00 (UTC+8) — не вводите настоящие персональные данные

Телефон покупателяK7Q2-9M4X

Демо-магазин, вживую····-····

Ждём, когда магазин выйдет в сеть…

Отсканируйте, чтобы открыть на телефоне
Открыть в новой вкладке

Это и есть demo.debugger.site с настоящим SDK. Отсканируйте код, чтобы вместо этого открыть магазин на телефоне.

Всё работает в вашем браузере: настоящий SDK (sdk.js) в iframe, прослойка WebSocket, которая туннелирует его соединение к смоделированному шлюзу на этой же странице, и сценарный агент, отправляющий настоящие RPC. Агент говорит на языке страницы; результаты инструментов — на языке шлюза (английский или китайский).

02Как это работает

Три шага от «у меня на телефоне не работает» до первопричины

  1. Добавьте SDK страницы

    Один скрипт в <head>, как можно раньше, чтобы console и сеть записывались с первой строки. В приложении внедрите тот же скрипт в самом начале загрузки документа.

  2. Пользователь сообщает код устройства

    У каждого телефона есть постоянный код вида K7Q2-9M4X в небольшой плашке. Пользователь может нажать Запросить поддержку — и устройство окажется в начале списка у агента.

  3. Ваш агент подключается по MCP

    Добавьте MCP-адрес вашего шлюза с API-ключом. А дальше просто опишите проблему — агент сам найдёт устройство, запросит разрешение и приступит к работе.

index.html
<!-- In <head>, before your own scripts; pin a version in production -->
<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, // optional: find devices by user
    helpButton: true,                // show the “Request assistance” button
  })
</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 не оформляется заказ — итог показывается как «--». Выясни почему.

03Что получает агент

Привычный процесс DevTools — через MCP, на чужом телефоне

  • Снимки доступности

    YAML в стиле Playwright с ref элементов. Агент читает страницу как структуру, а не как пиксели, — и действует по ref.

  • Настоящие взаимодействия

    click, fill, type, press, select, hover, scroll, drag — с проверкой доступности элемента и событиями, которые принимают React и Vue.

  • Console и сеть

    Записываются с загрузки страницы в буферы ограниченного размера, поэтому ошибки, случившиеся до подключения агента, никуда не денутся. Тела — по запросу.

  • Сеансы из нескольких страниц

    Список → карточка товара → оформление заказа или второй WebView: все страницы устройства образуют один сеанс с общей хронологией.

  • Изменения сеанса приходят сами

    Каждый результат инструмента заканчивается тем, что изменилось: новая страница, переход, ошибка, перехват управления пользователем. Опрашивать ничего не нужно.

  • Карточка задачи на телефоне

    Агент показывает на устройстве свой план и прогресс, так что пользователь всегда знает, что он делает и зачем.

  • Скриншоты

    Реальные пиксели, если приложение предоставляет мост, иначе — отрисовка DOM. Маскирование работает и там, и там.

  • Журнал сеанса на устройстве

    Страницы, нажатия, console и каждый запрос с момента запуска приложения — хранятся на телефоне в IndexedDB и читаются уже после того, как всё случилось.

  • Живые патчи

    На уровне advanced агент может пропатчить работающую страницу через evaluate_script и проверить исправление на месте.

  • Плохие сети

    Лёгкий heartbeat с нарастающими паузами; после трёх неудач — опрос присутствия раз в минуту, а шлюз будит страницу, когда это нужно.

  • 11 языков

    Интерфейс на телефоне, console и текст для агента на 11 языках, включая арабский с письмом справа налево. Свои языковые пакеты и формулировки — пожалуйста.

  • Любой MCP-клиент

    Streamable HTTP по адресу /v1/mcp для 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Главное

Сделано для багов, которые случаются только «там»

Три вещи, которых не дадут ни кабель, ни порт удалённой отладки, ни запись экрана.

Журнал сеанса · холодное хранение на устройстве

Баг уже случился? Журнал всё ещё на телефоне.

С момента запуска приложения SDK пишет журнал сеанса в IndexedDB устройства: посещённые страницы, нажатия и ввод пользователя, вывод console и каждый запрос — неудачные с заголовками и телами. Никуда ничего не передаётся: всё остаётся на телефоне, по тем же правилам маскирования, пока агент, которому пользователь разрешил доступ, не запросит журнал через get_session_overview и get_session_log. Хранятся три последних запуска, до 10 МБ каждый.

Живой патч · evaluate_script

Проверьте исправление на телефоне покупателя — до релиза.

С разрешения пользователя на уровне advanced evaluate_script выполняется прямо в странице — так агент может поправить испорченное состояние, подменить функцию или перерисовать вид и увидеть результат на реальном устройстве: живой патч, который подтверждает диагноз. Он живёт только в памяти этой страницы, ничего не сохраняется, а чувствительные нажатия по-прежнему требуют согласия пользователя.

Для агентов · MCP

Сделано для агентов, а не для человека с DevTools.

Каждый результат инструмента заканчивается тем, что изменилось на устройстве со времени прошлого вызова, поэтому агенту никогда не нужно ничего опрашивать. Содержимое страницы передаётся как недоверенные данные. Карточка задачи на телефоне показывает план агента, а шлюз говорит на языке агента — описания и результаты инструментов на 11 языках.

05Приватность и контроль

Телефон пользователя остаётся телефоном пользователя

Удалённая отладка работает только там, где ей доверяют. Каждый сеанс видно, он требует разрешения и его можно прервать.

  • Сначала разрешение

    Агент просит подключиться; пользователь видит, кто спрашивает, и сам выбирает уровень на телефоне. Считаются только настоящие нажатия — скрипт не может разрешить доступ сам себе.

  • Перехватить или завершить — в любой момент

    Пока агент работает, страница заблокирована, а по её краю идёт светящаяся рамка. Одно нажатие на Перехватить — и агент на паузе; Завершить отключает его.

  • Маскирование по умолчанию

    Пароли и всё, что помечено data-rwd-mask, показываются как •••• в снимках, скриншотах, console, сетевых данных и журнале сеанса. Селекторы и регулярные выражения настраиваются для каждого проекта.

  • Чувствительные нажатия требуют согласия

    Помечайте кнопки атрибутом data-rwd-confirm («Оформить заказ», «Удалить аккаунт») — и пользователь будет подтверждать каждое нажатие агента по ним.

  • Уровни доступа

    observe читает, interact действует, advanced добавляет скрипты, тела запросов и хранилище. Ограничиваются отдельно по ключу и по проекту.

  • Журнал аудита

    Каждое подключение, разрешение, вызов RPC и перехват управления записываются: кто, что и когда — но никогда содержимое страницы и значения параметров.

06Нативные приложения

В вашем приложении это один пользовательский скрипт

Скачайте SDK один раз и внедряйте его в самом начале загрузки документа: WKUserScript на iOS, addDocumentStartJavaScript на Android. Ваши веб-страницы не меняются вообще.

  • Один код устройства везде

    Передайте постоянный deviceId (и сохраните deviceToken), чтобы код не менялся между WebView и доменами.

  • Нативные кнопки управления

    Покажите свои собственные кнопки перехвата / возврата / завершения через nativeControl(); скрипты страницы вызвать его не могут.

  • Нативные диалоги разрешения

    nativeApproval: true передаёт запросы на подключение и подтверждения в интерфейс вашего приложения.

  • Скриншоты в реальных пикселях

    Небольшой мост (снимок WKWebView, bitmap на Android) даёт агенту настоящие пиксели вместо отрисовки DOM.

RemoteDebugger.swift
import WebKit

/// Call before webView.load(…): fetch the SDK once, inject it at document start.
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, // a UUID kept in UserDefaults
                "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. Ваши серверы. Ваши данные.

В шлюз встроены веб-консоль и SDK страницы. SQLite из коробки, Postgres — когда понадобится, Docker Compose и Caddy для HTTPS.

  • Веб-консоль

    Устройства, API-ключи, участники и роли, приглашения по QR-коду, политики и журнал аудита — плюс руководство по интеграции, уже заполненное вашими ключами.

  • Хранилище

    По умолчанию файл SQLite; задайте RWD_DATABASE_URL=postgres://…, чтобы использовать Postgres.

  • Эксплуатация

    Метрики Prometheus по адресу /v1/metrics, версионированные адреса 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

# или соберите, разверните и получите HTTPS с Caddy
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 — часть вашей страницы. В приложении вы внедряете его из нативного кода. Пользователь видит только небольшую плашку с кодом устройства, а когда подключается агент — диалог с запросом разрешения.

Что агент может видеть и делать?

Только то, что разрешил пользователь: страницы WebView этого устройства на выданном уровне. За пределами WebView он не управляет вообще ничем. Замаскированные поля остаются замаскированными, а содержимое страницы передаётся модели как недоверенные данные.

Баг случился до того, как агент подключился. Он потерян?

Нет. SDK ведёт журнал сеанса на устройстве с момента запуска приложения — страницы, нажатия, console и запросы, — поэтому агент, подключившийся позже, прочитает по нему весь путь до бага через get_session_log. В остальное время журнал не покидает телефон.

Может ли агент исправить баг прямо на телефоне?

Он может проверить исправление: на уровне advanced evaluate_script патчит работающую страницу в памяти — поправить состояние, подменить функцию, перерисовать — и агент видит, пропадает ли проблема. Настоящее исправление по-прежнему выходит с вашим обычным релизом, а на устройстве ничего не сохраняется.

Какие агенты с этим работают?

Любой MCP-клиент. Claude Code, Codex и Cursor обращаются к размещённому эндпоинту Streamable HTTP напрямую; клиенты, которые умеют только stdio, используют rwd mcp — небольшой мост к тому же эндпоинту.

Какие платформы поддерживаются?

Любой современный мобильный WebView или браузер: WKWebView на iOS, Android System WebView, встроенные браузеры приложений, обычные мобильные Safari и Chrome. Настольные браузеры тоже работают.

А если сеть плохая или WebSocket заблокирован?

Страница держит лёгкий heartbeat по WebSocket с экспоненциально растущими паузами. Если подключиться не удаётся три раза подряд, она переходит на опрос присутствия раз в минуту, а шлюз будит её, когда агент хочет подключиться.

Это замедлит мою страницу?

Это один скрипт. Записи console и сети лежат в кольцевых буферах ограниченного размера (по 500 записей, тела ответов — не больше 5 МБ), журнал сеанса пишется в фоне, а простаивающее соединение обменивается только heartbeat-ами.

Работает ли он рядом с eruda, vConsole или PageSpy?

Да: их узлы пропускаются в снимках и при попадании по координатам, наш собственный трафик не попадает в их сетевые логи, а сам инструмент может жить даже вкладкой внутри eruda.

Демо выше настоящее?

SDK настоящий и неизменённый; смоделирован только шлюз — в вашем браузере. Прослойка WebSocket туннелирует к нему соединение SDK через postMessage, а сценарный агент отправляет те же RPC, что отправлял бы настоящий шлюз. Чтобы увидеть всё по-настоящему, от начала до конца, попробуйте со своим агентом.