
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

Um Curso Intensivo em MCP: Um Guia para Iniciantes Usando TypeScript
Este artigo apresenta o Model Context Protocol (MCP) como um padrão aberto para conectar aplicações de IA, explicando suas três pilares e como construir um servidor MCP em TypeScript.

Construímos operações de dados colunares para agentes de IA — aqui está o porquê e como
O Frame é uma suíte de operações de dados colunares que permite que agentes de IA manipulem dados empresariais sem a necessidade de infraestrutura adicional ou chamadas externas, eliminando riscos de alucinação.

Eu deduplicei todos os registros MCP em um único índice. Veja como 22.561 servidores realmente se parecem
Registros MCP mostram contagens duplicadas. Após a deduplicação, 22.561 servidores distintos foram identificados, revelando um ecossistema maior do que muitos plugins maduros.
Gostou do conteudo?
Receba toda semana as principais novidades sobre WebMCP.