Um gateway MCP para todos os agentes
Servidor MCP único, com permissão por usuário e auditoria, que virou a porta de entrada das ferramentas dos agentes da empresa.
Resultados
560+
testes automatizados no Unificador
medidocontagem das funções de teste no repositório (nov/2026)
0
linhas de código para integrar um serviço novo: basta um cadastro no backoffice
antes: um adapter por serviço
medidodesde jul/2026pivô de arquitetura documentado na spec
30 s
prazo máximo por chamada de ferramenta, com erro estruturado
antes: chamada pendurada até o timeout de 300 s
medidonov/2026PR de correção do transporte
2
classes de vulnerabilidade crítica corrigidas em produção: SSRF e falsificação de identidade
declaradoauditoria de segurança que conduzi
Resumo
Contexto
Cada ferramenta de IA da empresa (editores, agentes internos e o agente de suporte da plataforma omnichannel) precisava configurar, uma a uma, as conexões MCP de que dependia, cada uma com sua credencial. Não havia um lugar central para dizer quem pode acessar o quê, nem registro do que foi consultado. O pedido veio do tech lead.
Ação
Desenhei e construí um servidor MCP unificado: o cliente se autentica uma vez e enxerga, numa lista só, as ferramentas de todas as conexões que tem permissão de usar. Logo no início troquei os adapters por serviço por um cliente MCP genérico, e integrar algo novo virou cadastro no backoffice. Depois vieram OAuth com login Google, conexões REST importadas de OpenAPI, identidade GCP para serviços privados e um servidor de triagem do Jira que recusa, por estrutura, card duplicado ou sem evidência.
Resultado
Em produção, com mais de 560 testes, o Unificador é a porta de entrada das ferramentas do agente de suporte, entre elas o servidor de triagem do Jira e o RAG interno. Corrigi vulnerabilidades críticas de duas classes (SSRF e falsificação de identidade) encontradas em auditoria própria. Depois de um incidente em que todas as chamadas falharam, migrei para transporte sem estado, com prazo de 30 s por chamada.
Lição
Quando a saída de um LLM volta para outro agente, ela é entrada de usuário: valide o formato e nunca repasse texto livre do modelo.
Arquitetura
Versão longa
O problema
Com o Model Context Protocol, um agente consegue usar ferramentas externas: Jira, bases de conhecimento, APIs internas. Mas cada cliente precisava cadastrar cada servidor MCP, guardar cada credencial e torcer para ninguém acessar o que não devia. Sem um ponto central, também não existia auditoria.
O Unificador
Uma autenticação, todas as ferramentas permitidas. O cliente se autentica uma vez (JWT ou OAuth) e recebe, agregadas, as ferramentas de todas as conexões liberadas para aquele usuário. A cada chamada, o backend decide qual conexão acionar.
Autorização em dois momentos e auditoria. A permissão é checada antes de expor a ferramenta e de novo antes de devolver a resposta, contra uma blacklist. Toda consulta vira um registro de auditoria. O backoffice (React, atrás do Google Cloud IAP) cuida de conexões, usuários, prompt e logs.
O pivô do início. A primeira versão tinha um adapter por serviço. Percebi que toda conexão podia ser tratada como um servidor MCP (nativo, ou uma API REST exposta como MCP a partir do OpenAPI) e troquei os adapters por um único cliente MCP genérico. Desde então, integrar um serviço novo não exige código.
OAuth, máquina a máquina e Cloud Run privado. Vieram depois: MCP OAuth com login Google e registro
dinâmico de cliente, client_credentials para serviços e um modo de autenticação que emite o ID
token do Google para chamar serviços privados. Medi a diferença contra o serviço real: um segredo
estático recebia 401, e o identity token, 200.
O servidor de triagem do Jira
Criar um card é fácil. O difícil é recusar o card errado: o duplicado e o que não tem informação para reproduzir. As duas recusas são estruturais, e não instruções de prompt que um agente sob pressão ou sob prompt injection poderia ignorar.
- Sem busca, sem card. As ferramentas de criação exigem um
busca_tokenassinado, que só existe depois de procurar duplicatas. - Portão de evidência. Um relato de bug só é aceito com descrição, passos, esperado, obtido, evidência, onde, quando e frequência. Se faltar algo, nada é criado, e o agente recebe a lista do que falta com uma mensagem pronta para o cliente.
- Dedup híbrida. São três consultas (cards recentes, frase exata da mensagem de erro e busca por palavras), mais uma regra determinística ("mesma mensagem de erro na mesma tela é duplicata") e um LLM juiz para o resto.
- O juiz não é confiável. Quem escreve o texto que o juiz lê é o cliente. Por isso o veredito só
pode ser
duplicataounovo, e qualquer outra coisa vira "perguntar ao cliente". A justificativa do modelo nunca chega ao agente, só ao log, porque seria um canal de prompt injection de segunda ordem saindo na voz do próprio serviço.
Um bug real guiou a dedup: um segundo relato do mesmo erro foi aberto 2 min 40 s depois do primeiro, porque a busca por palavras exigia todos os termos. A causa estava na busca, e a correção foi a estratégia híbrida.
O incidente
Um dia, todas as chamadas de ferramenta começaram a falhar. O transporte SSE guardava a sessão na memória da instância que abriu o stream; com autoscaling, a requisição seguinte caía em outra instância e recebia 404. A correção teve três partes: transporte Streamable HTTP sem estado, prazo total de 30 s por chamada e reconexão apenas quando o pedido ainda não tinha sido enviado, porque as ferramentas não são idempotentes. Entraram também um endpoint de saúde que testa o Jira de verdade e uma linha de log estruturada por chamada.
O que ainda falta
Ainda não tenho métricas de uso publicáveis, como cards evitados ou tempo economizado. Elas são o próximo passo, e os logs estruturados já estão no lugar para isso.
Lições aprendidas
- Genérico vence específico. Um cliente MCP genérico eliminou o código por integração logo no começo do projeto.
- Saída de LLM é entrada não confiável. O juiz de duplicatas só pode responder duplicata ou novo, e o texto dele nunca chega ao agente.
- Estado em memória não escala. Uma sessão presa a uma instância derrubou todas as chamadas com autoscaling; o transporte sem estado resolveu.