MCP: dando ferramentas a uma IA, com um servidor real
O protocolo MCP explicado com um servidor real, o do ArchFlow: quem fala com quem, o código peça por peça e como instalar e testar.
intermediárioPublicada em · 24 min de leitura
MCP (Model Context Protocol) é um protocolo aberto para dar ferramentas a uma IA. Em vez de só conversar, a IA passa a chamar funções suas: gerar um arquivo, consultar uma API, abrir um navegador. Quem expõe essas funções é um servidor MCP, um programa pequeno que você escreve.
Esta nota ensina o protocolo usando um servidor real, o do ArchFlow (tools/archflow/mcp.ts, no repositório svg-creator). Ele gera diagramas SVG animados a partir de texto, e foi ele (ou o CLI irmão dele) que desenhou todas as figuras daqui. As fontes .diagram ficam em assets/.
Ordem da nota: primeiro o protocolo (seções 1 a 4), depois a história de como o ArchFlow ganhou um MCP (5 a 7), o código peça por peça (8), como a IA usa as ferramentas (9) e como instalar e testar (10 e 11) e um checklist final (12). As seções 13 a 15 voltam ao protocolo com as perguntas que costumam cair em prova: o que o MCP acrescenta e o que não acrescenta (13), quando vale a pena usá-lo em vez de uma função direta (14) e como o cliente descobre tools, resources e prompts (15).
1. Quem fala com quem
- O host é o aplicativo onde a IA roda (Claude Code, Claude Desktop). Dentro dele mora o cliente MCP.
- O servidor MCP é o seu programa. Ele não fala com o usuário, só responde ao cliente.
- A IA decide quando usar uma ferramenta lendo o nome e a descrição que o servidor publicou. Por isso a descrição pesa tanto quanto o código.
Um servidor pode oferecer três coisas: tools (ações), resources (dados para ler) e prompts (roteiros prontos). O ArchFlow usa só tools, que cobrem a maior parte dos casos no começo.
2. A conversa por dentro
Cliente e servidor trocam mensagens JSON-RPC (JSON com method, params e id). Você quase nunca escreve isso à mão, o SDK cuida. Os quatro passos:
initialize: o cliente diz a versão do protocolo que fala, o servidor responde com o que sabe fazer.tools/list: o cliente pergunta quais ferramentas existem e recebe nome, descrição e o formato dos argumentos (JSON Schema).tools/call: a IA escolheu uma ferramenta e manda os argumentos.- Resultado: o servidor devolve conteúdo (texto, imagem) ou um erro marcado com
isError.
3. O menor servidor possível
pnpm add -D @modelcontextprotocol/sdk zod
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: 'ola', version: '0.1.0' });
server.registerTool(
'somar',
{
title: 'Somar dois números',
description: 'Soma a e b e devolve o resultado.',
inputSchema: { a: z.number(), b: z.number() },
},
async ({ a, b }) => ({ content: [{ type: 'text', text: String(a + b) }] })
);
await server.connect(new StdioServerTransport());
Cinco ideias aqui:
registerTool(nome, definição, função): o nome é o que a IA chama, a função é o que roda.inputSchemacom zod: o SDK converte para JSON Schema (o que o cliente lê notools/list) e valida os argumentos antes de chamar sua função. Argumento errado nem chega ao seu código.- O retorno é uma lista de
content:text,image(base64 emimeType) e outros tipos. - Transporte stdio: o cliente inicia o seu programa como processo filho e conversa pela entrada e saída padrão. Não há porta, servidor HTTP nem autenticação para configurar.
- Funções
asyncà vontade: o SDK espera a promessa.
4. A regra de ouro do stdio
No transporte stdio, o stdout é o canal do protocolo. Um único console.log("pronto") corrompe a conversa e o cliente derruba o servidor. Mensagens para humanos vão para o stderr:
const log = (message: string) => process.stderr.write(`[archflow-mcp] ${message}\n`);
Isso vale até para programas que você chama: no ArchFlow, a compilação do app (pnpm build) roda com stdio: ['ignore', 2, 2], ou seja, a saída dela vai para o stderr.
5. O problema que o ArchFlow resolve
O ArchFlow é um editor de diagramas (o projeto svg-creator) que lê e escreve um formato de texto:
diagrama "Load balancer"
direção LR
cliente = retângulo "Clientes" icon=lucide:monitor-smartphone
lb = ícone logos:aws-elb "Load Balancer"
cliente -> lb "HTTPS" anim=pacotes
Escrever isso é barato para uma IA, mas o resultado final (o SVG animado, com cartões, ícones e pacotes correndo nas arestas) só existia depois de abrir o app e clicar em Exportar. O objetivo era fechar esse buraco: a IA escreve o texto, o SVG aparece no disco, sem ninguém clicar.
A dificuldade é que o parser e o layout do formato de texto são TypeScript puro e rodam em Node, mas a exportação clona o DOM do React Flow. Sem navegador não há SVG.
6. Como foi construído: CLI antes do MCP
A primeira decisão foi não começar pelo MCP. O plano (docs/roadmap/TODO-archflow-cli.md) fez um CLI primeiro e deixou o MCP como última fase, por três motivos:
- O CLI é fácil de rodar e depurar no terminal. Um servidor MCP só se testa com um cliente conectado.
- Quase todo o trabalho (achar o Chrome, compilar o app, renderizar) é igual nos dois. Feito uma vez, o MCP vira uma casca fina.
- Os erros do CLI aparecem na tela. No MCP, um erro de stdout derruba a conexão sem aviso.
| Fase | O que entregou | O que ensinou |
|---|---|---|
| A. render | Ponte window.__archflow no app, servidor estático local, Chrome sem janela | O cartão tinha transition: all e a captura saía com o cartão escondido; a captura passou a esperar as transições acabarem |
| B. check e icons | Validar texto e achar ícones sem abrir navegador | Sanitizar o desenho de um ícone precisa de DOM, então o check só confere que o ícone existe |
| C. fundo transparente | SVG legível sobre fundo claro e escuro | Base escura opaca sob o vidro dos cartões e títulos de grupo em pílula |
| D. dia a dia | Pasta inteira, --if-newer, códigos de saída, trinco de compilação | Duas execuções juntas estragariam o dist uma da outra |
| E. documentação | Guia do CLI, colinha para a IA, README | A colinha tem teste que valida os exemplos dela |
| F. MCP | Quatro ferramentas sobre o mesmo núcleo | O que as seções 7 a 9 descrevem |
7. A arquitetura: duas portas, um núcleo
cli.ts e mcp.ts são duas entradas para as mesmas funções. Elas ficam em tools/archflow/, importam direto do src/ do app o que roda em Node (parser, layout, biblioteca de ícones) e usam o Chrome só para o que precisa de DOM.
O caminho de uma chamada a render_diagram:
- O
mcp.tsrecebe o texto e o caminho de saída. - A sessão (
session.ts) abre tudo o que o render exige, na primeira chamada: acha o Chrome, recompila o app se o código mudou, serve odist/numa porta local e abre um navegador sem janela. - O navegador carrega o app com
?archflow=1. Nesse modo, e só nele, o app expõewindow.__archflow.render(...). - O Node chama essa ponte com
page.evaluate. O app monta o diagrama a partir do texto, exporta com o mesmo código do botão Exportar e devolve o SVG (e um PNG, se pedirem prévia). - O Node grava o SVG no disco e responde ao cliente com um resumo.
8. O código, peça por peça
Todos os arquivos ficam em tools/archflow/. Cada um resolve um problema só.
| Arquivo | Papel |
|---|---|
mcp.ts | Registra as quatro ferramentas no SDK e liga o transporte stdio |
session.ts | Junta Chrome, compilação, servidor estático e navegador numa sessão com close() |
chrome.ts | Acha um Chromium já instalado (Chrome, Chromium, Brave, Edge) |
build.ts | Decide se o dist está velho e compila com trinco |
server.ts | Servidor HTTP mínimo para o dist/, só em 127.0.0.1 |
render.ts | Abre a página, espera a ponte ficar pronta e chama render |
check.ts | Valida o texto em Node, sem navegador |
icons.ts | Busca ícones na biblioteca em disco |
report.ts | Formata mensagens e diagnósticos com a linha |
Chrome sem baixar nada
Usa playwright-core, que traz a automação mas não baixa navegador. O chrome.ts procura os caminhos comuns de cada sistema. A variável ARCHFLOW_CHROME manda: se aponta para um arquivo que não existe, o programa avisa em vez de cair num navegador diferente sem ninguém saber.
O dist velho
build.ts compara a data do dist/index.html com a modificação mais recente de src/, public/ e index.html. Se o código é mais novo, roda pnpm build antes de renderizar. Para duas execuções simultâneas não compilarem ao mesmo tempo, usa um trinco: uma pasta em node_modules/.archflow-build.lock. Criar uma pasta é atômico, então só uma execução consegue. A outra espera, confere de novo se o dist já está bom e segue.
Servidor estático seguro
O server.ts resolve cada pedido para um caminho dentro do dist/ e recusa .., %2e%2e, barras invertidas e bytes nulos. Rotas sem extensão caem no index.html, como numa hospedagem de página única. Ele escuta só em 127.0.0.1, numa porta livre.
Ícones sem servidor
A biblioteca de ícones do app carrega seus dados com fetch("/icon-data/..."). No Node não existe servidor para responder. O installFileFetch troca o fetch global por uma versão que, para URLs que começam com /icon-data/, lê o arquivo de public/. O resto passa direto. Assim o mesmo código do app roda no Node sem mudanças. Hoje essa biblioteca tem mais de 39 mil ícones (Simple Icons, Logos, Lucide, Tabler, Phosphor, Material Design e Font Awesome), e a search_icons busca em todos.
Ponte com o app
src/archflowBridge.ts define o contrato (ArchflowRequest e ArchflowResult) que os dois lados importam, então o TypeScript confere a conversa entre o Node e a página. O pedido leva o texto, uma cor de fundo opcional e, se quiser prévia, a escala do PNG. O resultado traz ok, erros e avisos com a linha, a contagem de elementos e conexões, o SVG e o PNG em base64.
9. Como a IA usa as ferramentas
As quatro ferramentas formam um fluxo, e cada uma existe porque economiza uma volta inteira de tentativa e erro:
| Ferramenta | O que faz | Lição |
|---|---|---|
syntax_help | Devolve a colinha do formato (cheatsheet.md) | Dê à IA um manual curto; ela escreve melhor e gasta menos |
search_icons | Acha o nome exato de um ícone | Ferramentas pequenas e baratas evitam tentativa e erro |
check_diagram | Valida o texto sem navegador (cerca de 0,6 s) | Separe o que é barato do que é caro |
render_diagram | Gera o SVG animado e grava no disco | Resultado grande vai para o disco, não para o contexto da IA |
O caminho normal: ler a colinha uma vez, escrever o texto, procurar o nome dos ícones, validar, renderizar. Se a validação falha, a mensagem traz a linha e uma sugestão (diagrama:1: Esperava um id), e a IA corrige sem ajuda. Foi assim que as figuras desta nota nasceram: escritas, validadas, renderizadas com preview e ajustadas olhando o PNG (rótulos que ficavam cortados, por exemplo, foram encurtados).
Devolva pouco, grave o resto
O SVG tem de 50 a 200 KB. Se a ferramenta o devolvesse como texto, ocuparia o contexto da IA à toa. Então a render_diagram grava o arquivo em output e responde só com um resumo (2 elementos, 1 conexão, 45 KB). Para conferir o visual, a IA pede preview: true e recebe um PNG pequeno como image.
Erro útil faz parte da interface
return text(['Não gerou o SVG.', ...problems].join('\n'), true);
O segundo argumento liga isError. Compare com lançar uma exceção: o cliente só veria “erro interno” e a IA não teria o que corrigir.
Recurso caro: preguiçoso e compartilhado
Abrir um Chrome leva de 1 a 2 s. Por isso o servidor abre um navegador só, na primeira renderização, e reaproveita nas seguintes:
let queue: Promise<unknown> = Promise.resolve();
// ...
const run = queue.then(async () => renderTool(await getSession(), input));
queue = run.catch(() => undefined);
Duas chamadas simultâneas entram numa fila (uma promessa encadeada na outra), porque a página renderiza um diagrama por vez. O .catch na fila garante que uma falha não trava as próximas.
Separe a lógica do protocolo
renderTool, checkTool, iconsTool e syntaxTool são funções comuns e exportadas: recebem dados e devolvem um resultado. O createServer só as conecta ao SDK. Por isso dá para testá-las com Vitest sem subir MCP nenhum (tools/archflow/mcp.test.ts), e o CLI reaproveita as mesmas peças.
Limites de segurança
O servidor roda com as suas permissões, então ele se protege onde pode: render_diagram só grava arquivos .svg, o servidor estático só enxerga o dist/ e só escuta em 127.0.0.1, e o Chrome roda sem janela e sem baixar nada.
10. Registrar no Claude Code
Um arquivo .mcp.json na raiz do projeto basta:
{
"mcpServers": {
"archflow": {
"command": "pnpm",
"args": ["--silent", "archflow:mcp"]
}
}
}
O Claude Code pergunta se confia no servidor na primeira vez (ele vai rodar um comando na sua máquina, então a pergunta é séria). --silent impede o pnpm de imprimir cabeçalho no stdout. Também dá para registrar para o seu usuário inteiro: claude mcp add archflow -- pnpm --silent archflow:mcp, ou usar um caminho absoluto do projeto.
11. Testar sem depender da IA
O SDK traz um cliente. Um script de fumaça sobe o servidor como a IA faria e chama cada ferramenta:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
const client = new Client({ name: 'smoke', version: '1' });
await client.connect(
new StdioClientTransport({ command: 'pnpm', args: ['--silent', 'archflow:mcp'] })
);
console.log((await client.listTools()).tools.map((t) => t.name));
console.log(await client.callTool({ name: 'check_diagram', arguments: { text: 'a -> ' } }));
Foi assim que o servidor foi verificado: listou as quatro ferramentas, rejeitou um texto inválido com a linha do erro, achou logos:kafka e gerou um SVG de 45 KB com a prévia. Existe também o MCP Inspector (npx @modelcontextprotocol/inspector), uma interface web para chamar ferramentas na mão.
12. Checklist para o seu próximo servidor
- Nome e descrição pensados para a IA decidir bem (diga quando usar e o que devolve).
-
inputSchemacom zod e.describe()nos campos. - Nada no stdout além do protocolo.
- Resultados grandes em arquivo, resumo na resposta.
- Erros com
isErrore mensagem que diz como corrigir. - Recursos caros abertos sob demanda e fechados no
SIGINT/SIGTERM. - Lógica separada do SDK, com teste.
- Cuidado com segurança: o servidor roda com as suas permissões. Valide caminhos e extensões (a
render_diagramsó grava.svg).
13. O que o MCP acrescenta e o que ele não acrescenta
Pense no MCP como a tomada padrão de uma parede. Antes dela, cada aparelho vinha com um plugue próprio e cada casa precisava de um adaptador para cada aparelho. Com a tomada padronizada, qualquer aparelho que siga o formato funciona em qualquer parede. O que a tomada não faz é decidir se o aparelho pode ser ligado, nem impedir que ele seja uma gambiarra que pega fogo. Essa distinção é a resposta curta para a pergunta “o que o MCP acrescenta e o que não acrescenta”.
O que ele acrescenta é um formato comum. A especificação oficial o descreve como um protocolo aberto para integrar aplicações de LLM a fontes de dados e ferramentas, com mensagens JSON-RPC 2.0 entre host, cliente e servidor. Na prática, isso padroniza duas coisas: como o cliente descobre o que o servidor oferece (tools/list, resources/list, prompts/list) e como ele usa o que descobriu (tools/call, resources/read, prompts/get). Sem esse formato, quem escreve um host teria de aprender a API de cada serviço e quem escreve um serviço teria de fazer uma integração por host. Com ele, o servidor do ArchFlow que você viu nas seções anteriores funciona no Claude Code, no Claude Desktop ou em qualquer cliente que fale MCP, sem uma linha de código a mais.
O que ele não acrescenta é tudo o que decide se uma chamada deve acontecer e se ela é segura. A própria especificação diz que o MCP não consegue impor, no nível do protocolo, os princípios de segurança que ela recomenda. Ela os deixa para quem implementa o host e o servidor. Quatro consequências práticas:
- O MCP não dá permissão. Que o servidor anuncie uma ferramenta não significa que o modelo deva poder chamá-la. A especificação pede que o host obtenha consentimento explícito do usuário antes de invocar qualquer ferramenta, e recomenda que sempre haja um humano com poder de negar a chamada. Quem implementa essa tela de confirmação é o host (no Claude Code, é a pergunta que aparece antes de rodar a ferramenta).
- O MCP não substitui a validação. A especificação exige que o servidor valide todas as entradas das ferramentas, aplique controle de acesso, limite a taxa de chamadas e sanitize as saídas. O
inputSchemacom zod que você viu na seção 3 ajuda, mas ele só confere o formato (um número é um número). Dizer que um caminho de arquivo não escapa da pasta permitida, como orender_diagramfaz ao aceitar só.svg, continua sendo código seu. - O MCP não torna uma ferramenta segura. Uma ferramenta MCP é código arbitrário rodando com as permissões do processo. A especificação trata ferramentas como execução arbitrária de código e pede cautela proporcional. Um servidor MCP malfeito é tão perigoso quanto o mesmo código chamado sem MCP, com um agravante: ele é fácil de instalar.
- O MCP não garante que o texto que o servidor publica seja honesto. A especificação diz que descrições do comportamento de uma ferramenta, incluindo as anotações, devem ser tratadas como não confiáveis, a menos que venham de um servidor confiável. O nome e a descrição entram no contexto do modelo, então um servidor malicioso pode usá-los para tentar redirecionar o modelo (a prompt injection da nota Prompt e contexto chegando por outra porta).
Um exemplo concreto ajuda a separar as camadas. Imagine um servidor MCP com a ferramenta apagar_pasta. O protocolo cuida de listar a ferramenta, de entregar o argumento caminho e de devolver o resultado. Ele não pergunta se apagar aquela pasta é razoável, não confere se o caminho está dentro da área permitida e não pede a confirmação de ninguém. Cada uma dessas três coisas precisa existir em outro lugar: o host pede a confirmação, o servidor valida o caminho e o ambiente (usuário do sistema, container, permissões de arquivo) limita o estrago possível.
A tabela resume a divisão de trabalho.
| Pergunta | Quem responde |
|---|---|
| Que ferramentas existem e com que argumentos? | O protocolo (tools/list, inputSchema) |
| Como chamar e como receber o resultado? | O protocolo (tools/call, content, isError) |
| O usuário autorizou esta chamada? | O host (consentimento e confirmação) |
| O argumento é aceitável e o chamador pode fazer isto? | O servidor (validação e controle de acesso) |
| O que acontece se tudo der errado? | O ambiente (privilégios mínimos, isolamento) |
| A descrição da ferramenta é verdadeira? | Ninguém garante. Confie só em servidores que você escolheu confiar |
Um ponto de atualização sobre o estado do protocolo. Na consulta feita em 18/10/2026, a página principal da especificação aponta como revisão atual a de 2026-07-28. Nessa revisão não existe mais o handshake initialize descrito na seção 2: cada requisição carrega a versão do protocolo e as capacidades do cliente em metadados (_meta), e o servidor aceita ou recusa cada requisição por conta própria. Há ainda um método server/discover para o cliente descobrir de antemão as versões e capacidades do servidor. As revisões até 2025-11-25 usam o initialize, e a especificação descreve como clientes e servidores convivem entre as duas gerações. A seção 2 continua certa para essas revisões mais antigas, que são as que o SDK usado nos exemplos desta nota provavelmente fala. Não verifiquei qual revisão a versão instalada do @modelcontextprotocol/sdk implementa, então confira isso antes de depender de um dos dois comportamentos. Vale saber a ideia que não mudou: descoberta e chamada padronizadas, segurança por conta de quem implementa.
14. Quando usar MCP e quando uma função direta basta
O MCP tem custo. Há um processo extra para iniciar e vigiar, um protocolo para depurar, uma superfície de segurança nova (você está rodando o código de alguém, ou alguém roda o seu) e descrições de ferramentas que ocupam espaço no contexto do modelo a cada conversa. Esse custo se paga quando a padronização resolve um problema real. Quando não resolve, uma função comum é mais simples, mais rápida e mais fácil de testar.
O caso da função direta é o mais comum. Se a sua aplicação chama o Claude pela API de mensagens e quer que ele consulte o estoque, você descreve a ferramenta no pedido (nome, descrição e esquema de entrada), o modelo responde pedindo a chamada, o seu código executa uma função da própria aplicação e devolve o resultado na mensagem seguinte. Tudo acontece no mesmo processo, na mesma linguagem, com os mesmos tipos e o mesmo teste unitário de sempre. Colocar um servidor MCP no meio dessa conversa só acrescentaria um processo, uma serialização e uma fonte de falhas, sem que ninguém mais se beneficiasse da padronização.
O MCP começa a valer a pena quando aparece pelo menos uma destas situações:
- A mesma capacidade precisa servir vários clientes. Um único servidor atende o Claude Code, um editor e uma aplicação interna. Sem MCP, você escreveria uma integração para cada um.
- O dono da capacidade é outra pessoa ou outro time. Quem mantém a integração com o Jira publica um servidor, e quem constrói o agente apenas o conecta. A fronteira de processo e de contrato fica explícita.
- A ferramenta vive em outra linguagem ou outro ambiente. O ArchFlow é TypeScript, mas o cliente que o usa não precisa ser.
- O usuário final deve poder plugar capacidades por conta própria, sem você alterar o código da aplicação. É o caso de um host genérico como o Claude Code, que não conhece de antemão as ferramentas que você vai querer.
- Você quer um servidor de terceiros já pronto, em vez de escrever a integração.
O próprio ArchFlow mostra o raciocínio. A seção 6 conta que o CLI veio antes e que o MCP foi uma casca fina sobre o mesmo núcleo. O núcleo (renderTool, checkTool) é função direta e poderia ser chamado de qualquer programa TypeScript. O MCP entrou porque o objetivo era que um host que você não controla, o Claude Code, usasse essas funções sem que ele soubesse nada sobre o projeto.
Há um detalhe da plataforma da Anthropic que muda a conta. O conector MCP da API de mensagens (em beta na consulta de 18/10/2026, com o cabeçalho mcp-client-2025-11-20) permite ligar servidores MCP remotos direto na requisição, sem escrever um cliente MCP. A documentação lista duas limitações: dos recursos da especificação, apenas as chamadas de ferramenta são suportadas, e o servidor precisa estar exposto publicamente por HTTP (Streamable HTTP ou SSE). Servidores locais em stdio, como o do ArchFlow, não se conectam por esse caminho. Se você precisa de resources ou prompts, ou de um servidor local, o cliente MCP tem de estar no seu código ou no host (por exemplo o Claude Code).
Uma regra de bolso para decidir: pergunte quantos clientes diferentes vão usar a capacidade e quem controla o código dos dois lados. Um cliente, um dono, uma linguagem: função direta. Vários clientes, donos diferentes ou fronteira de linguagem: MCP.
15. Os três tipos de recurso do protocolo e como o cliente os descobre
Na seção 1 a nota disse que um servidor pode oferecer tools, resources e prompts. Falta explicar o que os separa. A diferença que a especificação destaca não é o formato dos dados, e sim quem decide quando cada um é usado. Isso importa porque determina onde o consentimento e a confirmação precisam aparecer.
As ferramentas (tools) são controladas pelo modelo. O modelo lê nome e descrição, decide que precisa de uma e pede a chamada. Servem para agir ou calcular: gravar um arquivo, consultar uma API, renderizar um SVG. Os recursos (resources) são controlados pela aplicação. São dados identificados por um URI, como file:///projeto/src/main.rs, que o host escolhe incorporar ao contexto, seja porque o usuário os selecionou numa lista, seja por uma heurística do próprio host. Servem para dar material de leitura: um arquivo, um esquema de banco, um histórico do git. Os prompts são controlados pelo usuário. São modelos de mensagem com argumentos, que o usuário escolhe explicitamente, o exemplo clássico sendo um comando de barra. Servem para entregar um roteiro pronto, como “revise este código” com o trecho já encaixado.
| Tipo | Quem decide usar | Para quê | Descoberta | Uso |
|---|---|---|---|---|
| Tool | O modelo | Executar ação ou cálculo | tools/list | tools/call |
| Resource | A aplicação (host) | Fornecer dados de contexto | resources/list e resources/templates/list | resources/read |
| Prompt | O usuário | Oferecer um roteiro de mensagem pronto | prompts/list | prompts/get |
A descoberta funciona em duas etapas, e é essa a mecânica que a prova costuma cobrar. Primeiro o servidor declara, nas capacidades, quais dos três tipos ele suporta (tools, resources, prompts), e cada declaração pode dizer se o servidor avisa quando a lista muda (listChanged). Os recursos têm ainda a opção subscribe, para acompanhar mudanças de um recurso específico. Depois o cliente pede a lista do que lhe interessa. Cada item traz o necessário para decidir se vale usá-lo: uma ferramenta traz nome, descrição e inputSchema (e pode trazer outputSchema); um recurso traz URI, nome, descrição e tipo MIME; um prompt traz nome, descrição e a lista de argumentos. As listas aceitam paginação por cursor, e a revisão atual também prevê dicas de cache (ttlMs e cacheScope) para o cliente não repetir a pergunta à toa.
Os recursos têm uma variação a mais: os modelos de recurso (resource templates), listados por resources/templates/list. Em vez de um URI fixo, o servidor publica um padrão como file:///{path}, e o cliente preenche a parte variável. É a forma de oferecer “qualquer arquivo do projeto” sem listar cada um.
Quando a lista muda no meio da sessão (um plugin foi ligado, um arquivo novo apareceu), o servidor que declarou listChanged envia uma notificação (notifications/tools/list_changed, e as equivalentes para recursos e prompts), e o cliente pede a lista de novo. Na revisão de 2026-07-28, o cliente que quer receber essas notificações abre antes um fluxo com subscriptions/listen. Não verifiquei como as revisões anteriores entregavam essas notificações, então confira a revisão que o seu SDK implementa antes de codificar isso.
Um ponto de projeto que a especificação deixa claro: a lista pode variar conforme a autorização apresentada na requisição (por exemplo, só as ferramentas que os escopos do chamador permitem), mas não pode variar conforme a conexão nem como efeito colateral de outras chamadas. Isso evita servidores que mudam de comportamento por estado escondido, e combina com o princípio de que o MCP não tem sessão de protocolo na revisão atual. Se uma ferramenta precisa de estado entre chamadas (um carrinho de compras, por exemplo), o guia da especificação sugere devolver um identificador explícito numa ferramenta de criação e pedi-lo como argumento nas chamadas seguintes, com o modelo carregando o identificador adiante.
Aplicando ao ArchFlow: as quatro ferramentas são tools porque é o modelo quem decide quando validar, buscar ícone ou renderizar. A syntax_help entrega um texto fixo, e isso a faz parecer um recurso. Ela é uma tool por escolha de projeto: assim o modelo pode buscar a colinha quando perceber que precisa, em vez de depender de o host ter anexado o recurso. Um prompt faria sentido para um roteiro como “desenhe a arquitetura deste repositório”, escolhido pelo usuário. Este exemplo é uma sugestão minha de desenho, não algo que o ArchFlow implemente hoje.
O que não consegui confirmar nesta consulta: quais hosts e clientes específicos, além do conector da API, expõem recursos e prompts ao usuário, e de que forma. A especificação deixa isso a critério da implementação (diz que o protocolo não impõe um modelo de interação), então a experiência varia de cliente para cliente. Teste com o seu cliente antes de assumir que um recurso ou prompt vai aparecer.
Fontes consultadas em 18/10/2026
- Especificação do MCP, revisão 2026-07-28: visão geral, servidor, ferramentas, recursos, prompts e versionamento (modelcontextprotocol.io/specification/2026-07-28).
- Documentação da Anthropic, conector MCP da API de mensagens (platform.claude.com/docs/en/agents-and-tools/mcp-connector).
Relacionados
- concorrência
- Arquitetura orientada a eventos
- Agents
- Prompt e contexto