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.