O que é Adaptador MCP?
Adaptador MCP (MCP Adapter) é um padrão de projeto de IA para apps com LLM e agentes, do grupo Ferramentas e ação. Expor sistemas como servidores MCP para qualquer agente usar o mesmo contrato.
MCP Adapter
Adaptador MCP (MCP Adapter) é um padrão de projeto de IA para apps com LLM e agentes, do grupo Ferramentas e ação. Expor sistemas como servidores MCP para qualquer agente usar o mesmo contrato.
Expor sistemas internos como servidores MCP (Model Context Protocol), para que qualquer agente use o mesmo contrato de ferramentas. Serve para empresas com vários agentes, clientes e modelos que precisam acessar os mesmos sistemas.
Uma tomada padrão na parede: qualquer aparelho com o plugue certo funciona, sem refazer a instalação elétrica.
Vitor trabalha no time de plataforma de uma empresa com quatro agentes em produção: suporte, back-office, engenharia e um assistente interno. Os quatro precisam consultar o ERP, o CRM e a base de tickets.
Cada time escreveu suas próprias ferramentas. O ERP tem quatro implementações de “buscar pedido”, com nomes, parâmetros e formatos de retorno diferentes. Uma devolve a data como 2026-09-30, outra como 30/09/2026, e uma terceira devolve o objeto inteiro do ERP, com 80 campos.
Quando a API do ERP mudou a autenticação, quatro times tiveram que corrigir o código na mesma semana. Quando a empresa quis testar um assistente de código que já sabe falar MCP, ninguém conseguiu ligar o ERP nele sem escrever a integração do zero.
E ninguém sabia responder uma pergunta simples da auditoria: quais agentes podem criar devoluções, e em nome de quem?
O problema não é cada ferramenta. É a falta de um contrato comum entre os sistemas e quem os usa.
A pergunta que este padrão responde: como escrever cada integração uma vez e usá-la em qualquer agente, modelo ou cliente?
Para cada sistema, crie um servidor MCP que expõe ferramentas (ações), recursos (dados para ler) e, quando fizer sentido, prompts prontos. O servidor é dono da autenticação, das permissões, da validação e do formato de saída. Os agentes se conectam como clientes MCP e recebem a lista de ferramentas com nome, descrição e schema.
O MCP é um protocolo aberto, lançado pela Anthropic em novembro de 2024 e adotado depois por outros provedores e ferramentas. O mesmo servidor funciona com agentes próprios, com assistentes de código, com IDEs e com conectores MCP das APIs de modelo. A integração deixa de pertencer a um agente e passa a pertencer ao sistema.
Pense na conta de integrações. Com 4 agentes e 3 sistemas, cada time escrevendo a sua, são até 12 integrações para manter. Com um servidor por sistema, são 3 servidores, e cada agente novo só precisa de um cliente MCP, que o framework normalmente já traz.
O MCP usa mensagens JSON-RPC. Quando o agente de suporte conecta no servidor do ERP, o cliente pede a lista de ferramentas (tools/list) e recebe algo assim (resumido):
{
"tools": [
{
"name": "find_order",
"description": "Busca status, itens e datas de um pedido. Use quando o usuário citar um número de pedido.",
"inputSchema": {
"type": "object",
"properties": { "order_id": { "type": "string", "pattern": "^[0-9]+$" } },
"required": ["order_id"]
}
}
]
}
O cliente entrega essa lista ao modelo como definições de ferramenta. Quando o modelo decide usar find_order, o cliente manda um tools/call:
{ "method": "tools/call", "params": { "name": "find_order", "arguments": { "order_id": "88231" } } }
O servidor checa o escopo do usuário, chama o ERP e devolve só o que interessa:
{
"content": [
{ "type": "text", "text": "{\"id\": \"88231\", \"status\": \"entregue\", \"delivered_at\": \"2026-09-30\", \"items\": [{\"sku\": \"CAD-112\", \"qty\": 2}]}" }
],
"isError": false
}
Repare no que o agente não vê: a URL do ERP, o token de serviço, os 80 campos crus. Os quatro agentes recebem a mesma resposta, no mesmo formato, com a mesma data.
flowchart LR
A1(["1. Agente de suporte"]):::llm --> C["2. Cliente MCP"]:::tool
A2(["1. Agente de back-office"]):::llm --> C
A3(["1. Assistente de código"]):::llm --> C
C --> S1["3. Servidor MCP do ERP"]:::tool
C --> S2["3. Servidor MCP do CRM"]:::tool
S1 --> P{"4. Auth e permissões"}
P --> ERP[("5. ERP")]:::store
S2 --> CRM[("5. CRM")]:::store
server erp_mcp:
tool find_order(order_id: string) -> Order # leitura
require scope("orders:read")
return normalize(erp.get_order(order_id))
tool create_return(order_id: string, reason: string) -> ReturnLabel # efeito
require scope("returns:write")
audit.log("create_return", caller, order_id)
return erp.create_return(order_id, reason, idempotency_key=request_id())
resource "erp://policies/returns" -> text # dado para ler
agent support:
tools = mcp.connect("erp_mcp", token=user_token).list_tools() # 2
run_agent(SUPPORT_PROMPT, tools) # 1
find_order, não GET /v2/sales/orders/{id}/header.order_id para orderId num deploy quebra todos os agentes ao mesmo tempo. Acrescente campos; para remover ou renomear, publique uma versão nova.| Variação | Onde roda | Bom para | Cuidado com |
|---|---|---|---|
| Local (stdio) | máquina do agente | ferramentas de desenvolvedor | credenciais na máquina de cada pessoa |
| Remoto (HTTP) | serviço compartilhado | produção, vários agentes | disponibilidade e autenticação |
| Conector da API | provedor chama seu servidor | agentes sem loop próprio | o servidor precisa estar exposto ao provedor |
| Gateway | na frente dos servidores | política e auditoria centrais | mais um salto e mais um ponto de falha |
| Aspecto | O que acontece | Como aparece no trace |
|---|---|---|
| Chamadas | Cada ferramenta vira uma requisição ao servidor | spans mcp.call com servidor e ferramenta |
| Latência | Um salto de rede a mais por chamada remota | duração do span mcp.call |
| Contexto | A lista de ferramentas do servidor entra no prompt | tokens de ferramentas por conexão |
| Falha: servidor fora | Todos os agentes que dependem dele param | erros em mcp.call de vários agentes ao mesmo tempo |
| Falha: schema mudou | Agentes antigos mandam argumentos inválidos | erros de validação depois de um deploy do servidor |
| Falha: ferramentas demais | Um servidor expõe dezenas de operações | escolha errada de ferramenta no agente |
O custo de contexto é fácil de esquecer. Conectar três servidores com 20 ferramentas cada coloca 60 definições em toda chamada do agente. Exponha só o necessário por agente, ou combine com o Roteador de Ferramentas.
{ "agent": "support", "task": "status do pedido 88231", "expected_tool": "find_order", "expected_scope": "orders:read" }
Os testes de contrato não precisam de modelo. Chame o servidor direto, com um cliente MCP de teste: um order_id com letras deve ser recusado, um usuário sem returns:write não pode criar devolução, e a resposta de find_order tem sempre os mesmos campos. Esses testes rodam em todo deploy do servidor, antes de qualquer agente sentir a mudança.
O servidor MCP é a fronteira de segurança. Ele autentica quem chama, aplica o menor privilégio por ferramenta e nunca entrega credenciais ao modelo.
Servidores de terceiros são código de terceiros: revise antes de conectar. As descrições das ferramentas vão direto para o contexto do modelo, então uma descrição maliciosa funciona como prompt injection (injeção de instrução). Em 2025, pesquisadores da Invariant Labs demonstraram esse ataque com o nome de “tool poisoning”: instruções escondidas na descrição de uma ferramenta levavam o agente a vazar dados de outra.
Os retornos também são conteúdo não confiável. Uma issue pública, um e-mail ou uma página lida por uma ferramenta pode carregar instruções para o agente. Isso é a injeção indireta descrita por Greshake et al. (2023). Veja Instruções Não Confiáveis e Reduzir Permissões da Ferramenta.
| Prós | Contras |
|---|---|
| Uma integração por sistema, usada por todos | Mais um serviço para operar |
| Troca de modelo ou cliente sem reescrever ferramentas | Um salto de rede a mais |
| Permissões e auditoria centralizadas | Servidor fora derruba vários agentes |
| Funciona com ferramentas de terceiros que falam MCP | Servidores de terceiros exigem revisão de segurança |
As duas abas criam um servidor MCP com uma ferramenta de leitura e uma de efeito, separadas por escopo.
Python. Use quando o time de plataforma escreve servidores em Python com o SDK oficial de MCP.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("erp") # 3. um servidor por sistema
@mcp.tool()
def find_order(order_id: str) -> dict:
"""Busca status, itens e datas de um pedido. Use quando o usuário citar um número de pedido."""
require_scope("orders:read") # 4. permissão do usuário que chamou
order = erp_client.get_order(order_id)
return { # 5. só campos úteis, formato estável
"id": order.id,
"status": order.status,
"delivered_at": order.delivered_at.isoformat() if order.delivered_at else None,
"items": [{"sku": i.sku, "qty": i.qty} for i in order.items],
}
@mcp.tool()
def create_return(order_id: str, reason: str) -> dict:
"""Cria uma devolução para um pedido entregue. Só use depois de o cliente confirmar a devolução."""
require_scope("returns:write")
audit_log("create_return", order_id=order_id, reason=reason)
label = erp_client.create_return(order_id, reason, idempotency_key=current_request_id())
return {"return_id": label.id, "label_url": label.url}
@mcp.resource("erp://policies/returns")
def returns_policy() -> str:
"""Política de trocas e devoluções vigente."""
return erp_client.get_policy("returns")
if __name__ == "__main__":
mcp.run() # stdio por padrão; para um servidor compartilhado, mcp.run(transport="streamable-http")O que você ganhou: qualquer cliente MCP passa a usar o ERP com o mesmo contrato e as mesmas permissões. O que você perdeu: require_scope e a identidade do usuário dependem do transporte e da sua autenticação; defina isso antes de expor o servidor.
TypeScript. Use quando o servidor roda em Node com o SDK oficial de MCP para TypeScript.
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: "erp", version: "1.4.0" });
server.registerTool(
"find_order",
{
description: "Busca status, itens e datas de um pedido. Use quando o usuário citar um número de pedido.",
inputSchema: { order_id: z.string().regex(/^\d+$/) },
},
async ({ order_id }) => {
requireScope("orders:read"); // 4
const o = await erp.getOrder(order_id);
const data = { id: o.id, status: o.status, delivered_at: o.deliveredAt, items: o.items.map((i) => ({ sku: i.sku, qty: i.qty })) };
return { content: [{ type: "text", text: JSON.stringify(data) }] }; // 5
},
);
server.registerTool(
"create_return",
{
description: "Cria uma devolução para um pedido entregue. Só use depois de o cliente confirmar a devolução.",
inputSchema: { order_id: z.string().regex(/^\d+$/), reason: z.string().max(500) },
},
async ({ order_id, reason }) => {
requireScope("returns:write");
await auditLog("create_return", { order_id, reason });
const label = await erp.createReturn(order_id, reason, { idempotencyKey: currentRequestId() });
return { content: [{ type: "text", text: JSON.stringify({ return_id: label.id, label_url: label.url }) }] };
},
);
await server.connect(new StdioServerTransport());O que você ganhou: o schema Zod valida a entrada no servidor, para qualquer cliente. O que você perdeu: o mesmo que em Python; autenticação e escopos precisam ser ligados ao transporte escolhido.
Adaptador MCP (MCP Adapter) é um padrão de projeto de IA para apps com LLM e agentes, do grupo Ferramentas e ação. Expor sistemas como servidores MCP para qualquer agente usar o mesmo contrato.
Ferramenta que Cospe HTML e Vazamento de Formato do Provedor.
Nos cenários reais Agente de código, Automação de back-office com execução durável e Chat com a base de conhecimento interna.