Software · Arquitetura & Engenharia de Dados
Model Context Protocol (MCP) por Dentro: Host, Client, Server e JSON-RPC
Como o protocolo aberto da Anthropic padroniza a exposição de ferramentas, recursos e prompts para modelos de linguagem: ciclo de vida de conexões, transporte, negociação de capacidades e segurança de execução.
Neste artigo
Antes do surgimento de padrões de comunicação dedicados, conectar modelos de linguagem a bancos de dados, terminais e APIs corporativas dependia de integrações proprietárias. Cada fornecedor de agentes definia seu próprio formato de function calling, obrigando equipes de engenharia a reescrever código de integração sempre que alteravam a ferramenta de execução ou o modelo subjacente.
O Model Context Protocol (MCP), anunciado pela Anthropic e adotado rapidamente por ecossistemas abertos de agentes, resolve essa fragmentação através de um contrato cliente-servidor padronizado. Inspirado na simplicidade que o Language Server Protocol (LSP) trouxe para compiladores e editores de código, o MCP separa a responsabilidade de quem orquestra o raciocínio da responsabilidade de quem fornece o acesso físico aos recursos do ambiente.
flowchart LR
subgraph HostApp["Aplicação Host (Claude Desktop, IDE, CLI)"]
LLM["Modelo / Agente"]
Client["Cliente MCP"]
LLM <--> Client
end
subgraph Transports["Camada de Transporte"]
Stdio["Stdio (Processo Local)"]
SSE["Streamable HTTP / SSE (Remoto)"]
end
subgraph MCPServers["Servidores MCP"]
SrvGit["MCP Git / Filesystem"]
SrvDB["MCP Postgres / SQLite"]
SrvAPI["MCP REST / GraphQL"]
end
Client <--> Stdio <--> SrvGit
Client <--> Stdio <--> SrvDB
Client <--> SSE <--> SrvAPI
A Topologia de Três Camadas
A arquitetura do MCP divide o ecossistema em três participantes com fronteiras de isolamento bem delimitadas:
- Host: A aplicação de interface direta com o usuário final (como uma IDE, um terminal interativo ou o Claude Desktop). O Host gerencia o ciclo de vida do modelo de IA, define políticas de segurança e autoriza ou bloqueia cada ação solicitada.
- Client: A biblioteca dentro do Host que mantém a conexão 1:1 com cada servidor. O cliente descobre capacidades, formata as requisições em conformidade com a especificação e injeta o contexto recebido no prompt do modelo.
- Server: Um processo leve (executado localmente via subprocesso ou remotamente via HTTP) que expõe ferramentas executáveis, recursos de leitura ou instruções prontas de prompt.
| Primitiva MCP | Direção | Finalidade Principal | Exemplo Prático |
|---|---|---|---|
| Tools | Modelo → Servidor | Funções executáveis com efeitos colaterais controlados | Rodar um comando git, executar uma query SQL, disparar um deploy |
| Resources | Servidor → Modelo | Dados contextuais passivos, lidos sob demanda como arquivos | Ler o conteúdo de um arquivo .env, inspecionar o schema de tabelas |
| Prompts | Servidor → Modelo | Modelos reutilizáveis de instrução pré-empacotados | Template de revisão de código, roteiro de depuração de logs |
| Sampling | Servidor → Host | Servidor requisita que o Host faça uma inferência via LLM | Servidor de banco pedindo resumo de telemetria sem expor credenciais |
O Protocolo no Fio: JSON-RPC 2.0
Toda a troca de mensagens ocorre em JSON-RPC 2.0. Esse formato garante que chamadas de métodos, retornos síncronos e notificações assíncronas trafeguem sem a necessidade de parsing binário proprietário.
1. Inicialização e Negociação de Capacidades
Quando o Host inicia um servidor, o primeiro passo é o aperto de mão (handshake) para registrar versões e recursos suportados:
// Requisição enviada pelo Cliente
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": { "listChanged": true },
"sampling": {}
},
"clientInfo": {
"name": "DATAXSTUDIOS-AgentRunner",
"version": "1.0.0"
}
}
}
O servidor responde confirmando a versão aceita e listando quais primitivas ele oferece:
// Resposta do Servidor
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": true }
},
"serverInfo": {
"name": "dxs-database-inspector",
"version": "0.4.2"
}
}
}
Após o handshake, o cliente envia uma notificação notifications/initialized, liberando o fluxo de dados.
2. Descoberta e Execução de Ferramentas
O modelo precisa conhecer os schemas de validação antes de invocar qualquer ação. O cliente envia tools/list e recebe um array de definições no padrão JSON Schema:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "execute_query",
"arguments": {
"sql": "SELECT id, status, total_amount FROM orders WHERE created_at >= NOW() - INTERVAL '24 hours'",
"readOnly": true
}
}
}
Caso o Host tenha políticas de aprovação humana, a interface pausa a execução neste momento e solicita consentimento antes de entregar o payload ao subprocesso do servidor.
Mecanismos de Transporte: Stdio vs Streamable HTTP
A especificação contempla dois modos principais de transporte físico:
sequenceDiagram
participant H as Host / Cliente
participant S as Servidor MCP (Processo Filho)
Note over H,S: Transporte via Standard Streams (stdio)
H->>S: Spawna processo filho stdin/stdout
H->>S: Envia initialize via stdin
S-->>H: Responde resultado via stdout
H->>S: Envia tools/call com argumentos
S-->>H: Retorna conteúdo formatado em stdout
- Stdio (Standard Input / Output): Ideal para servidores locais. O Host inicia o processo executável como filho e comunica-se enviando strings JSON terminadas por quebra de linha em
stdine lendo as respostas emstdout. Registros de log devem ser direcionados parastderrpara não corromper o canal de dados. - Streamable HTTP / SSE: Utilizado quando o servidor MCP reside em outro nó da rede ou dentro de um cluster. As requisições trafegam por POST HTTP padrão, enquanto notificações em tempo real e respostas longas utilizam Server-Sent Events (SSE).
Construindo um Servidor Prático com TypeScript
Com o SDK oficial @modelcontextprotocol/sdk, implementar um servidor que expõe métricas de disco e execução de scripts exige poucas linhas:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { execSync } from "node:child_process";
const server = new Server(
{ name: "dxs-system-ops", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// Registra as ferramentas disponíveis
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "get_disk_usage",
description: "Retorna a porcentagem de espaço ocupado em disco.",
inputSchema: {
type: "object",
properties: {
path: { type: "string", description: "Ponto de montagem" }
},
required: ["path"]
}
}
]
}));
// Executa a chamada validando os argumentos
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "get_disk_usage") {
const targetPath = String(request.params.arguments?.path ?? "/");
const output = execSync(`df -h "${targetPath}"`).toString("utf8");
return {
content: [
{ type: "text", text: output.trim() }
]
};
}
throw new Error(`Ferramenta não reconhecida: ${request.params.name}`);
});
// Conecta ao canal de entrada e saída padrão
const transport = new StdioServerTransport();
await server.connect(transport);
Implicações de Segurança e Fronteiras de Confiança
Como os servidores MCP operam com permissões no sistema operacional, a adoção do protocolo exige três salvaguardas essenciais:
- Princípio do Menor Privilégio: Servidores locais devem rodar com credenciais restritas, sem privilégios administrativos. Ferramentas que gravam arquivos devem validar caminhos para prevenir ataques de path traversal.
- Confirmação Humana Explícita: Ferramentas com efeitos irreversíveis (como envio de e-mails, mutações em bancos de produção ou destruição de containers) nunca devem ser acionadas de forma 100% autônoma pelo cliente.
- Resistência a Prompt Injection Indireto: Ao ler recursos externos via
resources/read, dados não confiáveis (como páginas HTML ou repositórios públicos) podem conter instruções maliciosas destinadas a manipular o comportamento do modelo.