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.
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/mobileclicon 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
WKWebViewpara 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 deuiautomator); iOS real vía ciclo de vida dedevicectl+ 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é
- Puntos de referencia
- Requisitos
- Instalación
- Uso
- Inicio rápido
- Las 51 herramientas
- La escalera de oráculo — aserciones confiables
- Backend de gestos nativo primero
- Introspección de red WebView y RN
- Límites documentados
- Arquitectura
- Desarrollo y pruebas
- Hoja de ruta y contribuciones
- Publicación
- Manual de prompts y referencias
- Ideas de diseño
- Contribuciones · Seguridad · Licencia
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):
| Enfoque | Por paso | Flujo de 8 pasos |
|---|---|---|
| Bucle de captura / visión | ~2,070 tokens | 16,557 tokens |
| Podium — sin visión, estructurado | ~390 tokens | 3,117 tokens |
| Ahorro | 5.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ón | Maestro (JVM por llamada) | Podium nativo | Aceleració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 APIcount_tokensde 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
fetchyWebSocketnativos;.npmrcestableceengine-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 motorrun_flowy 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 deadb+ jerarquía deuiautomator).device_listetiqueta 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:
| Habilidad | Invocar | Qué 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)
podium_health— confirma la disponibilidad dexcrun/maestro/ backend nativo.device_list— elige un simulador iniciadoudid.- Leer estado —
app_list,app_state,screen_size,orientation_get. - Conducir el dispositivo —
app_launch, luegotap_on/input_text/swipe/press_key, además deset_locationyorientation_set. Agrupa varios conrun_steps. - Crear y verificar —
inspect_screenpara descubrir elementos,run_flowpara comprobaciones declarativas, luegoassert_visible/validate_flowpara un veredicto con evidencia. - Inspeccionar WebViews —
webview_inspect→ tocar coordenadas,webview_eval,webview_navigate,webview_network. - 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.mdpara 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íaPODIUM_WDA_URL), y Android (emulador/dispositivo víaadb; jerarquía deuiautomator).device_listetiqueta 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)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
engine_inspect | udid, by?, value | AltTester (TCP) / WebGL CDP bridge | Lista objetos del motor (por nombre/ruta/componente/texto) con coordenadas absolutas de pantalla — sin capturas de pantalla |
engine_tap | udid, by?, value | AltTester / CDP | Resuelve el objeto y toca sus coordenadas de pantalla |
engine_swipe | udid, fromX/Y, toX/Y, durationMs? | AltTester / CDP | Desliza dentro de la vista del motor |
engine_call | udid, by?, value, component, method, parameters? | AltTester / CDP | Invoca 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-smokese omite hasta que se proporcione una compilación instrumentada), y Unity-WebGL necesita que la aplicación expongawindow.__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)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
canvas_inspect | udid, 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_resolve | udid, intent, webviewId? | puente + resolvedor semántico | Mapea una intención difusa ("close", "✕") a un objetivo clasificado y evidenciado; falla cerrada confidentEnough |
canvas_tap | udid, intent, bundleId?, webviewId? | resolvedor + toque nativo | Resuelve 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 enwindow, 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)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
podium_token_report | steps?, screenshotWidth?, screenshotHeight?, elementsPerStep?, toolCount? | estimadores de tokens | Tokens 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)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
podium_health | — | sondas which | Nunca falla; informa toolchain { xcrun, maestro, adb }, backend nativo y platforms: [ios-sim, ios-real, android] |
Dispositivo y simulador (6)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
device_list | — | simctl list -j + adb devices | Inventario iOS fusionado; adb ausente → android: { available: false } (solo detección) |
device_boot | udid | simctl boot | Idempotente — ya iniciado → alreadyBooted: true; espera hasta 30 s |
screen_size | udid | simctl io screenshot + sips | { widthPx, heightPx } (píxeles reales) |
orientation_get | udid | consulta nativa → heurística de captura | { orientation, basis } (exacto cuando es nativo) |
set_location | udid, latitude, longitude | simctl location set | Codifica la corrección del geo-spinner de QA |
open_url | udid, url | simctl openurl | Enlaces profundos + https:// |
Aplicaciones (6)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
app_install | udid, path (.app/.zip) | simctl install | Error de herramienta estructurado |
app_launch | udid, bundleId | simctl launch | Tiempo de espera explícito de 30 s (los lanzamientos en frío de RN ya no informan erróneamente fallos) |
app_terminate | udid, bundleId | simctl terminate | Error de herramienta estructurado |
app_uninstall | udid, bundleId | simctl uninstall | Error de herramienta estructurado |
app_list | udid | simctl listapps + plutil | { count, apps: [{ bundleId, name, type }] } |
app_state | udid, bundleId | simctl listapps + launchctl | { installed, running } — coincidencia exacta de bundle-id |
Captura (3)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
screenshot | udid, saveTo? | simctl io screenshot | Devuelve path + byteSize (sin inflado base64) |
record_start | udid, 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_stop | udid | grabador SIGINT + vaciado | { ok, path, sizeBytes } |
Inspección de UI y gestos (8)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
inspect_screen | udid, compact? | lista AX plana nativa → maestro hierarchy | compact:true (por defecto) devuelve solo nodos significativos |
tap_on | udid, bundleId, text|id|x+y, double?, long? | toque nativo → respaldo Maestro | texto/id resuelto mediante la lista de elementos; informa backend |
input_text | udid, bundleId, text, submit? | nativo → respaldo Maestro | informa backend |
swipe | udid, bundleId, direction, start/end? | nativo → respaldo Maestro | anulaciones %/píxel resueltas frente al tamaño lógico de pantalla |
press_key | udid, bundleId, key | nativo → respaldo Maestro | back/power/tab son solo Android |
orientation_set | udid, bundleId, value | nativo → respaldo Maestro | PORTRAIT / LANDSCAPE_LEFT / LANDSCAPE_RIGHT / UPSIDE_DOWN |
tap_with_fallback | udid, x, y, maxRetries?, offsetStep? | toque nativo + oráculo antes/después | Para superposiciones WebGL/Canvas; sin caminata ciega (offsetStep opt-in) |
notification_bar_clear | udid, bundleId? | toque nativo + oráculo | Descarta la barra de notificación de depuración de RN |
Flujos y automatización por lotes (4)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
run_steps | udid, bundleId, steps[] | backend nativo (idb/mobilecli) | Lote de acciones ordenadas en una llamada; resultados por paso |
run_flow | udid + exactamente uno de yaml/files/dir(+tags), env? | maestro test | Exactamente-uno-de validado antes de ejecutar; aprobado/fallido por paso |
export_flow | steps[], output path | generador de flujos | Exporta un lote run_steps a un flujo Maestro reutilizable (puente ingeniero→QA) |
cheat_sheet | — | assets/maestro-cheat-sheet.yaml incluido | Referencia de sintaxis de Maestro totalmente sin conexión |
Aserciones y veredictos — la escalera del oráculo (5)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
assert_visible | udid, text|id, … | escalera del oráculo (WebView-DOM › a11y › Maestro) | Aprobado/fallido evidenciado; informa qué oráculo lo demostró |
assert_text | udid, text | escalera del oráculo | abreviatura por texto para assert_visible |
assert_not_visible | udid, text|id | escalera del oráculo | Falla cerrada — si la ausencia no puede verificarse, falla |
wait_for_element | udid, text|id, timeoutMs? | escalera del oráculo (sondeo) | Consulta hasta que sea visible o se agote el tiempo |
validate_flow | udid, flow + assertions | escalera del oráculo + ejecución de flujo | Veredicto confiable y falsable sobre si un flujo recién construido funciona |
DOM de WebView y red (4)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
webview_inspect | udid, selector?, webviewId?, max? | mobilecli (CDP) | Resuelve un selector CSS a elementos DOM con tapX/tapY absolutos |
webview_eval | udid, expression, webviewId? | mobilecli (CDP) | Ejecuta JS en el contexto de la página; controlado por PODIUM_DISABLE_WEBVIEW_EVAL=1 |
webview_navigate | udid, action (goto/back/forward/reload), url? | mobilecli (CDP) | Controla la navegación del WebView |
webview_network | udid, durationMs?, format (json/har)?, saveTo?, redact?, includeResources? | CDP + shim fetch/XHR en página + Resource Timing | Captura tráfico HTTP dentro del WebView; exporta JSON o HAR 1.2 redactado |
Depuración de React Native — Metro CDP (4)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
metro_apps | port? (8081) | GET http://localhost:<port>/json | Errores diferenciados (tiempo de espera vs no ejecutándose vs otro) |
metro_logs | wsUrl?/port?, durationMs?, maxLogs? | WebSocket + CDP Runtime.enable | Auto-descubre la primera aplicación cuando se omite la URL |
metro_network | wsUrl?/port?, durationMs?, maxEntries? | CDP Network.enable | Solicitudes (url/método/estado/mimeType/ts) |
metro_state | expression?/wsUrl?/port?, timeoutMs? | CDP Runtime.evaluate | Lee el estado dentro de la aplicación (por defecto: store Redux expuesto globalmente) |
Diagnóstico de fallos (2)
| Herramienta | Parámetros clave | Motor subyacente | Comportamiento |
|---|---|---|---|
crash_list | processName?, sinceHours?, udid? | host + sim DiagnosticReports | Más recientes primero; etiquetados source: host | simulator |
crash_get | id, udid? | mismo | Seguro 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:
- DOM del WebView — cuando hay un
WKWebViewinspeccionable presente, consulta el DOM real. - Accesibilidad nativa — el conjunto de elementos AX nativos (vía
idb/mobilecli). - Maestro —
assertVisible/assertNotVisiblecomo 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):
idb— cuando tantoidbcomoidb_companionestán instalados (nativo, más rápido).mobilecli— la dependencia npm incluida (binario Go precompilado). Predeterminado; sin instalación.- 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 conlaunchApp: { 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_networkcaptura solicitudes en el objetivo RN/Hermes a través del dominio CDP Network — la herramienta adecuada para el propiofetchde una app RN nativa.webview_networkcaptura tráfico dentro de unWKWebView: inyecta un grabadorfetch/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.__podiumEngineno es direccionable por selector — recurre atap_with_fallbackcon 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; copiatextde la jerarquía textualmente o ancla con.*. - Android requiere
adbenPATH— gestos / inspección / capturas funcionan una vez queadbestá presente; cuando está ausente, cada ruta de Android degrada a un resultado estructurado "adb not found". orientation_getes 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_stopmantienen estado en proceso — serializastart→ … →stopen 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.__podiumEnginelisto 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 conprompts/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
execFilecon 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.
adbde 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