MCP (Model Context Protocol): Integrando AI Agents com Tools

Entenda o Model Context Protocol da Anthropic: arquitetura, primitivas (resources, prompts, tools) e como ele padroniza integração de AI agents com sistemas externos.

MCP: Como a Anthropic Quer Padronizar Integração de Tools em AI Agents

Desenvolver um AI agent significa, inevitavelmente, conectá-lo a sistemas externos: bancos de dados, APIs, filesystems, ferramentas internas. Tradicionalmente, isso exige implementar function calling específica para cada LLM provider, gerenciar contexto manualmente e manter múltiplas integrações sincronizadas. A Anthropic propôs uma solução diferente: o Model Context Protocol (MCP), um protocolo open-source anunciado em novembro de 2024 que separa a lógica de integração da implementação específica do LLM.

O MCP não é apenas mais uma biblioteca de abstrações. É uma especificação de protocolo baseada em JSON-RPC 2.0 que define como hosts (aplicações com LLMs) conversam com servidores (wrappers de ferramentas externas) através de uma arquitetura stateful. A aposta: padronizar essa camada reduz trabalho duplicado. Você implementa um servidor MCP uma vez, e qualquer host compatível pode usá-lo.

Mas vale adicionar essa camada extra de complexidade? Para responder, precisamos entender o que o MCP faz diferente arquiteturalmente e onde ele realmente agrega valor comparado a implementações diretas de function calling.

Arquitetura: Três Primitivas Fundamentais

O MCP organiza integrações em torno de três conceitos que vão além do tradicional “lista de funções invocáveis”:

Resources representam dados que o LLM pode consultar. Diferente de simplesmente passar contexto no prompt, resources são identificados por URIs (formato resource://server/path) e podem ser estáticos ou dinâmicos. Um servidor de filesystem pode expor resource://fs/project/README.md, enquanto um servidor de banco de dados pode gerar resource://db/users/latest dinamicamente. O host decide quando solicitar esses recursos através de resources/read, e o servidor retorna o conteúdo com metadata.

Prompts são templates reutilizáveis com slots para argumentos. Em vez de cada aplicação recriar prompts para tarefas comuns, um servidor MCP pode expor prompts/list retornando templates como “analise-logs” ou “gere-sql-query”. Isso centraliza expertise de prompting: o servidor do Postgres sabe como formular prompts eficazes para análise de schema, e qualquer host pode reutilizar esse conhecimento.

Tools são funções invocáveis pelo LLM, similar ao function calling tradicional. Cada tool possui um schema JSON para validação de parâmetros e retorna resultados estruturados. A diferença crucial? Tools operam dentro de uma sessão persistente que já estabeleceu capabilities e autenticação.

A separação dessas primitivas tem implicações práticas. Quando você implementa function calling direto, mistura tudo: dados de contexto vão no prompt, templates são strings hardcoded na aplicação, e funções são registradas ad-hoc. O MCP força uma separação que torna cada componente independente e reutilizável.

Arquitetura Stateful: Conexões Persistentes vs Request Stateless

Aqui está o trade-off fundamental: o MCP adiciona complexidade de gerenciamento de estado em troca de eficiência de contexto. Cada conexão passa por um handshake de initialize onde cliente e servidor negociam capabilities. Essa sessão persiste durante o lifecycle da aplicação host.

Por que isso importa? Em function calling tradicional, cada request é stateless. Você envia a lista completa de funções disponíveis toda vez, replica configurações de autenticação, e o LLM redescobre quais tools usar. Com MCP, o handshake acontece uma vez: o servidor declara “eu tenho 20 tools do GitHub, suporto resources do tipo markdown”, e essa informação permanece válida durante toda a sessão.

O protocolo usa JSON-RPC 2.0 sobre três camadas de transporte: stdio (processos locais), HTTP com Server-Sent Events (conexões remotas), e custom transports para casos especiais. A escolha de SSE para HTTP não é acidental - permite que o servidor envie notificações assíncronas quando resources mudam, algo que REST stateless não suporta naturalmente.

O custo dessa arquitetura é gerenciamento de conexões. Você precisa lidar com reconexões, timeouts, e garantir que servidores MCP sejam processos long-running confiáveis. Para ambientes onde você controla a infraestrutura, isso é aceitável. Para integrações simples ou serverless, adiciona overhead que pode não se justificar.

Diferenças Conceituais com Function Calling Tradicional

A documentação oficial não fornece benchmarks quantitativos comparando MCP com function calling, mas as diferenças arquiteturais criam padrões de uso distintos:

Escopo de contexto: Function calling envia definições de funções a cada request. Com 50+ funções, isso consome tokens significativos do context window. MCP declara capacidades no handshake e o host gerencia quais tools expor ao LLM em cada interação. Você pode ter 100 tools registrados no servidor mas passar apenas 5 relevantes ao LLM por request.

Composabilidade: Um servidor MCP é uma unidade isolada. O servidor do GitHub (disponível no repositório oficial em github.com/modelcontextprotocol/servers) implementa 20+ tools incluindo create_issue, push_files, search_repositories. Você adiciona esse servidor à configuração do Claude Desktop e todas essas funcionalidades ficam disponíveis. Com function calling direto, você provavelmente reimplementaria essas integrações para cada projeto.

Separação de responsabilidades: MCP empurra lógica de integração para fora da aplicação. Autenticação de APIs externas, rate limiting, transformação de dados - tudo acontece no servidor MCP. Sua aplicação host só gerencia a orquestração do LLM e decide quando usar cada capability. Se algo quebra na integração com Slack, você investiga o servidor MCP de Slack, não toda a aplicação.

Embora os detalhes exatos de performance não sejam públicos, a arquitetura sugere que MCP é mais eficiente para cenários com múltiplas interações na mesma sessão (agentes autônomos, análises longas) e menos apropriado para requests únicos onde o overhead de connection setup não se paga.

Patterns de Implementação em Python

Um servidor MCP típico em Python usa 50-200 linhas com o SDK oficial (mcp). A estrutura básica envolve decorators que registram handlers:

from mcp.server import Server
from mcp.types import Tool, TextContent

server = Server("example-server")

@server.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="analyze_data",
            description="Analisa dataset e retorna estatísticas",
            inputSchema={
                "type": "object",
                "properties": {
                    "dataset_path": {"type": "string"},
                    "metrics": {"type": "array", "items": {"type": "string"}}
                },
                "required": ["dataset_path"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "analyze_data":
        # Lógica de análise aqui
        results = perform_analysis(arguments["dataset_path"])
        return [TextContent(type="text", text=str(results))]

O pattern de resources é similar, mas com URIs e metadata:

@server.list_resources()
async def list_resources() -> list[Resource]:
    return [
        Resource(
            uri="resource://example/config",
            name="App Configuration",
            mimeType="application/json"
        )
    ]

@server.read_resource()
async def read_resource(uri: str) -> str:
    if uri == "resource://example/config":
        return load_config_json()

Autenticação geralmente usa variáveis de ambiente. O servidor do GitHub espera GITHUB_TOKEN, o do Slack precisa de SLACK_TOKEN. Essa configuração acontece no arquivo de config do cliente MCP (ex: claude_desktop_config.json no Claude Desktop):

{
  "mcpServers": {
    "github": {
      "command": "python",
      "args": ["-m", "mcp_server_github"],
      "env": {
        "GITHUB_TOKEN": "ghp_..."
      }
    }
  }
}

O modelo é simples mas eficaz: cada servidor é um processo isolado, a configuração declara dependências e credenciais, e o host gerencia lifecycle.

Estado Atual e Considerações Práticas

O MCP está em early adoption. Lançado em novembro de 2024, tem aproximadamente dois meses de existência pública. O suporte mais maduro está no Claude Desktop (versão 0.7.0+), mas vale destacar uma limitação crucial: o protocolo ainda não está disponível na API da Anthropic. Você pode usar MCP no desktop app, mas não em integrações server-side com a API comercial do Claude.

Adoções documentadas incluem Block (Square) que anunciou integração em novembro, e o editor Zed que adicionou suporte em dezembro 2024. O repositório oficial de servidores (github.com/modelcontextprotocol/servers) contém 11+ implementações de referência: filesystem, postgres, sqlite, github, google-drive, slack, puppeteer, brave-search. Esses servidores servem como templates e casos de uso reais.

Dois pontos críticos se você estiver considerando adotar MCP agora:

Documentação de produção é escassa. A maioria dos exemplos públicos são experimentais ou proofs-of-concept. Best practices para error handling, retry logic, monitoring em escala - isso ainda está sendo descoberto pela comunidade. A especificação técnica (spec.modelcontextprotocol.io) é sólida, mas padrões operacionais ainda não se consolidaram.

Complexidade adicional precisa se justificar. Se você está construindo um chatbot simples com 3-4 funções, implementar function calling direto é mais pragmático. MCP faz sentido quando você tem múltiplas integrações complexas que serão reutilizadas em diferentes contextos, ou quando precisa da separação de responsabilidades para auditoria e governança.

A aposta da Anthropic é clara: assim como REST se tornou padrão para APIs HTTP, MCP pode se tornar padrão para integrações de AI agents. A arquitetura é sólida tecnicamente, e o modelo open-source com SDKs oficiais acelera adoção. Mas dois meses é pouco tempo para validar um protocolo em produção. Vale acompanhar a evolução, experimentar com os servidores de referência, e avaliar se os trade-offs de complexidade se pagam para seu caso de uso específico.

Se você decidir explorar, comece com um servidor simples expondo 1-2 tools de sistemas que você já usa. A curva de aprendizado é baixa, e a experiência de ter tools reutilizáveis entre projetos pode revelar se a abordagem faz sentido para sua arquitetura.


← Voltar para home