Документация Раннер как MCP-сервер (браузер для вашего агента)

Раннер как MCP-сервер — дайте своему ИИ-агенту браузер

Любой агент, говорящий по MCP — Claude Code, Cursor, ваш собственный агент на
SDK — может управлять раннером Mockarty напрямую: открывать страницы, читать их,
кликать, вводить текст, делать скриншоты и управлять подключённым
Android-телефоном.

Браузерным инструментам не нужен сервер Mockarty, аккаунт или лицензионный
ключ.
Скачайте раннер, запустите в режиме MCP, подключите агента — этой
поверхностью можно пользоваться где угодно, как альтернативой полноценному
стеку браузерной автоматизации.

Управление устройствами и остальные механики тестирования — часть платформы:
они появляются только после рукопожатия раннера с сервером Mockarty
(COORDINATOR_URL + API_TOKEN, на сборке с лицензионным ключом Mockarty).
Неспаренный раннер их вообще не показывает — вы всегда видите ровно те
инструменты, которые сработают.

Зачем это агенту

Полноценный браузер стоит 50–150 МБ на инстанс и медленно стартует. Раннер
использует лёгкий headless-движок: сотни параллельных сессий помещаются на
скромной машине, а страницы возвращаются текстом или markdown — именно тем,
что модель реально читает, без лишнего круга со скриншотами.

Запуск

# stdio — транспорт, который локальные MCP-клиенты запускают сами
mockarty-runner mcp

# или по сети (нужен токен)
MOCKARTY_RUNNER_MCP_TOKEN=ваш-секрет mockarty-runner mcp --http 127.0.0.1:9800

Подключите MCP-клиент. Для Claude Code — в .mcp.json:

{
  "mcpServers": {
    "mockarty-runner": {
      "command": "mockarty-runner",
      "args": ["mcp"]
    }
  }
}

Через HTTP:

{
  "mcpServers": {
    "mockarty-runner": {
      "type": "http",
      "url": "http://127.0.0.1:9800/mcp",
      "headers": { "X-API-Key": "ваш-секрет" }
    }
  }
}

Инструменты

Сначала вызовите runner_info — он расскажет, что умеет эта машина (браузерный
движок, подключённые устройства, платформа), чтобы агент не гадал.

Инструмент Что делает
runner_info Возможности раннера — вызывать первым
Смотреть
browser_snapshot Элементы управления как ref=N role "имя" — действуйте по ref, без выдумывания CSS. Огромная страница обрезается и сообщает об этом; browser_find всё равно дотянется до контрола за кэпом
browser_read Содержимое страницы: text, markdown, outline, links. Очень большая страница обрезается (200 КБ / 500 ссылок) и ответ об этом сообщает — уточните селектором или browser_find за остальным
browser_find Поиск элементов по видимому имени → refs
browser_screenshot PNG страницы (когда важны пиксели). По умолчанию возвращает ссылку на скачивание (output="link"), чтобы большая картинка не топила контекст; output="base64" — только чтобы отдать пиксели vision-шагу
browser_pdf Сохранить страницу в PDF → ссылка на скачивание (или output="base64"). Проверка печатной вёрстки, архивация. Только движок Chromium — на раннере с движком light не показывается
Навигация
browser_open / browser_goto Открыть сессию / перейти. browser_open принимает storageState (из browser_storage_state), чтобы стартовать уже залогиненным
browser_back / browser_forward / browser_reload История
browser_wait_for Ждать появления/исчезновения текста, селектора или паузу
Взаимодействие
browser_act click / fill / press — по ref или CSS-селектору
browser_fill_form Заполнить всю форму за один вызов (+ опциональный submit-селектор или submitRef-ref из snapshot) — логин/регистрация одним тулом
browser_hover Наведение (меню, подсказки)
browser_select Выбор пункта(ов) в <select>
browser_check Поставить/снять галочку у чекбокса или радио
browser_upload Прикрепить файлы к file-инпуту
browser_drag Перетащить элемент на другой — каждый конец по селектору (from/to) или ref из snapshot (fromRef/toRef)
browser_key Клавиша странице (Escape, Enter, Control+A)
browser_resize Сменить вьюпорт (адаптивность)
Вкладки и диагностика
browser_tabs list / new / select / close
browser_capture Начать запись консоли и сети
browser_console Записанный вывод консоли (ошибки JS)
browser_network Записанные запросы (метод + URL)
Сессия
browser_eval Выполнить JS-выражение (результат обрезается ~200 КБ — возвращайте небольшое значение, не outerHTML)
browser_sessions Список открытых сессий
browser_storage_state Выгрузить cookies + localStorage (войти один раз и переиспользовать)
browser_close Закрыть сессию
Проверки
browser_case Прогнать целый ТЕСТ-КЕЙС одним вызовом — JSON-массив шагов goto/back/forward/reload/act/select/check/key/hover/drag/resize/upload/fill_form/wait/assert → отчёт PASS/FAIL; останавливается на первом упавшем шаге. Тестирование браузерных кейсов сверх пошагового драйва
browser_assert PASS/FAIL: текст (вхождение или regex), видимость, значение, количество, url, title, атрибут, checked, enabled
browser_dialog Принять или отклонить следующий alert / confirm / prompt
browser_element_screenshot Скриншот одного элемента (по умолчанию ссылка; output="base64" — инлайн)
browser_visual_diff PASS/FAIL против baseline-картинки, которую вы передаёте — доля изменённых пикселей; на fail подсвеченный diff приходит ссылкой
Аудиты (из коробки — у Playwright MCP нет ни того, ни другого)
browser_perf Отчёт производительности: web-vitals уровня Lighthouse из Performance API — TTFB, DOM interactive / content-loaded, load, First Contentful Paint, best-effort Largest Contentful Paint, число запросов, переданные байты
browser_a11y Аудит доступности: title/lang, структура заголовков, число landmark’ов и WCAG-проблемы — картинки без alt, контролы без label, кнопки/ссылки без доступного имени

Мобильные инструменты (для спаренных раннеров)

Когда раннер подключён к серверу Mockarty И к нему подключено Android-устройство
(adb в PATH, отладка по USB включена), появляется мобильная поверхность —
всё, что нужно агенту для управления телефоном, без установки Appium:

Инструмент Что делает
device_list Подключённые устройства
device_info Размер экрана, плотность, версия Android, модель
device_source Иерархия экрана как ref=N Class "текст" @x,y — действуйте по ref. Плотный экран обрезается и сообщает об этом; сузьте через filter или device_find
device_find Поиск по тексту / content-desc / resource id
device_tap Тап по ref (предпочтительно) или по x,y
device_text Ввод текста в активное поле
device_swipe Свайп по direction=up/down/left/right или координатам
device_key back, home, enter, recent, delete, громкость…
device_screenshot PNG экрана
device_app launch / terminate / clear / current / list
device_wait_for Ждать появления или исчезновения текста
device_assert PASS/FAIL: text_contains, text_absent, element_visible, element_absent, app_is
device_case Прогнать целый ТЕСТ-КЕЙС НА УСТРОЙСТВЕ одним вызовом — JSON-массив шагов app/tap/text/swipe/key/wait/assert → отчёт PASS/FAIL; останавливается на первом упавшем шаге (мобильный аналог browser_case)

runner_info сообщает, в каком вы режиме, и — в публичном — как разблокировать
остальное.

Мобильный сценарий

device_app     {"deviceId":"…","action":"launch","package":"com.example.app"}
device_wait_for{"deviceId":"…","text":"Вход"}
device_source  {"deviceId":"…"}              → ref=5 Button "Подключиться" @541,750
device_tap     {"deviceId":"…","ref":5}
device_assert  {"deviceId":"…","kind":"text_contains","expected":"Готово"}

Тап по ref, а не по пикселям, — именно это позволяет сценарию пережить другой
размер экрана и делает историю прогона читаемой.

Рабочий цикл

browser_open     {"url": "https://example.com"}          → sessionId
browser_snapshot {"sessionId": "s1"}                     → ref=2 textbox "Username", ref=1 button "Sign in"
browser_act      {"sessionId": "s1", "ref": 2, "kind": "fill", "value": "demo"}
browser_act      {"sessionId": "s1", "ref": 1}           → клик
browser_wait_for {"sessionId": "s1", "text": "Welcome"}  → дождаться асинхронного результата
browser_read     {"sessionId": "s1", "mode": "markdown"} → проверить
browser_close    {"sessionId": "s1"}

Используйте одну сессию на весь сценарий. browser_snapshot показывает, что
можно нажать; browser_read — что страница говорит. Действие по ref надёжнее
рукописного CSS-селектора и переживает перерисовки. После асинхронных действий —
browser_wait_for, а не опрос чтением.

Когда сценарий устоялся, оберните его в browser_case — прогон как один
повторяемый тест с единым вердиктом PASS/FAIL, как нужно CI:

browser_case {"url": "https://app/login", "steps": "[
  {\"do\":\"fill_form\",\"fields\":[{\"selector\":\"#user\",\"value\":\"demo\"}],\"submit\":\"button[type=submit]\"},
  {\"do\":\"wait\",\"text\":\"Welcome\"},
  {\"do\":\"assert\",\"kind\":\"text_contains\",\"expected\":\"Welcome, demo\"}
]"}
→ CASE PASSED (3/3 steps)     (или CASE FAILED at step N — останавливается там)

Чтобы прогнать кейс за логином одним вызовом, передайте storageState (JSON,
который вернул предыдущий browser_storage_state) вместе с url — свежая сессия
стартует уже аутентифицированной, и весь кейс идёт залогиненным без шага логина.
Требует движок Chromium (лёгкий движок не восстанавливает сохранённое состояние).

Типы шагов кейса: goto (переход), back/forward/reload (история навигации), act (click/fill/press по селектору или
ref), select (выбрать values в <select>), check (поставить галку —
checked по умолчанию true; передайте false, чтобы снять), key (клавиша —
Enter/Escape/Tab/ArrowDown), hover (навести указатель на селектор/ref —
раскрывает hover-меню), drag (перетащить источник селектор/ref на цель
to/toRef), resize (задать вьюпорт width×height — тестирование
адаптивности на любом разрешении), upload (прикрепить files с диска раннера
к file-<input> — по сетевому транспорту нужен RUNNER_MCP_UPLOAD_DIR),
fill_form (целая форма, опциональный
submit-селектор или submitRef), wait (ждать text/selector/gone, опциональный ms) и assert
(text_contains/text_matches/text_absent/visible/hidden/value/count/url_contains/title_contains/attribute/checked/enabled/disabled). Этого хватает на реальную форму —
включая выпадающие списки и чекбоксы — одним вызовом.

Разбор странного поведения страницы: browser_capture → воспроизвести →
browser_console и browser_network.

Чего он не сделает

  • Только http и https. file:// и прочие схемы отклоняются, поэтому
    чтение страницы никогда не превратится в чтение локальных файлов.
  • Адреса проверяются. Метаданные облака и некорректные хосты отклоняются.
    Если вы намеренно тестируете такой адрес — MOCKARTY_VIEW_ALLOW_ANY_TARGET=1.
    Переключатель один и снимает ту же проверку для каждого браузера, которым
    управляет Mockarty, — включая UI-тесты и интерактивные сессии, а не только
    для этого.
  • Платформенные инструменты без рукопожатия не появятся. Устройства и
    механики тестирования бэкенда — это возможности Mockarty; публичная
    поверхность — браузер.
  • HTTP-транспорт требует токен. Эти инструменты управляют настоящим
    браузером на вашей машине, поэтому без токена сетевой режим не стартует.
  • Относитесь к токену как к доступу к шеллу. Держатель токена может навести
    браузер на любой http(s)-адрес, достижимый с вашей машины, прочитать то, что
    рендерит любая страница, и приложить любой локальный файл, доступный процессу
    раннера (browser_upload), к странице. Привязывайте --http к loopback
    (127.0.0.1) или доверенной сети и выдавайте токен только агентам, которым
    доверяете так же, как доверили бы шелл на этой машине.

Параметры

Флаг / переменная Значение
--http <адрес> Отдавать streamable HTTP вместо stdio
--max-sessions N Лимит браузерных сессий (по умолчанию 100, LRU-вытеснение)
--session-ttl D Время жизни простаивающей сессии (по умолчанию 10m)
MOCKARTY_RUNNER_MCP_TOKEN Токен для HTTP-транспорта
RUNNER_MCP_ENGINE Движок браузера: chromium (по умолчанию) или light
RUNNER_BROWSER_AUTO_INSTALL 0 — не скачивать браузер при первом запуске (изолированные хосты)
RUNNER_ADB_BINARY Путь к adb, если его нет в PATH
VIEWCORE_ACT_TIMEOUT_MS Сколько browser_act / browser_fill_form ждут элемент до ошибки (по умолчанию 15000). Уменьшите для ещё более быстрой реакции на неверный селектор; увеличьте для страниц, где элементы появляются медленно.
RUNNER_MCP_UPLOAD_DIR По HTTP-транспорту browser_upload может читать файлы только из этой директории (удалённый клиент не должен читать произвольные файлы сервера). Не задано при HTTP = browser_upload запрещён. По stdio игнорируется — там клиент это локальный пользователь.

Какой движок браузера

По умолчанию сервер работает на полном Chromium. Он открывает https://
на любой машине, а сам браузер скачивается автоматически при первом открытии
страницы — ставить руками ничего не нужно.

RUNNER_MCP_ENGINE=light переключает на лёгкий движок: он держит гораздо
больше параллельных сессий при той же памяти — это удобно для массовых
скриптовых прогонов. Для открытия https:// ему нужно хранилище сертификатов
хоста, поэтому используйте его на сервере, где оно есть, а не на ноутбуке.
servo-ядро рендера лёгкого движка меняет размер окна на каждый скриншот, поэтому
смена viewport между кадрами (browser_resize перед снимком, разные viewport)
действует на обоих движках — тест может снимать одну сессию в нескольких
разрешениях на любом из них.

Изолированная среда: раннер с движками внутри

Обычная сборка скачивает движок браузера при первом обращении. В изолированном
контуре скачивать неоткуда, поэтому раннер можно собрать самодостаточным:
лёгкие движки запекаются в бинарь и распаковываются при первом использовании.
Один файл, ноль сети, работает за air gap.

GOOS=linux GOARCH=amd64 bash scripts/fetch-engines.sh   # один раз скачать движки
go build -tags embedengines -o mockarty-runner ./cmd/mockarty-runner

На выходе — единый бинарь (~270 МБ, движки внутри), который выполняет
browser_* вообще без скачиваний. Без тега получится «лёгкая» сборка (~70 МБ),
которая догружает движки по требованию — это правильный выбор, когда на машине
есть интернет.

Настоящие браузеры Playwright (Chromium/Firefox/WebKit) остаются отдельной
подключаемой историей — они не запекаются никогда. Либо укажите раннеру заранее
установленный браузер, либо пропишите пути к заранее положенным файлам движков
через RUNNER_LIGHTPANDA_PATH / RUNNER_SERVO_PATH.

Что дальше

Тот же раннер может войти в грид Mockarty (COORDINATOR_URL + API_TOKEN) и
выполнять UI-, нагрузочные, фаззинг- и мобильные тесты, приходящие с платформы,
с отчётами, историей и гридом устройств. См. Браузерный
раннер
и Метки раннеров.