Skip to main content
Glama
antonpinchuk

mobile-mcp-opengl

by antonpinchuk

MCP для разработки и автоматизации Android с OpenGL

MCP сервер для AI-кодинг-агентов (Claude Code, Cursor и т.д.) для тестирования Android-приложений, чей весь UI отрисовывается внутри одного непрозрачного OpenGL/Vulkan/Metal-поверхности — Cocos2d-x, Unity, Unreal, чистый OpenGL, libGDX и подобные движки.

Какую проблему это решает

adb shell uiautomator dump и все инструменты автоматизации на основе дерева доступности (включая большинство MCP-серверов для мобильной автоматизации) работают, анализируя нативную иерархию представлений Android — кнопки, метки, их текст и координаты. Это отлично работает для обычного Android-UI, построенного из нативных представлений.

Но это не работает для игры или приложения, которое рендерит весь свой UI как текстуры внутри одного GLSurfaceView. С точки зрения дерева доступности на экране есть ровно одно непрозрачное представление без дочерних элементов, без меток, без координат для чего-либо внутри него. Нечего анализировать — экран является чёрным ящиком, независимо от того, сколько UI на самом деле на нём.

Единственный реальный канал наблюдения — скриншоты. Этот сервер построен вокруг этого факта как обычного случая, а не как случайного запасного варианта.

Чем это отличается от mobile-mcp

mobile-next/mobile-mcp — это универсальный MCP-сервер для мобильной автоматизации, и он хороший выбор по умолчанию для обычных нативных приложений: сначала дерево доступности (быстро, дёшево, без vision-модели, без токенов изображений), с переходом на скриншоты + координаты только когда дерево не даёт нужного.

Для приложения с OpenGL-канвасом этот запасной вариант не случайный — это единственный путь, который вообще работает, каждый раз. mobile-mcp-opengl создан именно для этого случая и в результате принимает два разных дизайнерских решения:

  1. Вообще не пытается использовать дерево доступности. Нет смысла пытаться — для таких приложений оно всегда возвращает пустоту — поэтому каждый инструмент здесь идёт сразу к скриншоту + vision.

  2. Анализ изображений проходит через подключаемый, отдельный провайдер (см. ниже), а не через модель, которая запускает вызывающего агента. Функциональный цикл QA над игрой легко может достигать сотен проверок скриншотов за сессию; прогон всего этого через собственное зрение вашего основного кодинг-агента стоит и реальных денег, и токенов/контекста, которые вы бы предпочли потратить на саму работу по кодингу. Здесь байты скриншотов вообще не попадают в контекст вызывающего агента — только короткий текстовый ответ провайдера.

Related MCP server: Android-MCP

Почему комбинированные инструменты «действие+наблюдение», а не отдельные примитивы

Наивный дизайн предоставляет tap, screenshot и ask как три отдельных инструмента. Это заставляет вызывающего агента оркестрировать многошаговый цикл для каждого взаимодействия: нажатие → сделать скриншот → передать его шагу vision → прочитать результат → решить, что делать дальше. Каждый из этих шагов — отдельный вызов инструмента и отдельный ход — тратя токены на координацию вместо фактической логики теста, и давая больше поверхности для ошибок агента: пропустить шаг, перепутать порядок или рассуждать об устаревшем состоянии между вызовами.

Вместо этого этот сервер предоставляет комбинированные инструменты — tap_and_ask, swipe_and_ask, long_press_and_ask — которые выполняют действие, коротко ждут, делают скриншот, спрашивают vision-провайдера и возвращают один короткий ответ, всё одним вызовом инструмента. Многошаговый тестовый сценарий в итоге стоит примерно один ход агента на значимую проверку, а не три или четыре.

Обычный screenshot_ask (только наблюдение, без действия) и дешёвые инструменты без vision (type_text, press_key, logcat_grep) также доступны для частей тестового потока, которым не нужен этот паттерн.

Инструменты

Инструмент

Что делает

Вызов vision?

screenshot_ask

Скриншот, затем короткий вопрос о нём

Да

tap_and_ask

Нажатие (x, y), ожидание, скриншот, вопрос

Да

swipe_and_ask

Свайп/перетаскивание (x1,y1)→(x2,y2), ожидание, скриншот, вопрос

Да

long_press_and_ask

Долгое нажатие (x, y) в течение заданного времени, ожидание, скриншот, вопрос

Да

record_and_ask

Необязательное действие, затем N скриншотов с интервалами во времени, один и тот же вопрос о каждом кадре

Да (N вызовов)

type_text

Ввод текста в текущее сфокусированное поле

Нет

press_key

Отправка события Android KEYCODE_* (назад, ввод, ...)

Нет

logcat_grep

Чтение последних записей logcat, опционально фильтрация по регулярному выражению

Нет

vision_spend_report

Отчёт о совокупных затратах на vision за сегодня и порогах

Нет

Предпочитайте logcat_grep вызову vision всякий раз, когда то, что вам нужно, уже есть в строке лога (сбои, ваши собственные отладочные выводы, сетевые ошибки) — это бесплатно и точно, а вызов vision — ни то, ни другое.

Проверка анимаций: record_and_ask

Инструменты с одним кадром не могут сказать вам, анимируется ли что-то корректно (пульсирует ли плавно индикатор силы, взлетает ли метка и исчезает, возвращается ли спрайт в начальное положение). record_and_ask выполняет одно необязательное действие (нажатие или свайп, или ничего), ждёт waitMs (то же значение, что и waitMs в tap_and_ask/swipe_and_ask — время для начала реакции UI до первого кадра), затем делает frameCount скриншотов с интервалом intervalMs и возвращает один короткий ответ на каждый кадр — вызывающий агент получает временную шкалу за один вызов инструмента, вместо того чтобы самому организовывать N отдельных циклов скриншот+вопрос.

Почему один вызов vision на кадр, а не один вызов со всеми кадрами вместе. Оказалось, что imageCaption от Runware принимает недокументированный массив inputImages (множественное число) наряду с документированным одиночным inputImage — проверено напрямую через API. Он корректно работает ровно для 2 изображений (сравнение «до/после» в одном запросе вернулось правильным и связным). При 3+ изображениях в одном запросе и этот параметр массива, и вручную скомпонованное изображение-«фильмстрип» давали в тестах усечённые или искажённые ответы — маленькая vision-модель 7B, по-видимому, теряет связность после определённой суммарной визуальной+инструкционной нагрузки в одном вызове. Последовательные вызовы с одним изображением (подход этого инструмента) были надёжны при любом протестированном количестве кадров и не значительно дороже: стоимость определяется длиной ответа (см. ниже), а не количеством вызовов, поэтому N коротких последовательных ответов стоят примерно столько же или меньше, чем один длинный ответ с несколькими изображениями. Если ваш собственный провайдер обрабатывает многокадровые запросы более надёжно, это очевидное место для оптимизации — см. «Своя модель».

Настройка

git clone <this repo>
cd mobile-mcp-opengl
npm install
cp .env.example .env
# edit .env: at minimum set RUNWARE_API_KEY (or switch VISION_PROVIDER, see below)

Требуется adb в PATH (или ADB_PATH, заданный в .env), и запущенное/подключённое устройство или эмулятор. Если подключено более одного, задайте ADB_DEVICE_SERIAL (см. adb devices).

Регистрация в Claude Code

Добавьте .mcp.json в корень вашего проекта (этот файл обычно локальный для проекта и игнорируется git, так как обычно указывает на специфичный для машины путь или содержит специфичные для машины переопределения env):

{
  "mcpServers": {
    "mobile-opengl": {
      "command": "node",
      "args": ["/absolute/path/to/mobile-mcp-opengl/src/server.js"]
    }
  }
}

Claude Code автоматически подхватывает это для проекта. Сервер читает свой собственный .env (рядом с package.json в этом репозитории) для всей конфигурации — вызывающему агенту никогда не нужно знать или передавать какой-либо API-ключ.

Модель затрат — прочтите перед запуском длительной QA-сессии

Длина ответа определяет стоимость, а не размер изображения. Это было измерено эмпирически на провайдере по умолчанию Runware/Qwen2.5-VL-7B-Instruct: один и тот же вопрос с принудительным однословным ответом стоил одинаково ($0.0006) для размеров изображений от 360×360 до 1600×2400 (ретина-класс). То же изображение 1024×1024 с открытым запросом «опиши это» стоило $0.0013–0.0019 — в 2-3 раза больше — исключительно потому, что модель написала более длинный ответ, а не потому, что изображение было больше.

Практические следствия:

  • Не тратьте время на уменьшение скриншотов перед отправкой — это не значительно снижает стоимость для этого провайдера, и вы теряете детали, которые могут понадобиться.

  • Всегда формулируйте вопросы так, чтобы вынуждать короткие ответы: да/нет, число, короткая метка, крошечный JSON-объект с парой полей. Каждый инструмент этого сервера автоматически добавляет инструкцию о коротком ответе, но расплывчатый открытый вопрос («что ты видишь?») всё равно может подтолкнуть модель к более длинному ответу, чем конкретный («видно ли диалог ошибки? да/нет»).

При ~$0.0006 за вызов для хорошо сформулированных коротких вопросов сессия QA на 500 вызовов стоит примерно $0.30. Тот же объём открытых вопросов «опиши экран» может обойтись в 2-3 раза дороже.

Встроенные защитные ограничители затрат

Каждый вызов vision записывается в .vision-log.jsonl (JSONL, одна запись на вызов: временная метка, вопрос, ответ, стоимость). Поверх этого лога работают две независимые защиты, обе не зависят от провайдера (они работают на основе того costUsd, который сообщает провайдер):

  • Предупреждение на вызов (VISION_ALERT_USD, по умолчанию $0.0015): если отдельный вызов возвращается выше этого, ответ инструмента включает примечание [COST ALERT], сообщающее, что модель, вероятно, проигнорировала инструкцию о коротком ответе — сигнал переформулировать вопрос, а не молча проглатывать.

  • Дневной лимит (VISION_SESSION_CAP_USD, по умолчанию $2.00): как только совокупный зарегистрированный расход за сегодня достигает этого, каждый дальнейший вызов vision категорически отклоняется (до того, как он достигнет провайдера), пока лимит не будет повышен или день не сменится. Это жёсткая остановка против зациклившегося цикла, а не просто предупреждение.

Вызовите vision_spend_report в любое время, чтобы проверить сегодняшний итог без обращения к устройству или vision.

Если провайдер не может сообщить стоимость (см. openai-compatible ниже), вызовы от него записываются с costUsd: null и никогда не вызывают предупреждение и не учитываются в лимите — защитные механизмы просто не могут защитить расходы, о которых у них нет информации.

Своя модель

Анализ изображений проходит через src/providers/visionProvider.js, который выбирает провайдера по имени из VISION_PROVIDER в .env. Встроены два:

  • runware (по умолчанию) — напрямую общается с задачей imageCaption от Runware.ai, используя Qwen2.5-VL-7B-Instruct (AIR id runware:152@2) по умолчанию. Runware и OpenRouter — это два отдельных сервиса с отдельными API-ключами и каталогами моделей — этот сервер общается с Runware напрямую, а не через OpenRouter.

  • openai-compatible — универсальный провайдер для всего, что говорит на формате vision OpenAI chat-completions (части контента image_url). Работает с OpenRouter, локальным сервером Ollama/LM Studio с vision-моделью, Groq, Together.ai или любым другим совместимым endpoint. Настройте OPENAI_COMPATIBLE_BASE_URL, OPENAI_COMPATIBLE_API_KEY, OPENAI_COMPATIBLE_MODEL в .env. Большинство OpenAI-совместимых API сообщают об использовании токенов, а не о плоской долларовой стоимости; задайте OPENAI_COMPATIBLE_PRICE_PER_1M_INPUT/_OUTPUT, если хотите, чтобы этот провайдер оценивал costUsd на основе этого (в противном случае отслеживание затрат/защитные механизмы неактивны для этого провайдера, как отмечено выше).

Чтобы добавить полностью кастомного провайдера (самохостинговая модель, совершенно другая форма API), скопируйте src/providers/openaiCompatibleProvider.js как отправную точку, реализуйте:

async function ask(imageBuffer, mimeType, question) {
  // return { text: string, costUsd: number | null }
}
module.exports = { ask };

и зарегистрируйте его с именем в loadProvider() в src/providers/visionProvider.js.

Лицензия

MIT


Разработано Kinect.PRO

Install Server
F
license - not found
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    C
    quality
    B
    maintenance
    A lightweight bridge enabling AI agents to perform real-world tasks on Android devices such as app navigation, UI interaction, and automated QA testing without requiring computer-vision pipelines or preprogrammed scripts.
    14
    807
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to control Android devices and emulators through direct UI interaction, allowing app navigation, automated testing, and real-world task execution via ADB without computer vision or scripts.
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables AI agents to fully control Android devices through over 30 tools for app management, UI automation, and vision-based analysis via ADB. It supports multi-device management, action recording, and smart execution strategies ranging from UI hierarchy parsing to coordinate-based interaction.
    37
    137
    1
    MIT

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/antonpinchuk/mobile-mcp-opengl'

If you have feedback or need assistance with the MCP directory API, please join our Discord server