MCP em produção — 97M downloads, design patterns do arxiv, e o que ainda quebra

MCP em produção — 97M downloads, design patterns do arxiv, e o que ainda quebra

Em novembro de 2024, quando a Anthropic lançou o Model Context Protocol, os SDKs tinham 2 milhões de downloads mensais e a maioria das pessoas nem sabia o que era. Eu lembro de olhar a spec e pensar “isso é interessante, mas quem vai adotar?”. Dezesseis meses depois, são 97 milhões de downloads mensais e eu preciso admitir que estava errado.

MCP virou o protocolo padrão de conexão entre LLMs e ferramentas externas. Claude, GPT-5.4, Gemini — todos suportam. São 5.800+ servers no ecossistema. 4.750% de crescimento. E agora saiu um paper no arxiv que finalmente documenta o que funciona e o que não funciona quando você tenta colocar isso em produção.

O paper: arxiv 2603.13417

O paper “Bridging Protocol and Production: Design Patterns for Deploying AI Agents with MCP” é exatamente o tipo de documento que faltava. Não é um paper teórico sobre a beleza do protocolo — é um catálogo de design patterns extraídos de deploys reais de agentes usando MCP.

Os patterns que mais me interessaram:

1. Gateway Pattern

Em vez de cada agente se conectar diretamente a N MCP servers, você coloca um gateway na frente que gerencia conexões, auth e rate limiting. Parece óbvio, mas 90% dos tutoriais mostram conexão direta. Em produção com 10+ servers, sem gateway você vai ter um pesadelo de configuração e debug.

2. Tool Composition Pattern

Combinar ferramentas de múltiplos MCP servers em uma única chamada do agente. O paper mostra que a melhor abordagem é composição declarativa — o agente declara o que precisa, e o orquestrador resolve quais servers chamar. Tentativas de composição imperativa (o agente decidindo a sequência de chamadas) são frágeis e difíceis de debugar.

3. Fallback Chain Pattern

Quando um MCP server não responde, ter uma cadeia de fallback com servers alternativos. O paper documenta três estratégias: retry simples, fallback para server alternativo, e degradação graceful (retornar resultado parcial). Na prática, já implementei a terceira e é a que menos frustra o usuário final.

4. Context Window Management

O pattern mais técnico e mais útil. MCP servers podem retornar quantidades enormes de contexto — um server de database pode devolver milhares de linhas. O paper propõe um context budget por tool call, onde o orquestrador limita o output de cada server para caber no context window do modelo. Sem isso, um server guloso come o contexto inteiro e o agente perde acesso às outras ferramentas.

Hands-on: criando um MCP server

Chega de teoria. Vamos montar um MCP server básico que expõe uma API de busca para um agente.

TypeScript (SDK oficial)

npm install @modelcontextprotocol/sdk
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "search-server",
  version: "1.0.0",
});

// Registra uma tool que o agente pode chamar
server.tool(
  "search_docs",
  "Busca na documentação interna",
  {
    query: z.string().describe("Termo de busca"),
    limit: z.number().default(5).describe("Máximo de resultados"),
  },
  async ({ query, limit }) => {
    // Aqui vai sua lógica real — Elasticsearch, pgvector, whatever
    const results = await searchIndex(query, limit);
    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(results, null, 2),
        },
      ],
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

Python (SDK via PyPI)

pip install mcp
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import TextContent, Tool

server = Server("search-server")

@server.tool()
async def search_docs(query: str, limit: int = 5) -> list[TextContent]:
    """Busca na documentação interna."""
    results = await search_index(query, limit)
    return [TextContent(type="text", text=str(results))]

async def main():
    async with stdio_server() as (read, write):
        await server.run(read, write, server.create_initialization_options())

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

Ambos os SDKs usam stdio como transport padrão — o client spawna o server como processo filho e se comunica via stdin/stdout. Isso é simples para desenvolvimento, mas em produção você vai querer HTTP/SSE (Server-Sent Events), que ambos os SDKs já suportam.

Conectando no Claude Desktop (teste rápido)

Edite o claude_desktop_config.json:

{
  "mcpServers": {
    "search-docs": {
      "command": "node",
      "args": ["./dist/server.js"]
    }
  }
}

Reinicie o Claude Desktop e a tool search_docs aparece disponível. O agente pode invocá-la naturalmente durante a conversa.

O que ainda quebra em produção

Aqui é onde eu troco o chapéu de entusiasta pelo de engenheiro cansado. MCP em produção tem problemas reais que o hype esconde.

Auth cross-server

O maior gap. Cada MCP server gerencia sua própria autenticação. Se você tem 15 servers, o usuário precisa autenticar em cada um separadamente. Não existe um padrão de SSO ou token federation nativo no protocolo. O blog da WorkOS documenta bem esse problema e propõe soluções, mas nenhuma é oficial ainda.

Na prática, o que eu faço é injetar tokens via variáveis de ambiente no momento do spawn do server. Funciona, mas é um hack — e não escala para cenários onde o token precisa ser refreshed durante a sessão.

Session state

MCP sessions são stateless por padrão. Se o server crashar e reiniciar, todo o contexto acumulado se perde. O paper do arxiv propõe um State Checkpoint Pattern, mas ninguém implementou isso nos SDKs oficiais ainda. Se seu agente depende de estado acumulado ao longo de uma conversa (e a maioria depende), você precisa implementar persistência por conta própria.

Streaming

O suporte a streaming de respostas longas é inconsistente entre implementações. O SDK TypeScript lida bem com SSE, mas o SDK Python tem edge cases com backpressure que podem causar memory leaks em sessões longas. Já perdi horas debugando isso.

Observabilidade

Não existe um padrão de tracing entre client e servers MCP. Se uma cadeia de 5 tool calls falha, boa sorte descobrindo onde foi. Eu adaptei OpenTelemetry manualmente nos meus servers, mas deveria ser built-in.

Roadmap 2026: o que vem por aí

O The New Stack publicou o roadmap que a comunidade está trabalhando. Os pontos mais relevantes:

  • Auth padronizado: OAuth 2.1 como padrão de autenticação para MCP servers. Finalmente.
  • Streamable HTTP transport: substituição do SSE por um transport mais robusto para produção.
  • Registry protocol: um padrão para discovery de MCP servers — tipo um DNS para ferramentas de agentes.
  • Elicitation: capacidade do server pedir informação adicional ao usuário via o client, sem interromper o fluxo do agente.

Se o auth padronizado e o registry saírem no Q2 como prometido, MCP vira um protocolo enterprise-ready de verdade. Até lá, prepare-se para escrever bastante glue code.

Veredito

MCP não é mais experimental. 97 milhões de downloads mensais e suporte universal dos providers transformaram o protocolo em padrão de facto. O paper arxiv 2603.13417 é leitura obrigatória para quem está deployando agentes — os design patterns economizam semanas de tentativa e erro.

Mas “padrão de facto” não significa “maduro”. Auth, state e observabilidade são problemas reais que você vai enfrentar. O roadmap promete resolver boa parte disso em 2026, e a velocidade da comunidade (de 2M para 97M downloads em 16 meses) me dá alguma confiança.

Se você ainda não tem MCP servers no seu stack de agentes, comece com o Gateway Pattern e um server simples como o exemplo acima. Mantenha o escopo pequeno, instrumente tudo, e prepare-se para reescrever o auth quando o padrão OAuth 2.1 sair.

Paper: arxiv.org/abs/2603.13417. SDK TypeScript: @modelcontextprotocol/sdk. SDK Python: mcp no PyPI. Vai lá, monta um server, quebra em produção, e me conta o que deu errado.