
MCP vs CLI para Automação de Navegadores: Benchmark Revelador
Três semanas atrás, publiquei safari-mcp — um servidor de automação Safari nativo do macOS que fala o Protocolo de Contexto do Modelo. 84 ferramentas, AppleScript + extensão opcional para velocidade, mantém logins do Safari, zero sobrecarga do Chrome. Hoje está nos marketplaces do VS Code e Cursor.
Então eu vi HKUDS/CLI-Anything — um projeto com 29 mil estrelas que envolve software de código aberto como CLIs prontos para agentes. A proposta deles: "Faça TODO o software nativo para agentes." O principal exemplo deles é DOMShell envolto como cli-anything-browser — uma interface que pode ser encadeada para automação do Chrome.
Eu queria saber: vale a pena envolver safari-mcp como um CLI? Ou é apenas teatro — reexpondo um servidor MCP funcional como uma interface estritamente pior?
Então eu construí a estrutura (PR #212) e a testei ao vivo contra o caminho MCP direto. Safari real, macOS real, medido em 2026-04-10.
Veja o que eu encontrei.
TL;DR
| MCP (stdio direto) | CLI (subprocesso por chamada) | Vencedor | |
|---|---|---|---|
| Latência por chamada | 119ms | 3,023ms | MCP, 25× |
| Fluxo de trabalho de 5 operações | 2.7s | 15.2s | MCP, 5.6× |
| Tokens por chamada de API (definições de ferramentas) | 7,986 | 95 | CLI, 84× |
| Precisão da saída | idêntica | idêntica | empate |
- Se seu agente fala MCP (Claude Code, Cursor, Cline, Windsurf, Continue, OpenClaw, qualquer cliente ciente de MCP) — use o MCP diretamente. O CLI é estritamente mais lento.
- Se você precisa acioná-lo a partir do bash, CI, cron, ou um agente que não fala MCP — use o CLI. A economia de tokens se acumula; com a precificação do Claude Opus, uma sessão de 100 turnos economiza cerca de $12 apenas em sobrecarga de definição de ferramentas.
Essa é toda a história. Se você só queria os números, pode parar aqui. Se você quer a metodologia, os casos extremos e os bugs que encontrei ao longo do caminho, continue lendo.
O que eu realmente construí
A estrutura (safari/agent-harness/) é um gerador de CLI orientado a esquema:
Parser Zod Offline (
scripts/extract_tools.py) lê a fonte do safari-mcp e emiteresources/tools.json— o esquema completo para todas as 84 ferramentas. Consciente da profundidade, lida corretamente comz.array(z.object({...})).describe("outer").Gerador Click em Tempo de Execução (
safari_cli.py) carrega o registro no momento da importação e constrói um subcomando Click por ferramenta MCP. Nomes de argumentos, tipos, escolhas de enum, flags obrigatórias e descrições são todos extraídos do esquema. Mapeamento manual zero.Suite de Teste de Paridade (
test_parity.py) itera o registro e verifica se cada ferramenta é acessível, se cada parâmetro está conectado corretamente, se cada enum corresponde. Se o registro e o CLI alguma vez se desviarem, os testes gritam.
A superfície do CLI acaba parecendo assim:
$ cli-anything-safari tools count
84
$ cli-anything-safari tools describe safari_click
Nome: safari_click
CLI comando: tool click
Descrição: Clique no elemento. Use ref (do snapshot), seletor, texto ou x/y...
Parâmetros:
--ref (string, opcional)
--selector (string, opcional)
--text (string, opcional)
--x (number, opcional)
--y (number, opcional)
$ cli-anything-safari --json tool snapshot
"ref=0_0 body\nref=0_1 div\nref=0_2 navigation "Sidebar"\n..."
Mesma interface que o MCP upstream, apenas por trás das chamadas click.command(...).
A configuração do benchmark
Ambos os caminhos atingem o mesmo servidor safari-mcp no final. A diferença é o modelo de conexão:
MCP direto: Python → stdio (persistente) → safari-mcp → Safari
CLI: Python → subprocesso → npx → Node → safari-mcp → Safari
Para o MCP, usei mcp.ClientSession com uma conexão stdio persistente, medindo apenas a viagem de ida e volta de call_tool() (inicialização amortizada). Para o CLI, medi o tempo total de subprocess.run([...]). Ambos tiveram uma chamada de aquecimento que descartei.
O script de benchmark está em /tmp/benchmark_cli_vs_mcp.py (não comitado porque é um rascunho); o loop chave é:
# MCP: sessão persistente, N chamadas
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
await session.call_tool(tool_name, args) # aquecimento
for _ in range(n):
t0 = time.perf_counter()
await session.call_tool(tool_name, args)
times.append((time.perf_counter()A comparação entre MCP e CLI é crucial para empresas que buscam otimizar suas automações web. O uso do MCP pode resultar em economias significativas em custos e tempo, especialmente para aplicações que exigem alta performance. Essa análise ajuda as empresas brasileiras a escolherem a melhor abordagem para integrar automação em seus processos.
Noticias relacionadas

Claude Code + Notion: Fluxo de Trabalho Completo de Sistema de Conhecimento Automatizado
O artigo explora como integrar Claude Code com Notion usando o protocolo MCP, permitindo colaboração em tempo real e sincronização eficiente de documentos, superando limitações do Obsidian.

Pare de Promptar, Comece a Vibra: A Stack de 2026 para Fluxos de Trabalho Agentivos e MCP
O artigo discute a transição para Fluxos de Trabalho Agentivos e o Protocolo de Contexto de Modelo (MCP), destacando a importância de ferramentas que suportem esses novos padrões para aumentar a produtividade.

MCP na Prática — Parte 9: Dos Conceitos a um Exemplo Prático
A Parte 9 da série MCP na Prática mostra a transição de um servidor MCP local para um serviço HTTP independente, destacando mudanças no modelo de implantação e considerações de segurança.
Gostou do conteudo?
Receba toda semana as principais novidades sobre WebMCP.