podium-mcp

MCP unificado móvil E2E — 28 herramientas (paridad con mobile-mcp + Maestro + RN-debugger)

Documentación

podium-mcp

Una batuta. Cada instrumento.

Un único endpoint MCP stdio con 51 herramientas para control de dispositivos iOS (simulador + real) y Android, automatización nativa de UI, flujos de extremo a extremo, aserciones confiables, depuración de React Native, inspección de DOM WebView + red, y un cerebro canvas/WebGL sin visión para Pixi/Konva/Fabric/Phaser/Three/Babylon (validado en vivo en WebKit) — además de un puente de motor experimental para builds instrumentadas de Unity/GL (AltTester) — una conexión en lugar de media docena de servidores.

npm Glama mcp.so CI License: MIT

tools 51 tests 378 tokens ~5x cheaper canvas 6 live engines Node ≥22 TypeScript strict MCP stdio PRs welcome


podium-mcp agent session — one prompt opens Safari on a live iOS simulator, types github.com/hoainho, explores the profile and opens a repository

Un prompt → podium conduce Safari en vivo → escribe la URL → explora el perfil → abre un repositorio. Metraje capturado en un simulador de iPhone 16 Pro en vivo.


Un podio es donde se para un maestro: un lugar para dirigir toda la orquesta. Este servidor MCP unifica ocho conjuntos de capacidades detrás de un único endpoint stdio:

  • Gestión de dispositivos y aplicaciones — simuladores de iOS (simctl), iPhones reales (devicectl) y Android (adb) detrás de un modelo de dispositivo etiquetado por plataforma.
  • Inspección nativa de UI y gestos — enrutar a través de idb/mobilecli con un respaldo de Maestro (sin arranque de JVM por gesto).
  • Flujos de extremo a extremo y automatización por lotes — flujos declarativos de Maestro, lotes de acciones ordenadas y un exportador de flujos de ingeniero→QA.
  • Aserciones confiables — una escalera de oráculo (WebView-DOM › a11y nativo › Maestro) que devuelve veredictos falsables y con evidencia, y falla cerrada.
  • WebView DOM + red — resolver el DOM de WKWebView para obtener coordenadas de toque, evaluar JS, conducir la navegación y capturar tráfico HTTP dentro de la página como JSON/HAR.
  • Depuración de React Native — registros de consola de Metro, solicitudes de red y estado dentro de la aplicación a través de CDP, además de informes de fallos del host/simulador.
  • Dispositivos reales — emulador/dispositivo Android vía adb (gestos + jerarquía de uiautomator); iOS real vía ciclo de vida de devicectl + un backend WebDriverAgent opcional.
  • Automatización de canvas y motores de juego, sin visión — un cerebro canvas/WebGL conduce UIs de Pixi/Konva/Fabric/Phaser/Three/Babylon como objetos direccionables (validado en vivo en WebKit). Un puente de motor experimental conduce Unity/GL mediante una build instrumentada con AltTester (o un puente WebGL de window.__podiumEngine) — código completo + probado con mocks, aún no ejecutado contra una build de Unity en vivo.

En lugar de conectar varios servidores MCP en cada configuración de cliente, podium-mcp expone todo detrás de una conexión, con una capa compartida de execFile (sin shell), errores estructurados consistentes, reintento automático alrededor de la inestabilidad del controlador iOS de Maestro, y una única herramienta de verificación de salud para confirmar qué está disponible en el host.

Tabla de contenidos

Por qué

Conducir una aplicación React Native de extremo a extremo generalmente significa manejar varios servidores MCP — uno para control de dispositivo/aplicación, uno para flujos de UI, uno para registros de Metro/depurador, otro para inspección de WebView — cada uno con su propia entrada de configuración, peculiaridades y modos de fallo. podium-mcp colapsa eso en un servidor con:

  • un ejecutor de comandos basado en execFile (sin shell — los argumentos se pasan textualmente),
  • errores estructurados consistentes (una herramienta nunca bloquea el servidor),
  • reintento automático alrededor de la conocida inestabilidad del controlador iOS de Maestro,
  • degradación elegante cuando una cadena de herramientas (p. ej. adb) está ausente,
  • veredictos con evidencia para que un agente sepa cuándo un flujo realmente funcionó.

Puntos de referencia

Podium está construido sobre dos decisiones que lo hacen rápido y económico: conduce las UIs como datos estructurados — nunca capturas de pantalla — y enruta los gestos a través de un backend nativo sin arranque de JVM por acción.

Economía de tokens — sin visión es ~5× más barato

Un agente basado en capturas de pantalla envía una imagen a un modelo de visión en cada paso. Podium devuelve una lista compacta de elementos estructurados en su lugar. En un flujo móvil equivalente de 8 pasos (capturas de 1179×2556 vs listas de ~20 elementos):

EnfoquePor pasoFlujo de 8 pasos
Bucle de captura / visión~2,070 tokens16,557 tokens
Podium — sin visión, estructurado~390 tokens3,117 tokens
Ahorro5.3×−13,440 tokens (−81%)
vision loop  ████████████████████████████████  16,557 tokens
Podium       ██████  3,117 tokens   (5.3× cheaper, −81%)

La brecha se acumula con cada paso — una sesión de 30 pasos consume aproximadamente 62k vs 12k tokens de entrada. Además del costo por paso, el esquema completo de 51 herramientas viaja con cada solicitud (~3,612 tokens, ~71/herramienta); Podium mantiene descripciones de herramientas concisas para que el bloque de herramientas nunca domine la ventana de contexto.

Para UIs de canvas / WebGL la ventaja es estructural, no solo más barata: el Cerebro Canvas direcciona objetos por nombre y texto, donde un agente solo con capturas debe re-analizar píxeles en cada fotograma.

Velocidad — backend de gestos nativo primero

Los gestos se enrutan a través de idb / mobilecli en lugar de arrancar la JVM de Maestro por acción (medido en un simulador de iPhone 16 Pro en vivo):

OperaciónMaestro (JVM por llamada)Podium nativoAceleración
tap_on~14.7 s~0.6 s~24×
inspect_screen~8.9 s~0.9 s~10×

Una conexión, no seis

Todas las 51 herramientas — control de dispositivo y aplicación, automatización de UI, flujos declarativos de Maestro, aserciones con evidencia, captura de DOM WebView + red, depuración de React Native / Metro, y automatización de canvas/WebGL sin visión (además de un puente de motor experimental para Unity/GL instrumentado) — se encuentran detrás de un único endpoint stdio, reemplazando la pila habitual de media docena de servidores MCP separados.

Las cifras de tokens son estimaciones heurísticas (~4 caracteres/token; fórmula de imagen de Anthropic de ~750 px/token) — reproduce con npm run token-bench, o cambia a la API count_tokens de Anthropic para conteos exactos. Las cifras de velocidad se midieron en un simulador de iPhone 16 Pro en vivo (npm run benchmark).

Requisitos

  • macOS con herramientas de línea de comandos de Xcode (xcrun, simctl)
  • Node.js ≥ 22 (usa fetch y WebSocket nativos; .npmrc establece engine-strict=true)
  • mobilecli — incluido automáticamente como dependencia npm; el backend nativo de gestos + WebView por defecto (sin instalación separada)
  • (opcional) idb (idb + idb_companion) — backend de gestos nativo preferido cuando ambos están presentes; auto-detectado
  • (opcional) Maestro en PATH (o en ~/.maestro/bin) — el motor run_flow y la ruta de respaldo de gestos
  • (opcional) un bundler Metro en ejecución para las herramientas de depuración de metro_*
  • (opcional) Android SDK + adb — las rutas de adb son solo detección y degradan elegantemente cuando están ausentes

Alcance de plataforma (v0.3.0): podium automatiza simuladores de iOS, iPhones reales (ciclo de vida de devicectl + WebDriverAgent opcional), y emuladores/dispositivos Android (gestos de adb + jerarquía de uiautomator). device_list etiqueta cada objetivo con su plataforma y el backend se selecciona por objetivo. Cuando una cadena de herramientas (p. ej. adb) está ausente, esas rutas degradan a un resultado informativo en lugar de fallar.

Instalación

Plugin de Claude Code (recomendado)

Sin configuración manual — configuración única del marketplace, luego instalar:

/plugin marketplace add github:hoainho/podium-mcp
/plugin install podium-mcp@podium

El plugin inicia automáticamente el servidor MCP (las 51 herramientas) e incluye cinco habilidades:

HabilidadInvocarQué hace
Información del dispositivo/podium-mcp:device-info <UDID> [<BUNDLE_ID>]Verificación de salud, tamaño de pantalla, orientación, lista de aplicaciones
Flujo E2E/podium-mcp:e2e <UDID> <BUNDLE_ID> [path or description]Ejecutar o crear un flujo de Maestro
Reproducción de errores/podium-mcp:bug-repro <UDID> <BUNDLE_ID> <description>Captura de video + registros + evidencia de fallos
Depuración de RN/podium-mcp:rn-debug [UDID] [logs|apps|crash|all]Registros de Metro, aplicaciones conectadas, informes de fallos
Cerebro Canvas/podium-mcp:canvas <UDID> <intent>Inspeccionar / resolver / tocar UIs canvas-WebGL, sin visión

npx (instalación cero)

{
  "mcpServers": {
    "podium": { "command": "npx", "args": ["-y", "podium-mcp"] }
  }
}

Manual (desde el código fuente)

git clone git@github.com:hoainho/podium-mcp.git
cd podium-mcp
npm install
npm run build

Uso

Registra el servidor compilado con cualquier cliente MCP. Claude Code (.mcp.json):

{
  "mcpServers": {
    "podium": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/podium-mcp/dist/index.js"]
    }
  }
}

Prueba de humo manual rápida sobre stdio crudo (lista las 51 herramientas registradas):

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | node dist/index.js

Siempre llama a podium_health primero para confirmar qué cadena de herramientas está disponible en el host.

Inicio rápido (orden de uso)

  1. podium_health — confirma la disponibilidad de xcrun / maestro / backend nativo.
  2. device_list — elige un simulador iniciado udid.
  3. Leer estado — app_list, app_state, screen_size, orientation_get.
  4. Conducir el dispositivo — app_launch, luego tap_on / input_text / swipe / press_key, además de set_location y orientation_set. Agrupa varios con run_steps.
  5. Crear y verificar — inspect_screen para descubrir elementos, run_flow para comprobaciones declarativas, luego assert_visible / validate_flow para un veredicto con evidencia.
  6. Inspeccionar WebViews — webview_inspect → tocar coordenadas, webview_eval, webview_navigate, webview_network.
  7. Capturar y depurar — screenshot / record_start→record_stop; metro_logs / metro_network / metro_state; crash_list / crash_get.

Las 51 herramientas

Cada herramienta devuelve JSON estructurado y nunca lanza excepciones — los fallos regresan como errores de herramienta MCP. Consulta docs/tool-catalog.md para la referencia autoritativa por parámetro.

Soporte de plataforma (v0.3.0): las herramientas de gesto / inspección / ciclo de vida a continuación se ejecutan en simuladores de iOS, iPhones reales (devicectl + WebDriverAgent opcional vía PODIUM_WDA_URL), y Android (emulador/dispositivo vía adb; jerarquía de uiautomator). device_list etiqueta cada dispositivo con su plataforma y el backend se selecciona por objetivo.

Motor de juego — Unity / GL vía AltTester, sin visión · experimental (4)

HerramientaParámetros claveMotor subyacenteComportamiento
engine_inspectudid, by?, valueAltTester (TCP) / WebGL CDP bridgeLista objetos del motor (por nombre/ruta/componente/texto) con coordenadas absolutas de pantalla — sin capturas de pantalla
engine_tapudid, by?, valueAltTester / CDPResuelve el objeto y toca sus coordenadas de pantalla
engine_swipeudid, fromX/Y, toX/Y, durationMs?AltTester / CDPDesliza dentro de la vista del motor
engine_calludid, by?, value, component, method, parameters?AltTester / CDPInvoca un método de componente C# por reflexión (el análogo del motor a un manejador de eventos DOM)

Estado: experimental. Las formas de cable están probadas unitariamente contra mocks; la ruta de AltTester aún no ha sido validada contra una compilación de Unity en vivo (engine-smoke se omite hasta que se proporcione una compilación instrumentada), y Unity-WebGL necesita que la aplicación exponga window.__podiumEngine. Las herramientas de motor requieren una compilación instrumentada con AltTester (dev/staging) o ese puente WebGL; en una compilación no instrumentada fallan cerradas con un error accionable — nunca un respaldo de visión. Para aplicaciones canvas/WebGL que usan un framework JS, el cerebro canvas a continuación es la ruta validada.

Cerebro canvas — Pixi/Konva/Fabric/Phaser/Three/Babylon, sin visión (3)

HerramientaParámetros claveMotor subyacenteComportamiento
canvas_inspectudid, by?, value?, webviewId?puente de grafo de escena inyectado (eval CDP)Lista objetos canvas con coordenadas CSS-px listas para tocar — sin capturas de pantalla
canvas_resolveudid, intent, webviewId?puente + resolvedor semánticoMapea una intención difusa ("close", "✕") a un objetivo clasificado y evidenciado; falla cerrada confidentEnough
canvas_tapudid, intent, bundleId?, webviewId?resolvedor + toque nativoResuelve y toca la coincidencia confiable en coordenadas absolutas de pantalla (si no, falla cerrada)

Validado en vivo: los seis frameworks pasan una suite Playwright-WebKit (≈ WKWebView) a DPR 1 + 3 (npm run test:canvas, 19 pruebas). Las herramientas canvas requieren un WKWebView inspeccionable que aloje un framework compatible con su raíz accesible (comúnmente en window, o el __PIXI_APP__ de Pixi). Sin framework / sin WebView inspeccionable → falla cerrada con un error accionable — nunca un respaldo de visión.

Diagnósticos (1)

HerramientaParámetros claveMotor subyacenteComportamiento
podium_token_reportsteps?, screenshotWidth?, screenshotHeight?, elementsPerStep?, toolCount?estimadores de tokensTokens de entrada sin visión vs captura de pantalla/bucle de visión, la relación de ahorro y la sobrecarga de definición de herramienta por solicitud

Salud y cadena de herramientas (1)

HerramientaParámetros claveMotor subyacenteComportamiento
podium_health—sondas whichNunca falla; informa toolchain { xcrun, maestro, adb }, backend nativo y platforms: [ios-sim, ios-real, android]

Dispositivo y simulador (6)

HerramientaParámetros claveMotor subyacenteComportamiento
device_list—simctl list -j + adb devicesInventario iOS fusionado; adb ausente → android: { available: false } (solo detección)
device_bootudidsimctl bootIdempotente — ya iniciado → alreadyBooted: true; espera hasta 30 s
screen_sizeudidsimctl io screenshot + sips{ widthPx, heightPx } (píxeles reales)
orientation_getudidconsulta nativa → heurística de captura{ orientation, basis } (exacto cuando es nativo)
set_locationudid, latitude, longitudesimctl location setCodifica la corrección del geo-spinner de QA
open_urludid, urlsimctl openurlEnlaces profundos + https://

Aplicaciones (6)

HerramientaParámetros claveMotor subyacenteComportamiento
app_installudid, path (.app/.zip)simctl installError de herramienta estructurado
app_launchudid, bundleIdsimctl launchTiempo de espera explícito de 30 s (los lanzamientos en frío de RN ya no informan erróneamente fallos)
app_terminateudid, bundleIdsimctl terminateError de herramienta estructurado
app_uninstalludid, bundleIdsimctl uninstallError de herramienta estructurado
app_listudidsimctl listapps + plutil{ count, apps: [{ bundleId, name, type }] }
app_stateudid, bundleIdsimctl listapps + launchctl{ installed, running } — coincidencia exacta de bundle-id

Captura (3)

HerramientaParámetros claveMotor subyacenteComportamiento
screenshotudid, saveTo?simctl io screenshotDevuelve path + byteSize (sin inflado base64)
record_startudid, saveTo? (.mp4)simctl io recordVideo separado{ ok, path, pid }; ruta con marca de tiempo + vigilante de duración (PODIUM_MAX_RECORDING_MS); uno por udid
record_stopudidgrabador SIGINT + vaciado{ ok, path, sizeBytes }

Inspección de UI y gestos (8)

HerramientaParámetros claveMotor subyacenteComportamiento
inspect_screenudid, compact?lista AX plana nativa → maestro hierarchycompact:true (por defecto) devuelve solo nodos significativos
tap_onudid, bundleId, text|id|x+y, double?, long?toque nativo → respaldo Maestrotexto/id resuelto mediante la lista de elementos; informa backend
input_textudid, bundleId, text, submit?nativo → respaldo Maestroinforma backend
swipeudid, bundleId, direction, start/end?nativo → respaldo Maestroanulaciones %/píxel resueltas frente al tamaño lógico de pantalla
press_keyudid, bundleId, keynativo → respaldo Maestroback/power/tab son solo Android
orientation_setudid, bundleId, valuenativo → respaldo MaestroPORTRAIT / LANDSCAPE_LEFT / LANDSCAPE_RIGHT / UPSIDE_DOWN
tap_with_fallbackudid, x, y, maxRetries?, offsetStep?toque nativo + oráculo antes/despuésPara superposiciones WebGL/Canvas; sin caminata ciega (offsetStep opt-in)
notification_bar_clearudid, bundleId?toque nativo + oráculoDescarta la barra de notificación de depuración de RN

Flujos y automatización por lotes (4)

HerramientaParámetros claveMotor subyacenteComportamiento
run_stepsudid, bundleId, steps[]backend nativo (idb/mobilecli)Lote de acciones ordenadas en una llamada; resultados por paso
run_flowudid + exactamente uno de yaml/files/dir(+tags), env?maestro testExactamente-uno-de validado antes de ejecutar; aprobado/fallido por paso
export_flowsteps[], output pathgenerador de flujosExporta un lote run_steps a un flujo Maestro reutilizable (puente ingeniero→QA)
cheat_sheet—assets/maestro-cheat-sheet.yaml incluidoReferencia de sintaxis de Maestro totalmente sin conexión

Aserciones y veredictos — la escalera del oráculo (5)

HerramientaParámetros claveMotor subyacenteComportamiento
assert_visibleudid, text|id, …escalera del oráculo (WebView-DOM › a11y › Maestro)Aprobado/fallido evidenciado; informa qué oráculo lo demostró
assert_textudid, textescalera del oráculoabreviatura por texto para assert_visible
assert_not_visibleudid, text|idescalera del oráculoFalla cerrada — si la ausencia no puede verificarse, falla
wait_for_elementudid, text|id, timeoutMs?escalera del oráculo (sondeo)Consulta hasta que sea visible o se agote el tiempo
validate_flowudid, flow + assertionsescalera del oráculo + ejecución de flujoVeredicto confiable y falsable sobre si un flujo recién construido funciona

DOM de WebView y red (4)

HerramientaParámetros claveMotor subyacenteComportamiento
webview_inspectudid, selector?, webviewId?, max?mobilecli (CDP)Resuelve un selector CSS a elementos DOM con tapX/tapY absolutos
webview_evaludid, expression, webviewId?mobilecli (CDP)Ejecuta JS en el contexto de la página; controlado por PODIUM_DISABLE_WEBVIEW_EVAL=1
webview_navigateudid, action (goto/back/forward/reload), url?mobilecli (CDP)Controla la navegación del WebView
webview_networkudid, durationMs?, format (json/har)?, saveTo?, redact?, includeResources?CDP + shim fetch/XHR en página + Resource TimingCaptura tráfico HTTP dentro del WebView; exporta JSON o HAR 1.2 redactado

Depuración de React Native — Metro CDP (4)

HerramientaParámetros claveMotor subyacenteComportamiento
metro_appsport? (8081)GET http://localhost:<port>/jsonErrores diferenciados (tiempo de espera vs no ejecutándose vs otro)
metro_logswsUrl?/port?, durationMs?, maxLogs?WebSocket + CDP Runtime.enableAuto-descubre la primera aplicación cuando se omite la URL
metro_networkwsUrl?/port?, durationMs?, maxEntries?CDP Network.enableSolicitudes (url/método/estado/mimeType/ts)
metro_stateexpression?/wsUrl?/port?, timeoutMs?CDP Runtime.evaluateLee el estado dentro de la aplicación (por defecto: store Redux expuesto globalmente)

Diagnóstico de fallos (2)

HerramientaParámetros claveMotor subyacenteComportamiento
crash_listprocessName?, sinceHours?, udid?host + sim DiagnosticReportsMás recientes primero; etiquetados source: host | simulator
crash_getid, udid?mismoSeguro contra path traversal (solo nombre base); trunca honestamente

La escalera del oráculo — aserciones confiables

"Funciona" se operacionaliza como un veredicto falsable y evidenciado — nunca "se ve bien". Las aserciones y validate_flow resuelven la visibilidad a través de una escalera de tres peldaños, usando la señal más fuerte disponible:

  1. DOM del WebView — cuando hay un WKWebView inspeccionable presente, consulta el DOM real.
  2. Accesibilidad nativa — el conjunto de elementos AX nativos (vía idb/mobilecli).
  3. Maestro — assertVisible/assertNotVisible como respaldo.

assert_not_visible falla cerrada: si la ausencia no puede verificarse positivamente (p. ej., un WebView ilegible), informa fallo en lugar de un falso aprobado. Cada veredicto nombra el oráculo que lo produjo, para que un agente pueda ponderar su confianza.

Backend de gestos nativo primero

Los gestos imperativos (tap_on, input_text, swipe, press_key, orientation_set, run_steps) y inspect_screen se enrutan a través del backend disponible más rápido, probado una vez y almacenado en caché (con un TTL de caché negativa corto para que un backend que se inicia después del lanzamiento sea detectado):

  1. idb — cuando tanto idb como idb_companion están instalados (nativo, más rápido).
  2. mobilecli — la dependencia npm incluida (binario Go precompilado). Predeterminado; sin instalación.
  3. Respaldo de Maestro — cuando ningún backend nativo resuelve, o para acciones que no puede expresar (doble/presión larga, UPSIDE_DOWN). El gesto genera un flujo mínimo con launchApp: { stopApp: false }, trayendo la aplicación al frente sin reiniciarla para que el estado se conserve.

Cada resultado informa el backend que usó. Establece PODIUM_DISABLE_NATIVE=1 para forzar Maestro. Eliminar el arranque JVM por gesto redujo tap_on ~14.7 s → ~0.6 s y inspect_screen ~8.9 s → ~0.9 s en un simulador de iPhone 16 Pro. Ejecuta npm run benchmark para un barrido completo de aprobado/fallido.

Reintento por inestabilidad de Maestro: cuando se ejecuta el respaldo, su controlador iOS falla intermitentemente con Failed to connect to 127.0.0.1:<port>. Los flujos reintentan hasta 2× con retroceso de 2 s / 5 s e informan el conteo de retries; un fallo persistente devuelve la salida cruda con sugerencias de remediación.

Introspección de red WebView y RN

Dos capas de red distintas, dos herramientas:

  • metro_network captura solicitudes en el objetivo RN/Hermes a través del dominio CDP Network — la herramienta adecuada para el propio fetch de una app RN nativa.
  • webview_network captura tráfico dentro de un WKWebView: inyecta un grabador fetch/XHR (rico — método/estado/cabeceras/cuerpo para llamadas después de que comience la captura) y lee el buffer de Performance Resource Timing del navegador (includeResources, activado por defecto) — cada solicitud desde la navegación, incluidas las anteriores a la captura (URL/timing/tamaño). La fusión produce una lista de solicitudes casi completa, exportada como JSON o HAR 1.2 redactado.

Para un shell RN que aloja su UI en un WebView, las llamadas API de la app se ejecutan en la capa web — así que metro_network no ve nada y webview_network es la herramienta a usar. Las herramientas WebView requieren WKWebView.isInspectable = true (por defecto en compilaciones debug/staging; desactivado en producción); cuando no se encuentra ninguna, devuelven un error accionable.

Límites documentados (por diseño, no errores)

  • Canvas/WebGL necesita un framework JS cooperativo — el cerebro de canvas automatiza UIs de Pixi/Konva/Fabric/Phaser/Three/Babylon mediante selector cuando la app expone su raíz de scene-graph (validado en vivo). Un canvas WebGL crudo/personalizado, un build de producción opaco, o Unity sin un puente AltTester / window.__podiumEngine no es direccionable por selector — recurre a tap_with_fallback con coordenadas derivadas de capturas, o instrumenta el build.
  • Las herramientas WebView son solo para dev/QA — los builds de producción de App Store típicamente establecen isInspectable = false; las herramientas devuelven un error accionable y recurren a toques por coordenadas.
  • La memoria del proceso de contenido WebView es ilegible desde el sandbox de la app (límite de plataforma) — usa señales indirectas (advertencias de memoria, terminaciones de proceso).
  • El matcher text: de Maestro es regex de cadena completa (IGNORE_CASE) — las cadenas parciales no coinciden; copia text de la jerarquía textualmente o ancla con .*.
  • Android requiere adb en PATH — gestos / inspección / capturas funcionan una vez que adb está presente; cuando está ausente, cada ruta de Android degrada a un resultado estructurado "adb not found".
  • orientation_get es una heurística de aspecto de captura cuando no hay backend nativo presente — los simuladores de iOS no exponen una consulta directa de orientación.
  • record_start/record_stop mantienen estado en proceso — serializa start → … → stop en una conexión; una grabación activa por udid (un watchdog finaliza una que nunca se detiene).

Arquitectura

src/
  index.ts          # MCP server entry — registers every tool group, warms caches
  lib/
    exec.ts         # execFile-based runner (NO shell) + timeout/timedOut flag
    result.ts       # shared ok/error MCP content helpers
    simctl.ts       # xcrun simctl wrappers + device-list TTL cache
    native.ts       # gesture/inspect backend: idb → mobilecli → null (re-probe TTL)
    idb.ts          # idb gesture/inspect adapter
    gesture.ts      # unified native→Maestro executors (shared by screen + steps)
    oracle.ts       # the oracle ladder: WebView-DOM › a11y › Maestro
    maestro.ts      # Maestro engine: flow runner, idb retry, hierarchy
    export-maestro.ts # run_steps → reusable Maestro flow
    har.ts          # HAR 1.2 export for webview_network
    webview.ts      # mobilecli CDP — WebView list/inspect/eval/navigate/network
    metro.ts        # Metro CDP — app discovery, logs, network, state
    crash.ts        # DiagnosticReports crash listing/reading
    recording.ts    # detached screen recording lifecycle + watchdog (platform-aware)
    device-target.ts # DeviceTarget model + PlatformDriver registry (v0.3.0)
    drivers/        # per-platform lifecycle: ios-sim, android, ios-real
    adb.ts          # Android adb driver (list/install/launch/screenshot/wm size)
    adb-backend.ts  # adb gesture/inspect (input + uiautomator → AX elements)
    iosreal.ts      # real iOS via devicectl (list/install/launch) + capture
    wda.ts          # opt-in WebDriverAgent backend (/source + tap/swipe/keys)
    engine.ts       # no-vision engine client (AltTester + WebGL-in-WebView)
    engine-transport.ts # WebSocket transport for the AltTester bridge
    canvas-types.ts # Canvas Brain shared contract (CanvasObject, selectors)
    canvas-adapters.ts  # in-page bridge: detect + walk Pixi/Konva/Fabric/Phaser/Three/Babylon
    canvas-resolver.ts  # semantic "close brain": intent → ranked, evidenced target
    canvas-a11y.ts  # Flutter/ARIA fallback reader → CanvasObject (scaffolding, not wired — #9)
    canvas-vision.ts # opt-in vision fallback scaffolding (not wired — #9)
    token-report.ts # token estimators + no-vision vs vision-loop comparison
  tools/            # one file per group:
                    #   health, device, screen, steps, flow, assert, validate,
                    #   webview, debug, engine, canvas, token
assets/             # bundled offline Maestro cheat sheet + demo.gif
scripts/            # benchmark.ts, compare-mcps.ts, token-bench.mjs
e2e/                # smoke suites (smoke / full-smoke / webview-network-live / android-smoke / engine-smoke)
test/canvas-e2e/    # live Playwright-WebKit canvas bridge suite (6 frameworks)
docs/               # tool catalog, e2e transcript, roadmap, token-economics

Desarrollo y pruebas

npm run build       # tsc
npm run typecheck   # tsc --noEmit
npm test            # vitest run — 359 unit/integration tests (exec/network mocked, no sim needed)
npm run test:canvas # live canvas bridge suite in Playwright WebKit — 19 tests (run `npx playwright install webkit` first)
npm run benchmark   # spawn a fresh server over stdio and sweep the tool suite
node e2e/smoke.e2e.mjs        # real E2E against a booted simulator (macOS + Xcode)
node e2e/full-smoke.e2e.mjs   # drives the iOS-sim tool handlers (happy + structured-error paths)
node e2e/android-smoke.e2e.mjs # Android emulator/device smoke (story A3)
node e2e/engine-smoke.e2e.mjs  # AltTester engine smoke; skips without an instrumented build (story C4)

359 pruebas unitarias/de integración en 31 archivos, más 19 pruebas en vivo de canvas-bridge (378 en total), todas pasando — incluyendo el registro de destino de dispositivos v0.3.0, el driver Android adb + el parser uiautomator, el cliente del motor AltTester + el puente WebGL, los parsers reales de iOS devicectl/WDA, más la escalera de oráculo v0.2.0, el watchdog de grabación, paridad de gestos, exportación HAR, WebView y rutas Metro.

Estándares: TypeScript estricto, sin as any / @ts-ignore, sin ejecución de shell (todos los comandos vía lib/exec.ts), las herramientas devuelven errores estructurados en lugar de lanzar excepciones. Consulta CONTRIBUTING.md para la lista de verificación "añadir una nueva herramienta".

E2E en CI: el workflow E2E (simulator) arranca un simulador iOS real en un runner macOS y ejecuta las suites de humo nocturnas y bajo demanda (no es una puerta de PR — las ejecuciones de simulador son lentas). full-smoke.e2e.mjs verifica la ruta feliz donde existe un destino y la ruta real de error estructurado donde falta una dependencia (una app de depuración isInspectable para WebView; una app RN conectada para metro_*).

Hoja de ruta y contribuciones

podium-mcp está listo para producción en automatización de UI iOS/Android y canvas/WebGL sin visión (Pixi/Konva/Fabric/Phaser/Three/Babylon — validado en vivo). La frontera, donde un contribuidor puede marcar una diferencia real, vive en los issues abiertos:

Alto impacto — help wanted

  • #1 — validar la ruta del motor AltTester/Unity contra un build de Unity instrumentado en vivo (la mayor brecha hacia la automatización real de Unity).
  • #2 — e2e WKWebView en dispositivo real para el cerebro de canvas (hoy validado en Playwright WebKit).
  • #3 — adaptador Unity-WebGL: auto-detección y un puente window.__podiumEngine listo para usar.

Buenos primeros issues — good first issue

  • #4 — más adaptadores de canvas (PlayCanvas, Cocos Creator, p5.js).
  • #5 — exponer herramientas canvas_hittest / canvas_object_rect.
  • #7 — conteos exactos de tokens vía la API Anthropic count_tokens.
  • #6 — abordar objetivos Konva Group/Container.

Añadir una herramienta sigue una lista de verificación en CONTRIBUTING.md: TypeScript estricto, sin shell, errores estructurados-nunca-lanzar, una prueba vitest y una fila en el catálogo de herramientas. PRs bienvenidos.

Publicación

server.json es el manifiesto oficial del Registro MCP. Empujar una etiqueta v* ejecuta Publish to npm y luego Publish to MCP Registry (GitHub OIDC para el namespace io.github.hoainho/* — sin token de larga duración). Ambos workflows ejecutan typecheck → build → test como puerta primero; la publicación del registro solo tiene éxito una vez que la versión npm correspondiente está en vivo, y las versiones son inmutables.

Libro de jugadas de prompts y referencias

  • prompts/ — prompts de copiar y pegar para flujos e2e, casos de prueba, verificación de características, corrección de errores y control de dispositivos. Cada uno nombra las herramientas podium que impulsa y fue validado en un simulador real. Comienza con prompts/README.md.
  • docs/tool-catalog.md — referencia autoritativa herramienta por herramienta.
  • docs/e2e-demo.md — una transcripción real contra un simulador iPhone 16 Pro arrancado ejecutando una app RN de producción.

Ideas de diseño

  • Un podium, una conexión. Un solo servidor cubre cada capacidad móvil para que un agente configure un endpoint y descubra las 51 herramientas a la vez.
  • Seguro por construcción. Cada comando externo pasa por una capa execFile con un array de argumentos explícito — nunca una cadena de shell.
  • Nunca derribes al conductor. Las herramientas devuelven resultados y errores estructurados en lugar de lanzar; una mala llamada no puede tumbar el servidor.
  • Degrada, no falles. Una cadena de herramientas ausente (p. ej. adb de Android) produce un resultado informativo en lugar de un error duro.
  • Pruébalo, no adivines. Las aserciones devuelven veredictos con evidencia vía la escalera de oráculo y fallan cerradas cuando no pueden verificar.

Contribuciones

Contribuciones bienvenidas — consulta CONTRIBUTING.md y el Código de Conducta. Usa las plantillas de issues para errores y solicitudes de características.

Seguridad

Por favor reporta vulnerabilidades de forma privada según SECURITY.md — no abras un issue público. SECURITY.md también documenta el límite de confianza webview_eval / run_flow y la advertencia de PII en transcripciones.

Licencia

MIT © 2026 hoainho