Meu eval disse que um servidor MCP perfeito estava quebrado. Era o eval que estava mentindo.
Publicado originalmente em tengli.dev
Quando adicionei uma avaliação impulsionada por LLM ao mcpgrade, a primeira execução real produziu um resultado que parecia uma grande descoberta: context7 — um servidor com uma pontuação estática perfeita — falhou na seleção de ferramentas 62% das vezes. Um modelo que mostrava seu catálogo de duas ferramentas escolheu a ferramenta "errada" em 5 de 8 tarefas.
Se eu tivesse enviado esse número, estaria errado. Não levemente errado — sistematicamente, injustamente errado. Este post é sobre como eu descobri isso, porque o modo de falha se generaliza para a maioria dos benchmarks de agentes que as pessoas estão construindo agora.
A configuração
O modo --eval do mcpgrade funciona assim: ele lê o catálogo de ferramentas de um servidor, sintetiza tarefas realistas de um único passo ("encontre o canal do Slack onde o incidente foi discutido"), mostra ao modelo o catálogo completo e mede três coisas — ele escolhe a ferramenta certa, preenche argumentos válidos e recusa corretamente tarefas que nenhuma ferramenta pode lidar.
A rodada 1, em três servidores reais, custou cerca de doze centavos e produziu isso:
| Servidor | Pontuação estática | Seleção de ferramentas | Args | Recusa |
|---|---|---|---|---|
| context7 (2 ferramentas) | 100 | 38% | 100% | 100% |
| server-memory (9 ferramentas) | 81 | 93% | 100% | 100% |
| server-slack (8 ferramentas) | 97 | 54% | 100% | 100% |
Dois servidores com excelentes pontuações estáticas, aparentemente falhando ao vivo. Ou a análise estática era inútil, ou a avaliação estava quebrada.
A avaliação estava quebrada
Cada "erro" foi rastreado a uma causa. O post_message do Slack precisa de um thread_ts — um valor que você só pode obter de uma chamada anterior ao get_channel_history. O get-library-docs do context7 precisa de um ID de biblioteca que vem de resolve-library-id. Essas são ferramentas em pipeline: seus argumentos necessários são produzidos por outras ferramentas.
Meu sintetizador de tarefas não sabia disso. Ele gerou tarefas como "responder ao tópico sobre a interrupção" — sem um timestamp de thread. O modelo, bastante sensatamente, escolheu get_channel_history primeiro (para encontrar o tópico), ou se recusou. Meu avaliador marcou ambas as escolhas como erradas.
O modelo não estava confuso. O modelo estava certo. O benchmark estava avaliando o raciocínio correto de múltiplos passos como falha — e os 93% da memória eram a prova o tempo todo: suas ferramentas são de um único passo, então ele pontuou bem.
A correção foi uma restrição no prompt de síntese: toda tarefa deve incorporar valores concretos para cada parâmetro necessário. "Responder ao tópico 1721581200.123456 em #incidents" — agora a seleção de um único passo é uma pergunta justa. Rodada 2: context7 38% → 100%, slack 54% → 100%.
Se seu benchmark de agente mostra um modelo capaz falhando em ferramentas que usuários reais navegam bem, verifique se você está fazendo perguntas de um passo sobre ferramentas de múltiplos passos. Na minha experiência, a maioria dos números de "precisão de seleção de ferramentas" caseiros tem esse bug inflacionando silenciosamente suas taxas de falha.
Rodada 3: ele discrimina?
Um benchmark que dá 100% a todos é decoração. Então a rodada 3 apontou a avaliação corrigida para firecrawl — 26 ferramentas, a menor pontuação estática no meu scan de 36 servidores. Se a avaliação está medindo algo real, um catálogo bagunçado deve pontuar pior. E pontuou, de duas maneiras específicas:
1. Erros de seleção ocorreram exatamente nas colisões de nomenclatura que as regras estáticas haviam sinalizado. 84% de precisão na seleção, e os 16% não eram aleatórios: extract↔scrape, agent_status↔check_crawl_status, feedback↔search_feedback — os mesmos pares confusos que as regras estáticas (N002, C001) já haviam sinalizado apenas a partir de nomes e descrições. Esse é o resultado que eu mais queria: lint estático prevê confusão do modelo ao vivo. A varredura barata, gratuita e de dez segundos encontra os mesmos pontos de falha que a avaliação LLM.
2. A recusa colapsou. Dadas tarefas deliberadamente fora do escopo, os modelos se recusaram corretamente 100% das vezes em catálogos pequenos e bem documentados — e 50% das vezes nas 26 ferramentas vagas do firecrawl. Metade das vezes, o modelo "encontrou" uma ferramenta que parecia plausível e a chamou mesmo assim. Catálogos grandes e vagos não apenas causam escolhas erradas; eles causam ação quando a inação é correta, que na produção é o modo de falha mais assustador que existe. Ninguém revisa o agente que fez algo com confiança.
O que três rodadas me trouxeram
A calibração completa — três rodadas, quatro servidores — custou cerca de $0,60 em um modelo pequeno. Por isso, obtive respostas para as três perguntas que qualquer avaliação deve sobreviver:
- É justo? Após a correção de síntese, servidores bem projetados pontuam 100%. As falhas agora significam algo.
- Ele discrimina? Catálogos bagunçados pontuam visivelmente pior, de maneiras interpretáveis.
- É acessível? ~$0,04–0,2 por servidor. Executá-lo em cada PR é um erro de arredondamento.
A maioria dos construtores de benchmark pula direto para as tabelas de classificação. A etapa de calibração — tentando deliberadamente provar que sua própria métrica está mentindo — é barata, sem glamour, e a única coisa que separa uma medição de um gerador de números aleatórios com eixos.
A calibração não está terminada — um leitor provou isso
Dentro de um dia após o post de lançamento, um leitor (Mads Hansen, nos comentários do dev.to) apontou duas falhas que eu não havia percebido, e ele está certo em ambas.
Primeiro: minha taxonomia de resultados ainda é muito grosseira. "Recusa" atualmente agrupa um modelo que faz uma pergunta de esclarecimento e um modelo que declina diretamente — e nenhum deles é separado do resultado realmente perigoso, chamando com confiança uma ferramenta plausível, mas errada. Quatro categorias (chamada correta / recusa correta / esclarecimento correto / ação plausível insegura) com pesos diferentes é estritamente melhor, porque seus custos de produção são extremamente diferentes.
Segundo, e mais sutil: minhas tarefas sintéticas podem favorecer os esquemas que as geraram. O sintetizador lê o catálogo para escrever tarefas — então um catálogo mal escrito produz tarefas formuladas em seu próprio vocabulário ruim. A correção é a autoria retida: derivar intenções de falhas de integração reais, paráfraseá-las através de uma etapa que nunca vê nomes de ferramentas e congelar a divisão de teste antes de tocar em qualquer descrição.
Ambos agora estão questões rastreadas no repositório. Esse é o ponto de publicar sua metodologia em vez de apenas sua tabela de classificação: leitores depuram seu benchmark da mesma forma que depurariam seu código.
Números brutos completos e metodologia vivem no repositório: docs/eval-calibration.md. Se você construir benchmarks de agentes e encontrou outros padrões de injustiça sistemática, quero ouvir sobre eles — abra uma questão.
Eu construo integrações de agentes de IA em produção em uma grande empresa de tecnologia; mcpgrade é um projeto pessoal. A avaliação é executada em qualquer endpoint compatível com OpenAI — traga sua própria chave.
O artigo destaca a importância de avaliações precisas para servidores MCP, essencial para empresas que utilizam agentes de IA. A calibração correta de benchmarks pode evitar decisões erradas em ambientes de produção, impactando diretamente a eficiência operacional.
