MCP explicado pela especificação: o que um servidor realmente é
Uma linha de JSON em um subprocesso retorna 13 definições de ferramenta, lida pela revisão 2026-07-28 que removeu o handshake.
Nesta página
Instale um servidor MCP publicado, envie uma linha de JSON e leia o que volta.
npm i @modelcontextprotocol/server-everything@2026.8.31
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| npx @modelcontextprotocol/server-everything stdio{"result":{"tools":[{"name":"echo","title":"Echo Tool","description":"Echoes
back the input string","inputSchema":{"$schema":"http://json-schema.org/draft-07/
schema#","type":"object","properties":{"message":{"type":"string","description":
"Message to echo"}},"required":["message"]},"annotations":{"readOnlyHint":true,
… … 7,663 bytes on one line …
"jsonrpc":"2.0","id":1}Treze definições de ferramenta, em uma única linha, vindas de um processo que leu uma linha da sua entrada padrão. Você acabou de falar o Model Context Protocol, sem SDK, sem biblioteca cliente e sem framework. É isso tudo: um transporte, um formato de mensagem e um pequeno conjunto de métodos nomeados.
Capítulo 18 definiu uma ferramenta como duas coisas — um JSON Schema que o modelo vê e um endpoint no seu código que o modelo nunca vê. Capítulo 23 construiu um harness que mantém um catálogo delas. Nenhum dos dois respondeu à pergunta que decide se algo disso é reutilizável: quem escreve o schema, e como ele sai de quem o escreveu e entra no seu prompt? MCP é uma resposta para essa pergunta, e vale a pena lê-la no original, porque quase tudo que foi escrito sobre ele descreve uma revisão que não existe mais.
Três coisas sobre o comando que você acabou de executar estão erradas, e cada uma delas é uma seção deste capítulo. Ele não carregava versão de protocolo, então um servidor conforme teria recusado. Mesmo assim recebeu uma resposta, por um motivo que a especificação chama de risco, não de recurso. E ele pediu uma de três primitivas sem jamais descobrir que as outras duas existem.
O problema que ele resolve, e a analogia que a própria especificação faz
Link para a seção: O problema que ele resolve, e a analogia que a própria especificação fazAntes do wire, a aritmética. Você tem aplicações de IA e coisas que elas deveriam conseguir acessar — um calendário, um rastreador de tickets, um banco de dados de warehouse, uma ferramenta de design. Sem um contrato compartilhado, alguém escreve integrações, e cada uma delas é um schema mais um endpoint mais uma história de autenticação mais um fardo de manutenção. Com um contrato, o fornecedor da ferramenta escreve um servidor, o fornecedor da aplicação escreve um cliente, e o total é .
Isso não é uma observação nova, e a especificação diz de quem foi a ideia:
MCP takes some inspiration from the Language Server Protocol, which standardizes how to add support for programming languages across a whole ecosystem of development tools. In a similar way, MCP standardizes how to integrate additional context and tools into the ecosystem of AI applications.1
Leve essa comparação ao pé da letra, não como elogio. Antes daquele protocolo, dar suporte a uma linguagem em um editor significava um plugin por editor; depois, uma equipe de linguagem entregava um servidor e todo editor passava a tê-lo. A medida de sucesso não era elegância, era que a contagem de integrações parava de se multiplicar. O mesmo vale aqui: o valor está no número de implementações, não no design. Um protocolo que dois produtos falam é um formato de dados com cerimônia extra.
O que está de fato no wire
Link para a seção: O que está de fato no wireMensagens MCP são JSON-RPC 2.0. Uma solicitação é um objeto com jsonrpc, um id, um method e params opcional; uma resposta carrega o mesmo id e ou result ou error; uma notificação é uma solicitação sem id e não recebe resposta. A especificação acrescenta três restrições: o id deve ser uma string ou um número e não deve ser null, não deve colidir com outra solicitação ainda em andamento, e todo resultado deve carregar um campo resultType.2
No transporte stdio — o que o comando acima usou — a regra de framing é uma linha por mensagem:
Messages are delimited by newlines, and MUST NOT contain embedded newlines. […] The server MUST NOT write anything to its
stdoutthat is not a valid MCP message.3
Essa última cláusula é a forma mais comum de um servidor caseiro quebrar, e ele quebra silenciosamente: um console.log perdido, uma barra de progresso, um aviso de depreciação de uma dependência, e o parser de linhas do cliente encontra algo que não é JSON. A válvula de escape está na mesma seção — o servidor pode escrever o que quiser em stderr, e o cliente não deve tratar isso como erro. O servidor de referência acima imprime Starting default (STDIO) server... em toda inicialização, em stderr, e é por isso que o pipe ainda funcionou.
O outro transporte padrão é Streamable HTTP: cada mensagem é um POST para um único endpoint, e a resposta é ou um objeto JSON ou um stream de Server-Sent Events com escopo da solicitação — o formato de wire que o Capítulo 14 analisou à mão. A semântica é idêntica nos dois, porque um transporte é um binding: ele define framing e entrega, não significado.4
A primeira coisa que estava errada: não havia versão
Link para a seção: A primeira coisa que estava errada: não havia versãoO comando acima enviou tools/list e nada mais. Pela revisão atual, essa solicitação é malformada, e um servidor conforme deve rejeitá-la.
Desde 2026-07-28, MCP é um protocolo sem estado, e a especificação afirma isso sem ressalvas:
The Model Context Protocol (MCP) is a stateless protocol: all the information needed to process a request is contained in the request itself. A server processes each request independently; no state should be inferred from previous requests, even those on the same connection or stream.2
Então toda solicitação carrega sua própria versão de protocolo e suas próprias capacidades de cliente, em um objeto reservado _meta dentro de params. Dois desses campos são obrigatórios em toda solicitação; uma solicitação sem qualquer um deles é malformada e o servidor deve responder -32602:2
chave _meta | obrigatória | o que é |
|---|---|---|
io.modelcontextprotocol/protocolVersion | sim | a revisão que esta solicitação fala, por exemplo "2026-07-28" |
io.modelcontextprotocol/clientCapabilities | sim | o que o cliente pode fazer pelo servidor nesta solicitação |
io.modelcontextprotocol/clientInfo | não (mas deveria) | nome e versão do cliente, apenas para exibição e logs |
io.modelcontextprotocol/logLevel | não | o nível mínimo de log que o servidor deve emitir para esta solicitação |
Por extenso, um tools/list correto é isto — e é a última vez que este capítulo mostra os metadados completos, porque eles aparecem em toda solicitação daqui em diante:
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{"elicitation":{"form":{}}},
"io.modelcontextprotocol/clientInfo":{"name":"bare-hands","version":"0.0.1"}}}}O objeto de capacidades é a negociação. Não existe mais uma etapa separada de negociação: o cliente declara o que consegue fazer em cada solicitação, o servidor declara o que consegue fazer no resultado, e nenhum lado pode usar um recurso que o outro não declarou. Um servidor que precisa de uma capacidade que o cliente não declarou deve responder -32021 e nomear a capacidade ausente em data.requiredCapabilities. Um servidor que não fala a versão solicitada deve responder -32022 e listar as versões que fala.2
Clientes que querem a resposta de antemão podem pedi-la: server/discover é um RPC obrigatório que retorna versões compatíveis, capacidades, identidade e um bloco opcional de instructions em uma ida e volta.5 Chamá-lo é opcional. Implementá-lo não é.
A segunda coisa que estava errada: o servidor era legacy
Link para a seção: A segunda coisa que estava errada: o servidor era legacyO comando funcionou. Pela revisão atual, não deveria, e o motivo merece uma medição em vez de um parágrafo, porque é o estado do ecossistema inteiro em uma linha.
Sonde o servidor de referência do jeito que a especificação manda um cliente moderno sondar:
echo '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{}}}}' \
| npx @modelcontextprotocol/server-everything stdio{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}Esse é o terceiro ramo da regra de compatibilidade: um DiscoverResult significa moderno, um erro moderno reconhecido significa moderno-mas-versão-errada, e qualquer outra coisa — incluindo -32601 — significa legacy, volte para o handshake initialize.3 Então faça isso, pedindo a revisão atual:
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-07-28",
"capabilities":{},"clientInfo":{"name":"bare-hands","version":"0.0.1"}}}
← {"result":{"protocolVersion":"2025-11-25","capabilities":{"tools":{"listChanged":true},
"prompts":{"listChanged":true},"resources":{"subscribe":true,"listChanged":true},
"logging":{},"tasks":{…},"completions":{}},"serverInfo":{"name":"mcp-servers/everything",
"title":"Everything Reference Server","version":"2.0.0"},"instructions":"…"}}O cliente pediu 2026-07-28 e o servidor respondeu 2025-11-25. Em 7 de setembro de 2026, o servidor oficial de referência — pacote npm @modelcontextprotocol/server-everything, versão 2026.8.31, publicado em 31 de agosto de 2026 — não implementa a revisão atual. O TypeScript SDK em que ele se baseia também não, pelas datas: a release 1.30.0 saiu em 27 de julho de 2026, um dia antes da revisão.
Leia a consequência, não a fofoca. Quase tudo escrito sobre MCP descreve um protocolo com um handshake initialize, uma sessão, uma solicitação roots/list que o servidor envia ao cliente e um transporte HTTP+SSE. Todos os quatro sumiram ou estão sumindo. Quando você ler qualquer coisa sobre MCP, incluindo esta página, a primeira coisa a procurar é um número de revisão.
E o motivo pelo qual o primeiro comando funcionou é declarado na especificação como um risco, não um recurso:
some legacy servers do not validate that a request arrives after
initializeand would process an era-ambiguous method (such astools/call) under legacy semantics. Probing yields a deterministic failure instead.3
Medição: enviar tools/list para esse servidor sem handshake algum retorna o catálogo completo. Um método que deveria ter sido recusado foi atendido, exatamente por isso a especificação diz para sondar com server/discover primeiro, mesmo quando você só oferece suporte a versões modernas.
Três papéis, e a frase para citar do documento inteiro
Link para a seção: Três papéis, e a frase para citar do documento inteiroMCP tem três partes, e a distinção entre as duas primeiras é a que as pessoas misturam:
Host. A aplicação: o produto de chat, o editor, o agent. Ele é dono da conversa, do modelo, das credenciais e do consentimento do usuário. Ele cria clientes e impõe a fronteira de segurança entre eles.
Cliente. Um conector dentro do host. Cada cliente fala com exatamente um servidor — uma relação 1:1 estrita — e anexa a versão do protocolo e as capacidades a toda solicitação que roteia.
Servidor. Um processo ou serviço que expõe resources, ferramentas e prompts. Ele pode ser local ou remoto, opera de forma independente, e seu trabalho inteiro é uma área focada.6
Essa regra de “exatamente um servidor” não é burocracia. É o que torna implementável o princípio de design abaixo, e esta é a frase a levar da especificação se você levar apenas uma:
Servers should not be able to read the whole conversation, nor “see into” other servers. Servers receive only necessary contextual information. Full conversation history stays with the host. Each server maintains isolation. Cross-server interactions are controlled by the host.6
Isso vira de cabeça para baixo o modelo mental com que a maioria das pessoas chega. Um servidor de clima que você conecta ao seu assistente não vê o que você perguntou. Ele vê um tools/call com os argumentos que o modelo escolheu, e nada mais — não os turnos anteriores, não o seu system prompt, não os resultados que o servidor de calendário retornou um instante antes. Se dois servidores precisam cooperar, o host carrega um valor de um para o outro, deliberadamente, porque o modelo pediu. É por isso que o isolamento é a propriedade de segurança em que o Capítulo 30 se apoia: um servidor comprometido tem um raio de explosão pequeno e definido, e ampliá-lo exige que o host coopere.
A terceira coisa: três primitivas, ordenadas por quem manda
Link para a seção: A terceira coisa: três primitivas, ordenadas por quem mandaO primeiro comando pediu tools a esse servidor e recebeu treze. Faça as outras duas perguntas e ele também responde: resources/list retorna sete, prompts/list retorna quatro. Nenhuma delas apareceu, porque nada perguntou. Isso nos leva à espinha pedagógica do MCP, escondida na especificação como uma tabela que quase ninguém cita:
| Primitiva | Controle | Descrição | Exemplo |
|---|---|---|---|
| Prompts | Controlado pelo usuário | Templates interativos invocados por escolha do usuário | Comandos slash, opções de menu |
| Resources | Controlado pela aplicação | Dados contextuais anexados e gerenciados pelo cliente | Conteúdo de arquivos, histórico do git |
| Tools | Controlado pelo modelo | Funções expostas ao LLM para executar ações | Solicitações POST de API, escrita de arquivos |
Não são “três formas de expor uma capacidade”. São três respostas para quem decide que isso acontece. O modelo decide chamar uma ferramenta. A aplicação decide anexar um resource. A pessoa decide executar um prompt. Entenda isso errado e o recurso ainda funciona, mas funciona no momento errado e pelo motivo errado.
A forma mais clara de sentir isso é um calendário. Aqui está um servidor que expõe o mesmo calendário três vezes, uma como cada primitiva, em cem linhas de Node puro sem dependências:
const TOOL = {
name: "create_event",
description: "Create a calendar event. Writes to the calendar.",
inputSchema: {
type: "object",
properties: {
title: { type: "string", description: "Event title." },
startsAt: { type: "string", format: "date-time", description: "Start, ISO 8601 UTC." },
},
required: ["title"],
},
};
switch (method) {
case "resources/read":
return ok(id, { contents: [{ uri: "calendar://week",
mimeType: "application/json", text: JSON.stringify(EVENTS) }],
ttlMs: 60000, cacheScope: "private" });
case "prompts/get":
return ok(id, { description: PROMPT.description, messages: [{ role: "user",
content: { type: "text", text: `Read calendar://week and draft a plan. ` +
`Focus: ${params.arguments?.focus ?? "balance"}.` } }] });
case "tools/list":
return ok(id, { tools: [TOOL], ttlMs: 300000, cacheScope: "public" });
}Execute e pergunte das três formas. Saída real, uma mensagem por linha no wire, quebrada aqui para a página, com a solicitação _meta e o bloco de identidade do servidor omitidos:
→ resources/read {"uri":"calendar://week"}
← {"resultType":"complete","contents":[{"uri":"calendar://week",
"mimeType":"application/json","text":"[{\"id\":\"e1\",\"title\":\"Standup\",
\"startsAt\":\"2026-09-07T09:00:00Z\"},{\"id\":\"e2\",\"title\":\"Design review\",
\"startsAt\":\"2026-09-09T15:00:00Z\"}]"}],"ttlMs":60000,"cacheScope":"private"}
→ prompts/get {"name":"prepare_week","arguments":{"focus":"deep work"}}
← {"resultType":"complete","description":"Read the week and draft a plan.",
"messages":[{"role":"user","content":{"type":"text",
"text":"Read calendar://week and draft a plan. Focus: deep work."}}]}
→ tools/call {"name":"create_event","arguments":{"title":"Dentist",
"startsAt":"2026-09-10T08:30:00Z"}}
← {"resultType":"complete","content":[{"type":"text",
"text":"Created e3: Dentist at 2026-09-10T08:30:00Z"}],
"structuredContent":{"id":"e3","title":"Dentist","startsAt":"2026-09-10T08:30:00Z"},
"isError":false}Três métodos, três formatos, um calendário. Agora o ponto:
Ler a semana é um resource
Link para a seção: Ler a semana é um resourceEle é endereçado por uma URI, é inerte, e a aplicação decide se deve anexá-lo à conversa. Nada no protocolo permite que o modelo o busque por conta própria. O resultado carrega ttlMs e cacheScope, novos nesta revisão, para que o cliente possa colocar a semana em cache por um minuto em vez de ficar fazendo polling.
Criar um evento é uma ferramenta
Link para a seção: Criar um evento é uma ferramentaEla tem um schema, tem efeitos colaterais, e o modelo decide quando chamá-la. Seu resultado carrega isError, que é o campo defendido no Capítulo 18: uma falha de validação volta como um resultado de ferramenta que o modelo consegue ler e corrigir, não como um erro de protocolo.
“Prepare minha semana” é um prompt
Link para a seção: “Prepare minha semana” é um promptÉ um template nomeado, com argumentos, que a pessoa invoca — o comando slash no menu. Ele retorna mensagens, não uma resposta. É uma forma de o autor do servidor entregar a formulação que funciona com suas próprias ferramentas, que é exatamente o conhecimento que o autor do servidor tem e o usuário não.
Quase todo mundo transforma as três coisas em tools. O resultado é um catálogo em que uma leitura que a aplicação deveria ter anexado silenciosamente compete pela attention do modelo com uma escrita que precisa de aprovação, e em que a única coisa para a qual uma pessoa queria um botão fica enterrada em um schema. Não custa nada acertar, e isso é decidido antes de você escrever uma linha.
O servidor não pode chamar você
Link para a seção: O servidor não pode chamar vocêA ferramenta de calendário tem um argumento obrigatório, title, e um opcional, startsAt. Peça para ela criar um evento sem data, e algo interessante volta:
→ tools/call {"name":"create_event","arguments":{"title":"Dentist"}}
← {"resultType":"input_required",
"inputRequests":{"when":{"method":"elicitation/create","params":{"mode":"form",
"message":"When should \"Dentist\" start?",
"requestedSchema":{"type":"object",
"properties":{"startsAt":{"type":"string","format":"date-time"}},
"required":["startsAt"]}}}},
"requestState":"eyJ0aXRsZSI6IkRlbnRpc3QifQ=="}O servidor não enviou uma solicitação. Ele respondeu à que recebeu, com resultType: "input_required" e uma descrição do que ainda precisa. O cliente coleta a resposta da pessoa e então reenvia a chamada original — com um novo id, carregando inputResponses e ecoando de volta o requestState opaco:
→ tools/call {"name":"create_event","arguments":{"title":"Dentist"},
"inputResponses":{"when":{"action":"accept",
"content":{"startsAt":"2026-09-10T08:30:00Z"}}},
"requestState":"eyJ0aXRsZSI6IkRlbnRpc3QifQ=="}
← {"resultType":"complete","content":[{"type":"text",
"text":"Created e3: Dentist at 2026-09-10T08:30:00Z"}],"isError":false}Isso é Multi Round-Trip Requests, introduzido na revisão atual, e substituiu o design antigo em que servidores enviavam solicitações JSON-RPC de volta para clientes. A especificação de transporte agora declara a regra sem rodeios: “servers do not initiate JSON-RPC requests and clients do not send JSON-RPC responses”.4 Há uma única direção de iniciativa, e ela pertence ao host.
Dois recursos do lado do cliente usam esse mecanismo, e um deles tem um nome que vai confundir você.
Elicitation é o servidor pedindo algo à pessoa: um formulário com um JSON Schema deliberadamente restrito — objetos planos, propriedades primitivas, sem aninhamento — para que qualquer cliente consiga renderizá-lo sem um motor de layout. Ele carrega uma regra rígida: servidores não devem usar o modo formulário para pedir “senhas, chaves de API, tokens de acesso ou credenciais de pagamento”, e devem usar o modo URL para isso, que envia o usuário a uma página que o cliente nunca lê.7
Sampling é o servidor pedindo uma geração ao modelo do host, para que um servidor possa ser inteligente sem manter uma chave de API. E aqui vai o alerta de vocabulário, porque esta palavra já significa outra coisa neste curso: isso não é o sampling do Capítulo 17. Nada aqui tem a ver com temperatura, top-p ou o formato de uma distribuição de probabilidade. É uma chamada de modelo aninhada viajando de volta pelo protocolo.
Há um segundo motivo para não recorrer a isso: nesta revisão, sampling está deprecated, junto com roots e logging, sob a SEP-2577, com uma migração sugerida de forma direta — “integre diretamente com APIs de provedores de LLM em vez de Sampling”.8 A ideia não falhou tecnicamente; ela falhou em justificar sua área de superfície, e um protocolo que consegue remover coisas é mais saudável do que um que não consegue.
Quebre de propósito: conexões não são sessões
Link para a seção: Quebre de propósito: conexões não são sessõesA ausência de estado soa como um detalhe de formato de wire até você testá-la. Pegue a troca de três mensagens acima e execute cada mensagem em um processo separado — um node calendar.mjs novo, sem memória compartilhada, sem nada carregado adiante:
process A tools/call (no date) → resultType: input_required
requestState: eyJ0aXRsZSI6IkRlbnRpc3QifQ==
process B tools/call (with the answer, same requestState)
→ resultType: complete
"Created e3: Dentist at 2026-09-10T08:30:00Z"
process C resources/read calendar://week
→ events: 2 (Standup, Design review)O processo B, que nunca viu a pergunta, concluiu uma chamada multi-round-trip que o processo A começou. Esse é o ponto de requestState: a continuação viaja na mensagem, então nada depende de o processo ser o mesmo.
O processo C é a falha. O evento foi criado e não está lá — porque o servidor de brinquedo mantém EVENTS em um array em nível de módulo, e um array em nível de módulo é estado de conexão. A nota da especificação nomeia o erro com precisão:
an open connection, such as a STDIO process, is not a conversation or session: clients may interleave unrelated requests on the same transport, and a server must not treat connection or process identity as a proxy for conversation or session continuity.2
A correção prescrita não é uma sessão. É um handle explícito: uma ferramenta de criação retorna um identificador opaco, e toda chamada posterior o recebe como um argumento comum. O protocolo não tem conceito disso — “do ponto de vista do wire, um handle é uma string comum em um resultado de ferramenta e um argumento comum em chamadas de ferramenta subsequentes”.9 Isso coloca o modelo no comando de carregá-lo, e coloca o servidor no comando de validar que este chamador tem permissão para usá-lo em cada chamada, porque um handle é um nome, não uma permissão.
O que um servidor custa antes de fazer qualquer coisa
Link para a seção: O que um servidor custa antes de fazer qualquer coisaToda ferramenta que um servidor expõe é um schema que entra no seu prompt em toda solicitação, e o Capítulo 24 mediu o que isso faz com uma janela. MCP acrescenta uma segunda linha de custo fácil de perder, então vale contar as duas no servidor de referência acima.
13 tool definitions (name + description + inputSchema): 1,307 tokens
cheapest tool, get-tiny-image 52
costliest tool, gzip-file-as-resource 235
server `instructions`, returned by discovery: 312 tokens
------
one server, connected, before it is used: 1,619 tokensDuas observações. A primeira é aritmética: conecte cinco servidores desse tamanho e cerca de oito mil tokens da sua janela ficam comprometidos em todo turno, para sempre, quer o modelo use algum deles ou não — que é o mecanismo por trás da redução de 150.000 para 2.000 citada no Capítulo 24, e a razão pela qual existe descoberta just-in-time de ferramentas.
A segunda é uma nota de segurança vestida de contabilidade. instructions é texto em linguagem natural, escrito pelo autor do servidor, que cai no prompt do host, e as descrições de ferramentas ao lado dele são iguais. A especificação diz o que fazer sobre isso em seus próprios princípios de segurança: anotações e descrições de ferramentas “devem ser consideradas não confiáveis, a menos que obtidas de um servidor confiável”, e hosts “devem obter consentimento explícito do usuário antes de invocar qualquer ferramenta”.1 Conectar um servidor MCP não é adicionar uma dependência. É conceder a um estranho 1.619 tokens do seu system prompt e o direito de ser chamado. O Capítulo 30 é o que acontece quando esse estranho é hostil.
Seção datada: a revisão 2026-07-28, e o que ela quebra
Link para a seção: Seção datada: a revisão 2026-07-28, e o que ela quebraTudo nesta seção é verdadeiro para a revisão de protocolo 2026-07-28, a atual, lida em 7 de setembro de 2026. Revisões são datadas como YYYY-MM-DD, e a data é a última vez em que uma mudança incompatível com versões anteriores foi feita.10 O documento normativo é um arquivo TypeScript, schema/2026-07-28/schema.ts; o JSON Schema ao lado é gerado a partir dele, e é por isso que a especificação é lida aqui em TypeScript e por que ensinar MCP a partir de qualquer outra coisa é ensinar uma tradução.
| O que mudou | Era | Agora é | Quebra |
|---|---|---|---|
| O handshake | initialize + notifications/initialized, uma vez por conexão | removido; toda solicitação carrega versão e capacidades em _meta | todo cliente escrito antes desta revisão |
| Sessões | cabeçalho Mcp-Session-Id, estado com escopo de conexão | removidas; o estado viaja em handles explícitos criados pelo servidor | endpoints de listagem que variavam por conexão |
| Descoberta | inferida do resultado de initialize | server/discover, que servidores devem implementar | nada, mas agora é obrigatório implementar |
| Chamadas do servidor para o cliente | servidor enviava roots/list, sampling/createMessage, elicitation/create | InputRequiredResult e uma nova tentativa do cliente | todo servidor que empurrava uma solicitação para um cliente |
| Formato do resultado | qualquer objeto | resultType obrigatório: "complete" ou "input_required" | nada: um campo ausente deve ser lido como "complete" |
| Subscriptions | stream HTTP GET, resources/subscribe | um stream subscriptions/listen com tipos opt-in | o endpoint GET acabou |
| Retomada de stream | replay de Last-Event-ID em Streamable HTTP | removida; um stream quebrado perde a solicitação, reenvie com um novo id | clientes que dependiam de reentrega |
| Roots | um recurso de cliente que servidores podiam pedir | deprecated (SEP-2577); passe caminhos como argumentos de ferramenta ou URIs de resource | nada ainda — janela de doze meses |
| Sampling e logging | recursos de cliente | deprecated (SEP-2577) | nada ainda — janela de doze meses |
| Transporte HTTP+SSE | deprecated desde 2025-03-26 | Deprecated sob a política de ciclo de vida (SEP-2596) | migrar para Streamable HTTP |
| Registro de cliente | OAuth 2.0 Dynamic Client Registration, RFC 7591 | deprecated em favor de Client ID Metadata Documents | mantido para servidores de autorização sem eles |
| Códigos de erro | -32002 para resource não encontrado | -32602; -32020–-32099 reservados para a especificação | novos códigos -32020, -32021, -32022 |
A mudança de governança por baixo dessa tabela importa mais do que qualquer linha isolada. Esta revisão adotou uma política de ciclo de vida e depreciação de recursos: recursos são Active, Deprecated ou Removed, um recurso deprecated documenta seu caminho de migração e permanece na especificação por pelo menos doze meses antes de se tornar elegível para remoção, e há um registro listando tudo que está atualmente no estado Deprecated.8 Antes dessa política, “deprecated” em um protocolo de IA significava o que o último post de blog dizia. Agora significa uma data.
Mostrar detalhes
Extensions, que são a parte sobre a qual ninguém escreveu ainda.
Além do núcleo, MCP define extensions opcionais — “sempre opt-in e exigem suporte explícito tanto do cliente quanto do servidor”, declaradas por meio de um campo extensions nas capacidades do cliente e do servidor.1 Três vale conhecer pelo nome:
- Tasks (
io.modelcontextprotocol/tasks), movido do protocolo central para uma extension oficial nesta revisão: execução assíncrona de operações longas, com polling portasks/get, entrada no meio da execução portasks/update, e handles duráveis. É a resposta para uma ferramenta que leva vinte minutos, algo que o Capítulo 23 tratou com um evento de progresso e um sinal que chega à ferramenta. - Skills over MCP, um working group tornando agent skills — assunto do Capítulo 28 — descobríveis e consumíveis pelo protocolo.
- MCP Apps, UI interativa renderizada inline na conversa: gráficos, formulários, players de vídeo.
E observe o que “negociado” significa agora: não há inicialização onde negociar, então uma extension é declarada por solicitação como todo o resto.
Onde o MCP fica, diante de tudo com que é confundido
Link para a seção: Onde o MCP fica, diante de tudo com que é confundidoEste é o vocabulário de todo o bloco em um só lugar.
| O que é | Quem fala com quem | Quando é a resposta | |
|---|---|---|---|
| Uma API simples | Uma interface para um programa | seu código ↔ um serviço | Você está escrevendo o chamador. Você controla o schema, a auth e o tratamento de erros, e não há problema de descoberta a resolver. |
| MCP | Um protocolo para expor ferramentas, dados e templates a uma aplicação de IA | host ↔ servidor, um cliente para cada | Outra pessoa escreveu a capacidade e muitos hosts deveriam conseguir usá-la sem uma integração sob medida. |
| RAG | Uma técnica para encontrar texto e colocá-lo no prompt | seu código ↔ seu índice | O modelo precisa saber algo. Capítulo 19. MCP é uma forma de entregar um retriever; ele não é um retriever. |
| Agent skills | Uma pasta com um SKILL.md que o modelo lê | modelo ↔ um documento | O conhecimento é procedural — como nós fazemos isso — e é prosa, não uma função. Capítulo 28. |
| A2A | Um protocolo para agents colaborarem como pares | agent ↔ agent | O outro lado raciocina, planeja e mantém estado ao longo de uma tarefa longa, em vez de responder a uma chamada. |
| ACP | Era um protocolo separado de comunicação entre agents | — | Já não é uma comparação ativa. Veja abaixo. |
Dois deles merecem uma frase cada, porque é onde a confusão realmente mora.
MCP versus A2A não é rivalidade, e as duas especificações dizem isso. A documentação do A2A traça a linha pelo que está do outro lado: MCP “define como um agent de IA interage com e utiliza tools e resources individuais, como um banco de dados ou uma API”, onde uma tool executa “funções específicas, muitas vezes sem estado”; A2A trata de agents, “sistemas mais autônomos” que “raciocinam, planejam, usam múltiplas tools, mantêm estado por interações mais longas e participam de diálogos complexos, muitas vezes multi-turn”. O próprio resumo é a frase a lembrar: “A2A é sobre agents fazendo parceria em tarefas, enquanto MCP é mais sobre agents usando capacidades”.11 Os dois se aninham — uma aplicação usa A2A para chegar a outros agents, e cada agent usa MCP para chegar às suas próprias tools. O Capítulo 25 traçou essa linha dentro de um processo, entre perguntar a um sub-agent e entregar a conversa a ele; A2A a traça entre organizações.
MCP versus ACP é uma comparação com uma premissa vencida, exatamente por isso vale respondê-la. O Agent Communication Protocol era um padrão aberto separado para mensagens agent-to-agent. Sua própria documentação agora abre com o aviso: “ACP is now part of A2A under the Linux Foundation!”12 A resposta honesta para “MCP ou ACP?” em setembro de 2026 é que a pergunta tem uma opção a menos do que sugerem as páginas ranqueadas para ela.
E a comparação que mais pedem, mcp vs api, tem a resposta menos interessante: MCP é uma API. O que ele acrescenta não é poder, são convenções — um conjunto fixo de nomes de métodos, uma chamada de descoberta, uma hierarquia de controle sobre as primitivas e um modelo de isolamento. Você abre mão da liberdade de desenhar sua própria interface e ganha todo host que fala o protocolo, que é a troca que todo protocolo sempre ofereceu.
Para onde isso vai agora
Link para a seção: Para onde isso vai agoraAgora você consegue ler a especificação sem tradutor, distinguir um resource de uma ferramenta e de um prompt por quem está no comando, digitar uma solicitação à mão quando uma biblioteca cliente está mentindo para você, e datar qualquer artigo sobre MCP que leia pelos recursos deprecated que ele ainda ensina como atuais.
O que você ainda não fez foi publicar um. O Capítulo 27 escreve o mesmo servidor duas vezes — TypeScript e Python, lado a lado, porque MCP é o único território genuinamente bilíngue deste curso e os números dizem isso nas duas direções. Ele cobre corretamente os dois transportes vivos, o inspector, empacotamento e a metade do protocolo que este capítulo deixou de lado de propósito: authorization. Porque, no instante em que seu servidor é remoto em vez de um subprocesso no seu próprio laptop, o cliente de um estranho vai apresentar um token, e a regra da especificação sobre o que você pode fazer com ele é incomumente rígida.
Isso levanta a pergunta que o próximo capítulo precisa responder, e ela não é simpática: se um token chega ao seu servidor e foi emitido para a audience de outra pessoa, o que exatamente impede você de encaminhá-lo?
Fontes e método
Link para a seção: Fontes e métodoToda citação, nome de método, código de erro e regra neste capítulo foi lida na especificação do Model Context Protocol, revisão 2026-07-28, em 7 de setembro de 2026. Todo trace foi produzido localmente no Node 22: o servidor de calendário de brinquedo tem 101 linhas e nenhuma dependência, e o servidor de referência é o pacote npm publicado nomeado abaixo. Nenhuma API paga foi chamada para escrever este capítulo — nada aqui precisa de um modelo, o que por si só é o ponto.
As medições: @modelcontextprotocol/server-everything@2026.8.31, publicado em 31 de agosto de 2026, construído sobre @modelcontextprotocol/sdk@1.30.0, publicado em 27 de julho de 2026 — um dia antes da revisão que este capítulo descreve. Ele responde server/discover com -32601, negocia 2025-11-25 quando solicitado por 2026-07-28, e atende tools/list sem handshake algum. Seu catálogo tem 13 ferramentas em 7.663 bytes; contagens de token são o200k_base via tiktoken, sobre name, description e inputSchema de cada definição, que é o que um provedor renderiza no seu prompt, não o que o frame JSON-RPC pesa.
Anthropic, Code execution with MCP: building more efficient agents, 4 de novembro de 2025, é a fonte do número de 150.000 para 2.000, citado e usado no Capítulo 24 e apenas referenciado aqui.
Referências
Link para a seção: Referências-
Specification,
modelcontextprotocol.io/specification/latest(redirecionando para/2026-07-28), lida em 7 de setembro de 2026. Fonte da comparação com o Language Server Protocol; da afirmação de que a especificação é “baseada no schema TypeScript emschema.ts”; do resumo do protocolo base (“solicitações sem estado e autocontidas”, “negociação de capacidade por solicitação”); da lista de extensions (Tasks, Skills over MCP, MCP Apps) e da afirmação de que extensions “são sempre opt-in e exigem suporte explícito tanto do cliente quanto do servidor”; e dos princípios de Segurança e Trust & Safety, incluindo “hosts devem obter consentimento explícito do usuário antes de invocar qualquer ferramenta” e o tratamento de anotações de ferramentas como não confiáveis. ↩ ↩2 ↩3 -
Base Protocol,
modelcontextprotocol.io/specification/2026-07-28/basic. Fonte das restrições JSON-RPC (id não null, sem reutilização de id,resultTypeobrigatório); da seção de statelessness e sua nota de que um processo stdio aberto não é uma sessão; da tabela de chaves reservadas_metae do status obrigatório/opcional de cada campo por solicitação; da regra-32602para campo obrigatório ausente; da regraMissingRequiredClientCapability(-32021); e da política de alocação de códigos de erro. ↩ ↩2 ↩3 ↩4 ↩5 -
stdio transport,
modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio. Fonte das regras de framing delimitado por nova linha, do requisito de pureza destdout, da permissão destderr, e da sonda de compatibilidade retroativa com três resultados — incluindo o aviso de que alguns servidores legacy processam métodos ambíguos entre eras sem handshake, o que a medição deste capítulo reproduz. ↩ ↩2 ↩3 -
Transports overview,
modelcontextprotocol.io/specification/2026-07-28/basic/transports. Fonte do enquadramento “um transporte é um binding” e da afirmação de que servidores não iniciam solicitações JSON-RPC e clientes não enviam respostas JSON-RPC. ↩ ↩2 -
Discovery,
modelcontextprotocol.io/specification/2026-07-28/server/discover. Fonte do status obrigatório deserver/discover, do formato deDiscoverResult, e do campoinstructionsdescrito como “orientação opcional em linguagem natural para LLMs sobre como usar este servidor de forma eficaz”. ↩ -
Architecture,
modelcontextprotocol.io/specification/2026-07-28/architecture. Fonte das definições de host/cliente/servidor, da regra 1:1 de cliente para servidor, dos quatro princípios de design, dos quais o princípio de isolamento é citado aqui sem seu quinto bullet, “Host process enforces security boundaries”, e da seção de negociação de capacidades. ↩ ↩2 -
Elicitation,
.../client/elicitation, e Sampling,.../client/sampling. Fonte dos dois modos de elicitation e seu schema restrito; da proibição de solicitar credenciais por modo formulário; da definição de sampling, seu requisito de human-in-the-loop e o aviso de depreciação anexado a ele. ↩ -
Key Changes,
modelcontextprotocol.io/specification/2026-07-28/changelog, e Feature lifecycle and deprecation policy,.../community/feature-lifecycle. Fonte de cada linha da tabela de mudanças: remoção de sessões e do cabeçalhoMcp-Session-Id(SEP-2567); statelessness e remoção deinitialize(SEP-2575);server/discover(SEP-2575);subscriptions/listen(SEP-2575); Multi Round-Trip Requests eresultType(SEP-2322); remoção da retomabilidade de stream (SEP-2575); depreciação de Roots, Sampling e Logging (SEP-2577); reclassificação de HTTP+SSE (SEP-2596); depreciação de Dynamic Client Registration em favor de Client ID Metadata Documents; renumeração dos códigos de erro; e a janela de depreciação de doze meses. ↩ ↩2 -
Tools,
modelcontextprotocol.io/specification/2026-07-28/server/tools, e Server Features,.../server. Fonte da tabela de hierarquia de controle reproduzida acima; dos formatostools/listetools/call; da distinçãoisErrorentre erros de protocolo e erros de execução de ferramenta; das regras de nome de ferramenta e da nota de namespace que recomenda “prefixar nomes de ferramentas com um identificador de servidor”; e da orientação não normativa “Stateful Tools” sobre handles explícitos. ↩ -
Versioning,
modelcontextprotocol.io/specification/versioning. Fonte do esquemaYYYY-MM-DD, dos estados de revisão Draft/Current/Final, da confirmação de que 2026-07-28 é current, e das regras de negociação por solicitação. A tabela de tiers do SDK emmodelcontextprotocol.io/docs/sdklista TypeScript, Python, C#, Go e Rust no Tier 1, Java e Ruby no Tier 2, e Swift, PHP e Kotlin no Tier 3. ↩ -
A2A Protocol, versão 1.0.0,
a2a-protocol.org— a especificação e a página A2A and MCP: Relationship and Distinction, lidas em 7 de setembro de 2026. Fonte da distinção tools-versus-agents, da afirmação de que os dois protocolos “atendem necessidades distintas, mas altamente complementares”, e da formulação partnering/using. ↩ -
Agent Communication Protocol,
agentcommunicationprotocol.dev, lido em 7 de setembro de 2026: “ACP is now part of A2A under the Linux Foundation!”, um banner adicionado acima de uma especificação que ainda é servida inteira — arquitetura, manifesto de agent, descoberta de agent, estrutura de mensagem, agents com estado, ciclo de vida de execução e a lista de endpoints REST ainda respondem 200. A especificação não desapareceu; o projeto, sim. ↩