podium-mcp
MCP E2E móvel unificado — 28 ferramentas (mobile-mcp + Maestro + paridade com RN-debugger)
Documentação
podium-mcp
Um bastão. Todos os instrumentos.
Um único endpoint MCP stdio com 51 ferramentas para controle de dispositivos iOS (simulador + físico) e Android, automação de UI nativa, fluxos de ponta a ponta, asserções confiáveis, depuração de React Native, inspeção de DOM + rede em WebView e um cérebro canvas/WebGL sem visão para Pixi/Konva/Fabric/Phaser/Three/Babylon (validado ao vivo no WebKit) — além de uma ponte de engine experimental para builds Unity/GL instrumentadas (AltTester) — uma conexão em vez de meia dúzia de servidores.
Um prompt → podium dirige o Safari ao vivo → digita a URL → explora o perfil → abre um repositório. Gravação capturada em um simulador de iPhone 16 Pro ao vivo.
Um pódio é onde o maestro se posiciona — um lugar para conduzir toda a orquestra. Este servidor MCP unifica oito conjuntos de capacidades atrás de um único endpoint stdio:
- Gerenciamento de dispositivos e apps — simuladores iOS (
simctl), iPhones físicos (devicectl) e Android (adb) atrás de um modelo de dispositivo unificado com tag de plataforma. - Inspeção e gestos de UI nativa — rota via
idb/mobileclicom fallback para Maestro (sem inicialização de JVM por gesto). - Fluxos de ponta a ponta e automação em lote — fluxos Maestro declarativos, lotes de ações ordenadas e um exportador de fluxo engenheiro→QA.
- Asserções confiáveis — uma escada de oráculos (WebView-DOM › a11y nativo › Maestro) que retorna veredictos falseáveis e baseados em evidências, e falha de forma segura.
- DOM + rede em WebView — resolve o DOM do
WKWebViewpara coordenadas de toque, avalia JS, conduz navegação e captura tráfego HTTP na página como JSON/HAR. - Depuração de React Native — logs de console do Metro, requisições de rede e estado do app via CDP, além de relatórios de crash do host/simulador.
- Dispositivos físicos — emulador/dispositivo Android via
adb(gestos + hierarquiauiautomator); iOS físico via ciclo de vidadevicectl+ backend WebDriverAgent opcional. - Automação de canvas e game engine, sem visão — um cérebro canvas/WebGL conduz UIs Pixi/Konva/Fabric/Phaser/Three/Babylon como objetos endereçáveis (validado ao vivo no WebKit). Uma ponte de engine experimental conduz Unity/GL via build instrumentado com AltTester (ou uma ponte WebGL
window.__podiumEngine) — código completo + testado com mocks, ainda não executado contra um build Unity ao vivo.
Em vez de conectar vários servidores MCP em cada configuração de cliente, podium-mcp expõe tudo atrás de uma conexão, com uma camada execFile compartilhada (sem shell), erros estruturados consistentes, nova tentativa automática em torno da instabilidade do driver iOS do Maestro e uma única ferramenta de verificação de saúde para confirmar o que está disponível no host.
Sumário
- Por quê
- Benchmarks
- Requisitos
- Instalação
- Uso
- Início rápido
- As 51 ferramentas
- A escada de oráculos — asserções confiáveis
- Backend de gestos nativo-first
- Introspecção de rede WebView e RN
- Limitações documentadas
- Arquitetura
- Desenvolvimento e testes
- Roadmap e contribuições
- Lançamentos
- Playbook de prompts e referências
- Ideias de design
- Contribuindo · Segurança · Licença
Por quê
Conduzir um app React Native de ponta a ponta geralmente significa gerenciar vários servidores MCP — um para controle de dispositivo/app, um para fluxos de UI, um para logs do Metro/debugger, outro para inspeção de WebView — cada um com sua própria entrada de configuração, peculiaridades e modos de falha. podium-mcp colapsa tudo isso em um servidor com:
- um único executor de comandos baseado em
execFile(sem shell — argumentos são passados verbatim), - erros estruturados consistentes (uma ferramenta nunca derruba o servidor),
- nova tentativa automática em torno da instabilidade conhecida do driver iOS do Maestro,
- degradação graciosa quando uma toolchain (ex.:
adb) está ausente, - veredictos baseados em evidências para que um agente saiba quando um fluxo realmente funcionou.
Benchmarks
Podium é construído sobre duas escolhas que o tornam rápido e barato: ele conduz UIs como dados estruturados — nunca screenshots — e roteia gestos por um backend nativo sem inicialização de JVM por ação.
Economia de tokens — sem visão é ~5× mais barato
Um agente baseado em screenshots envia uma imagem a um modelo de visão em cada passo. Podium retorna uma lista estruturada compacta de elementos. Em um fluxo móvel equivalente de 8 passos (screenshots 1179×2556 vs listas de ~20 elementos):
| Abordagem | Por passo | Fluxo de 8 passos |
|---|---|---|
| Loop de screenshot / visão | ~2.070 tokens | 16.557 tokens |
| Podium — sem visão, estruturado | ~390 tokens | 3.117 tokens |
| Economia | 5,3× | −13.440 tokens (−81%) |
vision loop ████████████████████████████████ 16,557 tokens
Podium ██████ 3,117 tokens (5.3× cheaper, −81%)
A lacuna se acumula a cada passo — uma sessão de 30 passos roda aproximadamente 62k vs 12k tokens de entrada. Além do custo por passo, o schema completo das 51 ferramentas viaja com cada requisição (~3.612 tokens, ~71/ferramenta); Podium mantém descrições de ferramentas enxutas para que o bloco de ferramentas nunca domine a janela de contexto.
Para UIs canvas / WebGL, a vantagem é estrutural, não apenas mais barata: o Cérebro Canvas endereça objetos por nome e texto, onde um agente baseado apenas em screenshots precisa re-analisar pixels a cada frame.
Velocidade — backend de gestos nativo-first
Gestos roteiam via idb / mobilecli em vez de inicializar a JVM do Maestro
por ação (medido em um simulador de iPhone 16 Pro ao vivo):
| Operação | Maestro (JVM por chamada) | Podium nativo | Aceleração |
|---|---|---|---|
tap_on | ~14,7 s | ~0,6 s | ~24× |
inspect_screen | ~8,9 s | ~0,9 s | ~10× |
Uma conexão, não seis
Todas as 51 ferramentas — controle de dispositivo e app, automação de UI, fluxos Maestro declarativos, asserções baseadas em evidências, DOM WebView + captura de rede, depuração React Native / Metro e automação canvas/WebGL sem visão (além de uma ponte de engine experimental para Unity/GL instrumentado) — ficam atrás de um único endpoint stdio, substituindo a pilha usual de meia dúzia de servidores MCP separados.
Os números de tokens são estimativas heurísticas (~4 caracteres/token; fórmula de imagem ~750 px/token da Anthropic) — reproduza com
npm run token-bench, ou troque pela APIcount_tokensda Anthropic para contagens exatas. Os números de velocidade foram medidos em um simulador de iPhone 16 Pro ao vivo (npm run benchmark).
Requisitos
- macOS com ferramentas de linha de comando do Xcode (
xcrun,simctl) - Node.js ≥ 22 (usa
fetcheWebSocketnativos;.npmrcdefineengine-strict=true) mobilecli— empacotado automaticamente como dependência npm; o backend nativo padrão de gestos + WebView (sem instalação separada)- (opcional)
idb(idb+idb_companion) — backend nativo de gestos preferido quando ambos estão presentes; auto-detectado - (opcional) Maestro em
PATH(ou em~/.maestro/bin) — o enginerun_flowe o caminho de fallback de gestos - (opcional) um bundler Metro em execução para as ferramentas de depuração
metro_* - (opcional) Android SDK +
adb— caminhos adb são somente detecção e degradam graciosamente quando ausentes
Escopo de plataforma (v0.3.0): podium automatiza simuladores iOS, iPhones físicos (ciclo de vida
devicectl+ WebDriverAgent opcional) e Android emuladores/dispositivos (gestosadb+ hierarquiauiautomator).device_listmarca cada alvo com sua plataforma e o backend é selecionado por alvo. Quando uma toolchain (ex.:adb) está ausente, esses caminhos degradam para um resultado informativo em vez de falhar.
Instalação
Plugin Claude Code (recomendado)
Sem configuração manual — configuração única no marketplace, depois instale:
/plugin marketplace add github:hoainho/podium-mcp
/plugin install podium-mcp@podium
O plugin inicia automaticamente o servidor MCP (todas as 51 ferramentas) e inclui cinco skills:
| Skill | Invocar | O que faz |
|---|---|---|
| Informações do dispositivo | /podium-mcp:device-info <UDID> [<BUNDLE_ID>] | Verificação de saúde, tamanho da tela, orientação, lista de apps |
| Fluxo E2E | /podium-mcp:e2e <UDID> <BUNDLE_ID> [path or description] | Executar ou criar um fluxo Maestro |
| Reprodução de bug | /podium-mcp:bug-repro <UDID> <BUNDLE_ID> <description> | Captura de vídeo + logs + evidências de crash |
| Depuração RN | /podium-mcp:rn-debug [UDID] [logs|apps|crash|all] | Logs do Metro, apps conectados, relatórios de crash |
| Cérebro Canvas | /podium-mcp:canvas <UDID> <intent> | Inspecionar / resolver / tocar UIs canvas-WebGL, sem visão |
npx (instalação zero)
{
"mcpServers": {
"podium": { "command": "npx", "args": ["-y", "podium-mcp"] }
}
}
Manual (a partir do código-fonte)
git clone git@github.com:hoainho/podium-mcp.git
cd podium-mcp
npm install
npm run build
Uso
Registre o servidor compilado com qualquer cliente MCP. Claude Code (.mcp.json):
{
"mcpServers": {
"podium": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/podium-mcp/dist/index.js"]
}
}
}
Teste rápido manual via stdio bruto (lista as 51 ferramentas 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
Sempre chame podium_health primeiro para confirmar qual toolchain está disponível no host.
Início rápido (ordem de uso)
podium_health— confirme a disponibilidade dexcrun/maestro/ backend nativo.device_list— escolha um simulador iniciadoudid.- Leia o estado —
app_list,app_state,screen_size,orientation_get. - Conduza o dispositivo —
app_launch, depoistap_on/input_text/swipe/press_key, além deset_locationeorientation_set. Agrupe vários comrun_steps. - Crie e verifique —
inspect_screenpara descobrir elementos,run_flowpara verificações declarativas, depoisassert_visible/validate_flowpara um veredicto baseado em evidências. - Inspecione WebViews —
webview_inspect→ toque em coordenadas,webview_eval,webview_navigate,webview_network. - Capture e depure —
screenshot/record_start→record_stop;metro_logs/metro_network/metro_state;crash_list/crash_get.
As 51 ferramentas
Toda ferramenta retorna JSON estruturado e nunca lança exceções — falhas retornam como erros de ferramenta MCP. Veja
docs/tool-catalog.mdpara a referência autoritativa por parâmetro.Suporte de plataforma (v0.3.0): as ferramentas de gesto / inspeção / ciclo de vida abaixo rodam em simuladores iOS, iPhones físicos (
devicectl+ WebDriverAgent opcional viaPODIUM_WDA_URL) e Android (emulador/dispositivo viaadb; hierarquia deuiautomator).device_listmarca cada dispositivo com sua plataforma e o backend é selecionado por alvo.
Game engine — Unity / GL via AltTester, sem visão · experimental (4)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
engine_inspect | udid, by?, value | AltTester (TCP) / ponte WebGL CDP | Lista objetos do engine (por nome/caminho/componente/texto) com coordenadas absolutas de tela — sem screenshots |
engine_tap | udid, by?, value | AltTester / CDP | Resolve o objeto e toca em suas coordenadas de tela |
engine_swipe | udid, fromX/Y, toX/Y, durationMs? | AltTester / CDP | Desliza dentro da visualização do engine |
engine_call | udid, by?, value, component, method, parameters? | AltTester / CDP | Invoca um método de componente C# por reflexão (o análogo de engine de um manipulador de eventos DOM) |
Status: experimental. Os formatos de wire são testados por unidade contra mocks; o caminho AltTester ainda não foi validado contra um build Unity ao vivo (
engine-smokepula até que um build instrumentado seja fornecido), e Unity-WebGL precisa que o app exponhawindow.__podiumEngine. As ferramentas de engine exigem um build instrumentado com AltTester (dev/staging) ou essa ponte WebGL; em um build não instrumentado, elas falham de forma fechada com um erro acionável — nunca um fallback de visão. Para apps canvas/WebGL que usam um framework JS, o cérebro de canvas abaixo é o caminho validado.
Cérebro de canvas — Pixi/Konva/Fabric/Phaser/Three/Babylon, sem visão (3)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
canvas_inspect | udid, by?, value?, webviewId? | ponte de grafo de cena injetada (avaliação CDP) | Lista objetos de canvas com coordenadas CSS-px prontas para toque — sem capturas de tela |
canvas_resolve | udid, intent, webviewId? | ponte + resolvedor semântico | Mapeia uma intenção difusa ("fechar", "✕") para um alvo classificado e com evidências; falha fechada confidentEnough |
canvas_tap | udid, intent, bundleId?, webviewId? | resolvedor + toque nativo | Resolve e toca na correspondência confiante em coordenadas absolutas de tela (caso contrário, falha fechada) |
Validado ao vivo: todos os seis frameworks passam em uma suíte Playwright-WebKit (≈ WKWebView) em DPR 1 + 3 (
npm run test:canvas, 19 testes). As ferramentas de canvas exigem um WKWebView inspecionável hospedando um framework suportado com sua raiz acessível (comumente emwindow, ou o__PIXI_APP__do Pixi). Sem framework / sem WebView inspecionável → falha fechada com um erro acionável — nunca um fallback de visão.
Diagnóstico (1)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
podium_token_report | steps?, screenshotWidth?, screenshotHeight?, elementsPerStep?, toolCount? | estimadores de token | Tokens de entrada sem visão vs. com captura de tela/loop de visão, a taxa de economia e a sobrecarga de definição de ferramenta por solicitação |
Saúde e toolchain (1)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
podium_health | — | sondas which | Nunca falha; relata toolchain { xcrun, maestro, adb }, backend nativo e platforms: [ios-sim, ios-real, android] |
Dispositivo e simulador (6)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
device_list | — | simctl list -j + adb devices | Inventário iOS mesclado; adb ausente → android: { available: false } (somente detecção) |
device_boot | udid | simctl boot | Idempotente — já iniciado → alreadyBooted: true; aguarda até 30 s |
screen_size | udid | simctl io screenshot + sips | { widthPx, heightPx } (pixels reais) |
orientation_get | udid | consulta nativa → heurística de captura de tela | { orientation, basis } (exato quando nativo) |
set_location | udid, latitude, longitude | simctl location set | Codifica a correção do spinner de geo da QA |
open_url | udid, url | simctl openurl | Deep links + https:// |
Apps (6)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
app_install | udid, path (.app/.zip) | simctl install | Erro de ferramenta estruturado |
app_launch | udid, bundleId | simctl launch | Timeout explícito de 30 s (inicializações RN a frio não relatam mais falha incorretamente) |
app_terminate | udid, bundleId | simctl terminate | Erro de ferramenta estruturado |
app_uninstall | udid, bundleId | simctl uninstall | Erro de ferramenta estruturado |
app_list | udid | simctl listapps + plutil | { count, apps: [{ bundleId, name, type }] } |
app_state | udid, bundleId | simctl listapps + launchctl | { installed, running } — correspondência exata de bundle-id |
Captura (3)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
screenshot | udid, saveTo? | simctl io screenshot | Retorna path + byteSize (sem inchaço de base64) |
record_start | udid, saveTo? (.mp4) | simctl io recordVideo destacado | { ok, path, pid }; caminho com timestamp + watchdog de duração (PODIUM_MAX_RECORDING_MS); um por udid |
record_stop | udid | gravador SIGINT + flush | { ok, path, sizeBytes } |
Inspeção de UI e gestos (8)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
inspect_screen | udid, compact? | lista AX nativa plana → maestro hierarchy | compact:true (padrão) retorna apenas nós significativos |
tap_on | udid, bundleId, text|id|x+y, double?, long? | toque nativo → fallback Maestro | text/id resolvidos via a lista de elementos; relata backend |
input_text | udid, bundleId, text, submit? | nativo → fallback Maestro | relata backend |
swipe | udid, bundleId, direction, start/end? | nativo → fallback Maestro | Overrides de %/pixel resolvidos vs. tamanho lógico da tela |
press_key | udid, bundleId, key | nativo → fallback Maestro | back/power/tab são somente Android |
orientation_set | udid, bundleId, value | nativo → fallback Maestro | PORTRAIT / LANDSCAPE_LEFT / LANDSCAPE_RIGHT / UPSIDE_DOWN |
tap_with_fallback | udid, x, y, maxRetries?, offsetStep? | toque nativo + oráculo antes/depois | Para overlays WebGL/Canvas; sem caminhada cega (offsetStep opt-in) |
notification_bar_clear | udid, bundleId? | toque nativo + oráculo | Dispensa a barra de notificação de debug do RN |
Fluxos e automação em lote (4)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
run_steps | udid, bundleId, steps[] | backend nativo (idb/mobilecli) | Lote de ações ordenado em uma chamada; resultados por etapa |
run_flow | udid + exatamente um de yaml/files/dir(+tags), env? | maestro test | Exatamente-um-de validado antes da execução; pass/fail por etapa |
export_flow | steps[], caminho de saída | gerador de fluxo | Exporta um lote run_steps para um fluxo Maestro reutilizável (ponte engenheiro→QA) |
cheat_sheet | — | assets/maestro-cheat-sheet.yaml incluído | Referência de sintaxe Maestro totalmente offline |
Asserções e veredictos — a escada do oráculo (5)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
assert_visible | udid, text|id, … | escada do oráculo (WebView-DOM › a11y › Maestro) | Pass/fail com evidências; relata qual oráculo provou |
assert_text | udid, text | escada do oráculo | Atalho por texto para assert_visible |
assert_not_visible | udid, text|id | escada do oráculo | Falha fechada — se a ausência não puder ser verificada, falha |
wait_for_element | udid, text|id, timeoutMs? | escada do oráculo (polling) | Faz polling até ficar visível ou expirar o tempo |
validate_flow | udid, fluxo + asserções | escada do oráculo + execução de fluxo | Veredicto confiável e falseável sobre se um fluxo recém-construído funciona |
DOM do WebView e rede (4)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
webview_inspect | udid, selector?, webviewId?, max? | mobilecli (CDP) | Resolve um seletor CSS para elementos DOM com tapX/tapY absolutos |
webview_eval | udid, expression, webviewId? | mobilecli (CDP) | Executa JS no contexto da página; controlado por PODIUM_DISABLE_WEBVIEW_EVAL=1 |
webview_navigate | udid, action (goto/back/forward/reload), url? | mobilecli (CDP) | Conduz a navegação do WebView |
webview_network | udid, durationMs?, format (json/har)?, saveTo?, redact?, includeResources? | CDP + shim de fetch/XHR na página + Resource Timing | Captura tráfego HTTP dentro do WebView; exporta JSON ou HAR 1.2 com redação |
Debug de React Native — Metro CDP (4)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
metro_apps | port? (8081) | GET http://localhost:<port>/json | Erros diferenciados (timeout vs. não em execução vs. outro) |
metro_logs | wsUrl?/port?, durationMs?, maxLogs? | WebSocket + CDP Runtime.enable | Descobre automaticamente o primeiro app quando a URL é omitida |
metro_network | wsUrl?/port?, durationMs?, maxEntries? | CDP Network.enable | Requisições (url/method/status/mimeType/ts) |
metro_state | expression?/wsUrl?/port?, timeoutMs? | CDP Runtime.evaluate | Lê o estado do app (padrão: store Redux exposto globalmente) |
Diagnóstico de crashes (2)
| Ferramenta | Parâmetros-chave | Engine de suporte | Comportamento |
|---|---|---|---|
crash_list | processName?, sinceHours?, udid? | host + sim DiagnosticReports | Mais recentes primeiro; marcados source: host | simulator |
crash_get | id, udid? | mesmo | Seguro contra path-traversal (somente basename); trunca honestamente |
A escada do oráculo — asserções confiáveis
"Funciona" é operacionalizado como um veredicto falseável e com evidências — nunca "parece ok". Asserções e validate_flow resolvem visibilidade através de uma escada de três degraus, usando o sinal mais forte disponível:
- DOM do WebView — quando um
WKWebViewinspecionável está presente, consulte o DOM real. - Acessibilidade nativa — o conjunto de elementos AX nativos (via
idb/mobilecli). - Maestro —
assertVisible/assertNotVisiblecomo fallback.
assert_not_visible falha fechada: se a ausência não puder ser verificada positivamente (por exemplo, um WebView ilegível), relata falha em vez de um falso positivo. Cada veredicto nomeia o oráculo que o produziu, para que um agente possa ponderar sua confiança.
Backend de gestos nativo-primeiro
Gestos imperativos (tap_on, input_text, swipe, press_key, orientation_set, run_steps) e inspect_screen roteiam pelo backend disponível mais rápido, sondado uma vez e armazenado em cache (com um TTL de cache negativo curto para que um backend que inicie após o lançamento seja detectado):
idb— quando ambosidbeidb_companionestão instalados (nativo, mais rápido).mobilecli— a dependência npm incluída (binário Go pré-compilado). Padrão; sem instalação.- Fallback Maestro — quando nenhum backend nativo resolve, ou para ações que ele não pode expressar (toque duplo/longo,
UPSIDE_DOWN). O gesto gera um fluxo mínimo comlaunchApp: { stopApp: false }, trazendo o app para o primeiro plano sem reiniciar para que o estado seja preservado.
Cada resultado relata o backend usado. Defina PODIUM_DISABLE_NATIVE=1 para forçar Maestro. Eliminar a inicialização JVM por gesto reduziu tap_on ~14,7 s → ~0,6 s e inspect_screen ~8,9 s → ~0,9 s em um simulador de iPhone 16 Pro. Execute npm run benchmark para uma varredura completa de pass/fail.
Tentativa de flakiness do Maestro: quando o fallback é executado, seu driver iOS falha intermitentemente com Failed to connect to 127.0.0.1:<port>. Os fluxos tentam novamente até 2× com backoff de 2 s / 5 s e relatam a contagem de retries; uma falha persistente retorna a saída bruta com dicas de remediação.
Introspecção de rede WebView e RN
Duas camadas de rede distintas, duas ferramentas:
metro_networkcaptura requisições no alvo RN/Hermes via domínio de rede CDP — a ferramenta certa para o própriofetchde um app RN nativo.webview_networkcaptura tráfego dentro de umWKWebView: injeta um gravadorfetch/XHR(rico — method/status/headers/body para chamadas após o início da captura) e lê o buffer de Performance Resource Timing do navegador (includeResources, padrão ativado) — toda requisição desde a navegação, incluindo as anteriores à captura (URL/timing/size). A mesclagem produz uma lista de requisições quase completa, exportada como JSON ou HAR 1.2 com redação.
Para um shell RN que hospeda sua UI em um WebView, as chamadas de API do app rodam na camada web — então metro_network não vê nada e webview_network é a ferramenta a usar. As ferramentas de WebView exigem WKWebView.isInspectable = true (padrão em builds debug/staging; desativado em produção); quando nenhum é encontrado, retornam um erro acionável.
Limites documentados (por design, não bugs)
- Canvas/WebGL precisa de um framework JS cooperativo — o cérebro de canvas automatiza UIs Pixi/Konva/Fabric/Phaser/Three/Babylon por seletor quando o app expõe a raiz do scene-graph (validado ao vivo). Um canvas WebGL bruto/personalizado, um build de produção opaco, ou Unity sem uma ponte AltTester /
window.__podiumEnginenão é endereçável por seletor — recorra atap_with_fallbackcom coordenadas derivadas de screenshot, ou instrumente o build. - Ferramentas WebView são apenas para dev/QA — builds de produção da App Store normalmente definem
isInspectable = false; as ferramentas retornam um erro acionável e recorrem a toques por coordenadas. - A memória do processo de conteúdo WebView é ilegível a partir do sandbox do app (limitação da plataforma) — use sinais indiretos (avisos de memória, terminações de processo).
- O matcher
text:do Maestro é regex de string completa (IGNORE_CASE) — strings parciais não correspondem; copie otextda hierarquia literalmente ou ancore com.*. - Android requer
adbemPATH— gestos / inspeção / screenshot funcionam uma vez queadbestá presente; quando ausente, todo caminho Android degrada para um resultado estruturado "adb not found". orientation_geté uma heurística de aspecto de screenshot quando nenhum backend nativo está presente — simuladores iOS não expõem consulta direta de orientação.record_start/record_stopmantêm estado no processo — serializestart→ … →stopem uma conexão; uma gravação ativa por udid (um watchdog finaliza uma que nunca é parada).
Arquitetura
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
Desenvolvimento e testes
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 testes de unidade/integração em 31 arquivos, mais 19 testes ao vivo de ponte de canvas (378 no total), todos passando — incluindo o registro de alvos de dispositivo v0.3.0, o driver Android adb + parser uiautomator, o cliente de engine AltTester + ponte WebGL, os parsers reais de iOS devicectl/WDA, além da escada de oráculo v0.2.0, watchdog de gravação, paridade de gestos, exportação HAR, WebView e caminhos Metro.
Padrões: TypeScript estrito, sem as any / @ts-ignore, sem execução de shell (todos os comandos via lib/exec.ts), ferramentas retornam erros estruturados em vez de lançar exceções. Veja CONTRIBUTING.md para o checklist "adicionar uma nova ferramenta".
E2E no CI: o workflow E2E (simulator) inicia um simulador iOS real em um runner macOS e executa as suítes de fumaça diariamente e sob demanda (não é um portão de PR — execuções de simulador são lentas). full-smoke.e2e.mjs afirma o caminho feliz onde um alvo existe e o caminho real de erro estruturado onde uma dependência está ausente (um app de debug isInspectable para WebView; um app RN conectado para metro_*).
Roadmap e contribuições
podium-mcp está pronto para produção em automação de UI iOS/Android e canvas/WebGL sem visão (Pixi/Konva/Fabric/Phaser/Three/Babylon — validado ao vivo). A fronteira, onde um contribuidor pode fazer uma diferença real, vive em issues abertas:
Alto impacto — help wanted
- #1 — validar o caminho da engine AltTester/Unity contra um build Unity instrumentado ao vivo (a maior lacuna para automação Unity real).
- #2 — e2e WKWebView em dispositivo real para o cérebro de canvas (hoje validado no Playwright WebKit).
- #3 — adaptador Unity-WebGL: auto-detecção + uma ponte
window.__podiumEngineplug-and-play.
Boas primeiras issues — good first issue
- #4 — mais adaptadores de canvas (PlayCanvas, Cocos Creator, p5.js).
- #5 — expor ferramentas
canvas_hittest/canvas_object_rect. - #7 — contagens exatas de tokens via API Anthropic
count_tokens. - #6 — abordar alvos Konva Group/Container.
Adicionar uma ferramenta segue um checklist em CONTRIBUTING.md: TypeScript estrito, sem shell, erros estruturados-nunca-lançar, um teste vitest e uma linha no catálogo de ferramentas. PRs são bem-vindos.
Lançamento
server.json é o manifesto oficial do Registro MCP. Enviar uma tag v* executa
Publish to npm e depois
Publish to MCP Registry (GitHub OIDC para o
namespace io.github.hoainho/* — sem token de longa duração). Ambos os workflows executam typecheck → build → test
como um portão primeiro; a publicação no registro só é bem-sucedida uma vez que a versão npm correspondente está ao vivo, e
versões são imutáveis.
Playbook de prompts e referências
prompts/— prompts copiáveis para fluxos e2e, casos de teste, verificação de recursos, correção de bugs e controle de dispositivo. Cada um nomeia as ferramentas podium que aciona e foi validado em um simulador real. Comece comprompts/README.md.docs/tool-catalog.md— referência autoritativa ferramenta por ferramenta.docs/e2e-demo.md— uma transcrição real contra um simulador iPhone 16 Pro iniciado executando um app RN de produção.
Ideias de design
- Um podium, uma conexão. Um único servidor cobre todas as capacidades móveis para que um agente configure um endpoint e descubra todas as 51 ferramentas de uma vez.
- Seguro por construção. Todo comando externo passa por uma camada
execFilecom um array de argumentos explícito — nunca uma string de shell. - Nunca derrube o maestro. Ferramentas retornam resultados e erros estruturados em vez de lançar; uma chamada ruim não pode derrubar o servidor.
- Degrade, não falhe. Uma toolchain ausente (ex.:
adbdo Android) produz um resultado informativo em vez de um erro grave. - Prove, não adivinhe. Asserções retornam vereditos com evidências via a escada de oráculo e falham fechado quando não podem verificar.
Contribuições
Contribuições são bem-vindas — veja CONTRIBUTING.md e o Código de Conduta. Use os templates de issue para bugs e solicitações de recursos.
Segurança
Por favor, relate vulnerabilidades de forma privada conforme SECURITY.md — não abra uma issue pública.
SECURITY.md também documenta o limite de confiança webview_eval / run_flow e a ressalva de PII em transcrições.
Licença
MIT © 2026 hoainho