MCP explicado pela especificação: o que é realmente um server
Uma linha de JSON para um subprocesso devolve 13 definições de ferramentas, à luz da revisão 2026-07-28 que removeu o handshake.
Nesta página
Instale um server MCP publicado, envie-lhe 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 ferramentas, numa só linha, vindas de um processo que leu uma linha da sua entrada standard. Acabou de falar o Model Context Protocol, sem SDK, sem biblioteca de cliente e sem framework. É isto tudo: um transporte, um formato de mensagem e um pequeno conjunto de métodos com nome.
O 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ê. O Capítulo 23 construiu um harness que mantém um catálogo delas. Nenhum respondeu à pergunta que decide se algo disto é reutilizável: quem escreve o schema, e como é que ele passa de quem o escreveu para o seu prompt? MCP é uma resposta a essa pergunta, e vale a pena lê-lo no original, porque quase tudo o que se escreveu sobre ele descreve uma revisão que já não existe.
Três coisas no comando que acabou de executar estão erradas, e cada uma é uma secção deste capítulo. Não levava versão do protocolo, por isso um server conforme tê-lo-ia recusado. Ainda assim obteve uma resposta, por uma razão que a especificação chama um perigo, não uma funcionalidade. E pediu um de três primitivos sem nunca descobrir que os outros dois existem.
O problema que resolve, e a analogia que a própria especificação faz
Ligação para a secção: O problema que resolve, e a analogia que a própria especificação fazAntes do wire, a aritmética. Tem aplicações de IA e coisas a que elas deveriam conseguir chegar — um calendário, um gestor de tickets, uma base de dados de armazém, uma ferramenta de design. Sem um contrato partilhado, alguém escreve integrações, e cada uma delas é um schema mais um endpoint mais uma história de autenticação mais um encargo de manutenção. Com um contrato, o fornecedor da ferramenta escreve um server, o fornecedor da aplicação escreve um cliente, e o total é .
Isto 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 à letra, não como um elogio. Antes desse protocolo, suportar uma linguagem num editor significava um plugin por editor; depois, uma equipa de linguagem enviava um único server e todos os editores o recebiam. A medida de sucesso não era a elegância, era o facto de a contagem de integrações deixar de se multiplicar. O mesmo acontece aqui: o valor está no número de implementações, não no design. Um protocolo falado por dois produtos é um formato de dados com cerimónia extra.
O que está realmente no wire
Ligação para a secção: O que está realmente no wireAs mensagens MCP são JSON-RPC 2.0. Um pedido é um objeto com jsonrpc, um id, um method e params opcional; uma resposta transporta o mesmo id e ou result ou error; uma notificação é um pedido sem id e não recebe resposta. A especificação acrescenta três restrições por cima: o id tem de ser uma string ou um número e não pode ser null, não pode colidir com outro pedido ainda em curso, e todos os resultados têm de transportar 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 server caseiro falhar, e falha em silêncio: 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 escapatória está na mesma secção — o server pode escrever o que quiser em stderr, e o cliente não deve tratar isso como erro. O server de referência acima imprime Starting default (STDIO) server... em cada arranque, em stderr, e é por isso que o pipe continuou a funcionar.
O outro transporte standard é Streamable HTTP: cada mensagem é um POST para um único endpoint, e a resposta é ou um objeto JSON ou uma stream de Server-Sent Events com o âmbito do pedido — o wire format que o Capítulo 14 analisou à mão. A semântica é idêntica em ambos, porque um transporte é um binding: define framing e entrega, não significado.4
A primeira coisa que estava errada: não havia versão
Ligação para a secção: A primeira coisa que estava errada: não havia versãoO comando acima enviou tools/list e mais nada. Na revisão atual, esse pedido está malformado, e um server conforme tem de o rejeitar.
Desde 2026-07-28, MCP é um protocolo stateless, e a especificação diz isso sem hesitação:
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
Por isso, cada pedido transporta a sua própria versão do protocolo e as suas próprias capacidades de cliente, num objeto reservado _meta dentro de params. Dois desses campos são obrigatórios em todos os pedidos; um pedido sem qualquer um deles é malformado e o server tem de responder -32602:2
Chave _meta | obrigatório | o que é |
|---|---|---|
io.modelcontextprotocol/protocolVersion | sim | a revisão que este pedido fala, por exemplo "2026-07-28" |
io.modelcontextprotocol/clientCapabilities | sim | o que o cliente consegue fazer pelo server neste pedido |
io.modelcontextprotocol/clientInfo | não (mas deve) | nome e versão do cliente, apenas para apresentação e logs |
io.modelcontextprotocol/logLevel | não | o nível mínimo de log que o server deve emitir para este pedido |
Escrito por extenso, um tools/list correto é isto — e é a última vez que este capítulo mostra os metadados por inteiro, porque estão em todos os pedidos 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. Já não há um passo separado de negociação: o cliente declara o que consegue fazer em cada pedido, o server declara o que consegue fazer no resultado, e nenhum dos lados pode usar uma funcionalidade que o outro não tenha reivindicado. Um server que precise de uma capacidade que o cliente não declarou tem de responder -32021 e nomear a capacidade em falta em data.requiredCapabilities. Um server que não fale a versão pedida tem de responder -32022 e listar as versões que fala.2
Clientes que queiram a resposta logo à partida podem pedi-la: server/discover é um RPC obrigatório que devolve versões suportadas, capacidades, identidade e um bloco opcional de instructions numa só ida e volta.5 Chamá-lo é opcional. Implementá-lo não é.
A segunda coisa que estava errada: o server era legacy
Ligação para a secção: A segunda coisa que estava errada: o server era legacyO comando funcionou. Na revisão atual não deveria ter funcionado, e a razão por que funcionou merece uma medição, não um parágrafo, porque é o estado de todo o ecossistema numa linha.
Sonde o server de referência da forma como 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, recue 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 server respondeu 2025-11-25. Em 7 de setembro de 2026, o server oficial de referência — pacote npm @modelcontextprotocol/server-everything, versão 2026.8.31, publicado a 31 de agosto de 2026 — não implementa a revisão atual. Nem, nas datas, o SDK TypeScript em que foi construído: a release 1.30.0 saiu a 27 de julho de 2026, na véspera da revisão.
Leia a consequência, não a fofoca. Quase tudo o que está escrito sobre MCP descreve um protocolo com um handshake initialize, uma sessão, um pedido roots/list que o server envia ao cliente, e um transporte HTTP+SSE. Os quatro desapareceram ou estão a desaparecer. Quando ler qualquer coisa sobre MCP, incluindo esta página, a primeira coisa a procurar é um número de revisão.
E a razão por que o primeiro comando funcionou está indicada na especificação como um perigo, não uma funcionalidade:
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
Medido: enviar tools/list a esse server sem handshake nenhum devolve o catálogo completo. Um método que devia ter sido recusado foi servido, que é exatamente por isso que a especificação diz para sondar primeiro com server/discover, mesmo quando só suporta versões modernas.
Três papéis, e a frase a citar de todo o documento
Ligação para a secção: Três papéis, e a frase a citar de todo o documentoMCP tem três partes, e a distinção entre as duas primeiras é a que as pessoas tendem a colapsar:
Host. A aplicação: o produto de chat, o editor, o agent. É dono da conversa, do modelo, das credenciais e do consentimento do utilizador. Cria clientes e impõe a fronteira de segurança entre eles.
Cliente. Um conector dentro do host. Cada cliente fala com exatamente um server — uma relação estrita de 1:1 — e anexa a versão do protocolo e as capacidades a todos os pedidos que encaminha.
Server. Um processo ou serviço que expõe recursos, ferramentas e prompts. Pode ser local ou remoto, opera de forma independente, e toda a sua função é uma área focada.6
Essa regra de "exatamente um server" não é contabilidade. É o que torna implementável o princípio de design abaixo, e esta é a frase a reter da especificação se só reter 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
Isto vira do avesso o modelo mental com que a maioria das pessoas chega. Um server de meteorologia que liga ao seu assistente não vê o que perguntou. Vê um tools/call com os argumentos que o modelo escolheu, e nada mais — nem os turnos anteriores, nem o seu system prompt, nem os resultados que o server de calendário devolveu há um momento. Se dois servers precisarem de cooperar, o host transporta um valor de um para o outro, deliberadamente, porque o modelo o pediu. É por isso que o isolamento é a propriedade de segurança em que o Capítulo 30 assenta: um server comprometido tem um raio de explosão pequeno e definido, e aumentá-lo exige a cooperação do host.
A terceira coisa: três primitivos, ordenados por quem manda
Ligação para a secção: A terceira coisa: três primitivos, ordenados por quem mandaO primeiro comando pediu ferramentas a esse server e recebeu treze. Faça-lhe as outras duas perguntas e ele também responde: resources/list devolve sete, prompts/list devolve quatro. Nenhum apareceu, porque nada perguntou. O que nos traz à espinha pedagógica de MCP, presente na especificação como uma tabela que quase ninguém cita:
| Primitivo | Controlo | Descrição | Exemplo |
|---|---|---|---|
| Prompts | Controlado pelo utilizador | Templates interativos invocados por escolha do utilizador | Comandos slash, opções de menu |
| Recursos | Controlados pela aplicação | Dados contextuais anexados e geridos pelo cliente | Conteúdos de ficheiros, histórico git |
| Ferramentas | Controladas pelo modelo | Funções expostas ao LLM para executar ações | Pedidos API POST, escrita de ficheiros |
Não são "três formas de expor uma capacidade". São três respostas a quem decide que isto acontece. O modelo decide chamar uma ferramenta. A aplicação decide anexar um recurso. A pessoa decide executar um prompt. Se errar isto, a funcionalidade continua a funcionar, mas funciona no momento errado e pela razão errada.
A forma mais clara de o sentir é um calendário. Aqui está um server que expõe o mesmo calendário três vezes, uma como cada primitivo, 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-o e pergunte-lhe das três formas. Output real, uma mensagem por linha no wire, embrulhado aqui para a página, com o _meta do pedido e o bloco de identidade do server 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 formas, um calendário. Agora o ponto:
Ler a semana é um recurso
Ligação para a secção: Ler a semana é um recursoÉ endereçado por um URI, é inerte, e a aplicação decide se o anexa à conversa. Nada no protocolo permite ao modelo ir buscá-lo por iniciativa própria. O resultado transporta ttlMs e cacheScope, novos nesta revisão, para que o cliente possa pôr a semana em cache durante um minuto em vez de fazer polling.
Criar um evento é uma ferramenta
Ligação para a secção: Criar um evento é uma ferramentaTem um schema, tem efeitos secundários, e o modelo decide quando a chamar. O seu resultado transporta 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.
"Preparar a minha semana" é um prompt
Ligação para a secção: "Preparar a minha semana" é um promptÉ um template com nome e argumentos que a pessoa invoca — o comando slash no menu. Devolve mensagens, não uma resposta. É uma forma de o autor de um server enviar a formulação que funciona com as suas próprias ferramentas, que é precisamente o conhecimento que o autor do server tem e o utilizador não.
Quase toda a gente transforma estas três coisas em ferramentas. O resultado é um catálogo onde uma leitura que a aplicação devia ter anexado silenciosamente compete pela attention do modelo com uma escrita que precisa de aprovação, e onde a única coisa para a qual uma pessoa queria um botão fica enterrada num schema. Não custa nada acertar, e decide-se antes de escrever uma linha.
O server não pode ligar-lhe de volta
Ligação para a secção: O server não pode ligar-lhe de voltaA ferramenta de calendário tem um argumento obrigatório, title, e um opcional, startsAt. Peça-lhe para 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 server não enviou um pedido. Respondeu ao que lhe foi dado, com resultType: "input_required" e uma descrição do que ainda precisa. O cliente recolhe a resposta da pessoa e depois reenvia a chamada original — com um novo id, transportando 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}Isto é Multi Round-Trip Requests, introduzido na revisão atual, e substituiu o desenho antigo em que servers enviavam pedidos JSON-RPC de volta para clientes. A especificação de transporte diz agora a regra de forma direta: "servers do not initiate JSON-RPC requests and clients do not send JSON-RPC responses".4 Há uma direção de iniciativa, e pertence ao host.
Duas funcionalidades do lado do cliente assentam nesse mecanismo, e uma delas tem um nome que o vai fazer tropeçar.
Elicitation é o server pedir algo à pessoa: um formulário com um JSON Schema deliberadamente restrito — objetos planos, propriedades primitivas, sem aninhamento — para que qualquer cliente o possa renderizar sem motor de layout. Traz uma regra rígida: servers não podem usar o modo formulário para pedir "passwords, API keys, access tokens, or payment credentials", e têm de usar o modo URL para isso, que envia o utilizador para uma página que o cliente nunca lê.7
Sampling é o server pedir uma geração ao modelo do host, para que um server possa ser inteligente sem guardar uma API key. E aqui fica o aviso de vocabulário, porque esta palavra já significa outra coisa neste curso: isto não é o sampling do Capítulo 17. Nada aqui tem a ver com temperatura, top-p ou a forma de uma distribuição de probabilidade. É uma chamada de modelo aninhada a viajar para trás através de um protocolo.
Há uma segunda razão para não recorrer a isto: nesta revisão, sampling está deprecated, juntamente com roots e logging, ao abrigo de SEP-2577, com uma migração sugerida sem rodeios — "integrate directly with LLM provider APIs instead of Sampling".8 A ideia não falhou tecnicamente; falhou em justificar a sua área de superfície, e um protocolo que consegue remover coisas é mais saudável do que um que não consegue.
Parta-o de propósito: ligações não são sessões
Ligação para a secção: Parta-o de propósito: ligações não são sessõesA statelessness parece um detalhe de wire format até a testar. Pegue na troca de três mensagens acima e execute cada mensagem num processo separado — um node calendar.mjs fresco, sem memória partilhada, sem nada transportado:
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, completou uma chamada multi-round-trip que o processo A começou. Esse é o objetivo de requestState: a continuação viaja na mensagem, por isso nada depende de o processo ser o mesmo.
O processo C é a falha. O evento foi criado e não está lá — porque o server de brinquedo mantém EVENTS num array ao nível do módulo, e um array ao nível do módulo é estado de ligaçã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 devolve um identificador opaco, e todas as chamadas posteriores o recebem como argumento normal. O protocolo não tem conceito dele — "from the wire's perspective a handle is an ordinary string in a tool result and an ordinary argument to subsequent tool calls".9 Isto põe o modelo encarregado de o transportar, e põe o server encarregado de validar que este chamador está autorizado a usá-lo em cada chamada, porque um handle é um nome, não uma permissão.
O que um server custa antes de fazer qualquer coisa
Ligação para a secção: O que um server custa antes de fazer qualquer coisaCada ferramenta que um server expõe é um schema que entra no seu prompt em todos os pedidos, e o Capítulo 24 mediu o que isso faz a uma context window. MCP acrescenta uma segunda rubrica fácil de ignorar, por isso vale a pena contar ambas no server 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: ligue cinco servers deste tamanho e cerca de oito mil tokens da sua context window ficam ocupados em todos os turnos, para sempre, quer o modelo use algum deles quer 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 por que existe descoberta de ferramentas just-in-time.
A segunda é uma nota de segurança disfarçada de contabilidade. instructions é texto em linguagem natural, escrito pelo autor do server, que entra no prompt do host, e as descrições de ferramentas ao lado são iguais. A especificação diz o que fazer quanto a isso nos seus próprios princípios de segurança: anotações e descrições de ferramentas "should be considered untrusted, unless obtained from a trusted server", e hosts "must obtain explicit user consent before invoking any tool".1 Ligar um server MCP não é adicionar uma dependência. É conceder a um estranho 1.619 tokens do seu system prompt e o direito a ser chamado. O Capítulo 30 mostra o que acontece quando esse estranho é hostil.
Secção datada: a revisão 2026-07-28, e o que parte
Ligação para a secção: Secção datada: a revisão 2026-07-28, e o que parteTudo nesta secção é verdadeiro para a revisão do protocolo 2026-07-28, a atual, lida em 7 de setembro de 2026. As revisões são datadas YYYY-MM-DD e a data é a última vez que foi feita uma alteração retroincompatível.10 O documento normativo é um ficheiro 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 ensinar MCP a partir de outra coisa é ensinar uma tradução.
| O que mudou | Era | Agora é | Parte |
|---|---|---|---|
| O handshake | initialize + notifications/initialized, uma vez por ligação | removido; cada pedido transporta versão _meta e capacidades | todos os clientes escritos antes desta revisão |
| Sessões | cabeçalho Mcp-Session-Id, estado com âmbito de ligação | removidas; o estado viaja em handles explícitos cunhados pelo server | endpoints de listagem que variavam por ligação |
| Descoberta | inferida a partir do resultado initialize | server/discover, que servers têm de implementar | nada, mas agora é obrigatório implementar |
| Chamadas server-para-cliente | o server enviava roots/list, sampling/createMessage, elicitation/create | InputRequiredResult e uma nova tentativa do cliente | todos os servers que empurravam um pedido para um cliente |
| Forma do resultado | qualquer objeto | resultType obrigatório: "complete" ou "input_required" | nada: um campo ausente tem de ser lido como "complete" |
| Subscrições | stream HTTP GET, resources/subscribe | uma stream subscriptions/listen com tipos opt-in | o endpoint GET desapareceu |
| Retoma de stream | replay Last-Event-ID em Streamable HTTP | removida; uma stream partida perde o pedido, reemita com um novo id | clientes que dependiam de reentrega |
| Roots | uma funcionalidade de cliente que servers podiam pedir | deprecated (SEP-2577); passe caminhos como argumentos de ferramenta ou URIs de recurso | nada ainda — janela de doze meses |
| Sampling e logging | funcionalidades de cliente | deprecated (SEP-2577) | nada ainda — janela de doze meses |
| Transporte HTTP+SSE | deprecated desde 2025-03-26 | Deprecated segundo a política de ciclo de vida (SEP-2596) | migre para Streamable HTTP |
| Registo de cliente | OAuth 2.0 Dynamic Client Registration, RFC 7591 | deprecated a favor de Client ID Metadata Documents | mantido para authorization servers sem eles |
| Códigos de erro | -32002 para recurso não encontrado | -32602; -32020–-32099 reservados para a especificação | novos códigos -32020, -32021, -32022 |
A alteração de governação por baixo dessa tabela é mais importante do que qualquer linha isolada. Esta revisão adotou uma política de ciclo de vida de funcionalidades e depreciação: as funcionalidades são Active, Deprecated ou Removed, uma funcionalidade deprecated documenta o seu caminho de migração e permanece na especificação durante pelo menos doze meses antes de se tornar elegível para remoção, e há um registo que lista tudo o que está atualmente no estado Deprecated.8 Antes dessa política, "deprecated" num protocolo de IA significava o que dissesse o último blog post. Agora significa uma data.
Mostrar detalhes
Extensões, a parte sobre a qual ainda ninguém escreveu.
Para além do núcleo, MCP define extensões opcionais — "always opt-in and require explicit support from both client and server", declaradas através de um campo extensions nas capacidades do cliente e do server.1 Há três que vale a pena conhecer pelo nome:
- Tasks (
io.modelcontextprotocol/tasks), movida do protocolo core para uma extensão oficial nesta revisão: execução assíncrona de operações longas, com polling através detasks/get, input a meio da execução através detasks/update, e handles duráveis. É a resposta para uma ferramenta que demora vinte minutos, que o Capítulo 23 tratou com um evento de progresso e um sinal que chega à ferramenta. - Skills over MCP, um grupo de trabalho que torna agent skills — o tema do Capítulo 28 — descobríveis e consumíveis através do protocolo.
- MCP Apps, UI interativa renderizada inline na conversa: gráficos, formulários, leitores de vídeo.
E note o que "negociado" significa agora: não há inicialização onde negociar, por isso uma extensão é declarada por pedido, como tudo o resto.
Onde MCP fica, face a tudo aquilo com que é confundido
Ligação para a secção: Onde MCP fica, face a tudo aquilo com que é confundidoEste é o vocabulário de todo o bloco num só lugar.
| O que é | Quem fala com quem | Quando é a resposta | |
|---|---|---|---|
| Uma API simples | Uma interface para um programa | o seu código ↔ um serviço | Está a escrever o chamador. Controla o schema, a auth e o tratamento de erros, e não há problema de descoberta para resolver. |
| MCP | Um protocolo para expor ferramentas, dados e templates a uma aplicação de IA | host ↔ server, um cliente para cada | Outra pessoa escreveu a capacidade e muitos hosts devem conseguir usá-la sem uma integração à medida. |
| RAG | Uma técnica para encontrar texto e pô-lo no prompt | o seu código ↔ o seu índice | O modelo precisa de saber algo. Capítulo 19. MCP é uma forma de entregar um retriever; não é um retriever. |
| Agent skills | Uma pasta com um SKILL.md que o modelo lê | modelo ↔ um documento | O conhecimento é procedimental — como nós fazemos isto — e é prosa, não uma função. Capítulo 28. |
| A2A | Um protocolo para agents colaborarem como pares | agent ↔ agent | O outro lado raciocina, planeia 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 viva. Ver abaixo. |
Dois desses merecem uma frase cada, porque é aí que a confusão realmente vive.
MCP face a A2A não é uma rivalidade, e ambas as especificações o dizem. A documentação A2A traça a linha pelo que está do outro lado: MCP "defines how an AI agent interacts with and utilizes individual tools and resources, such as a database or an API", em que uma ferramenta executa "specific, often stateless, functions"; A2A aborda agents, "more autonomous systems" que "reason, plan, use multiple tools, maintain state over longer interactions, and engage in complex, often multi-turn dialogues". O seu próprio resumo é a frase a reter: "A2A is about agents partnering on tasks, while MCP is more about agents using capabilities."11 Os dois encaixam — uma aplicação usa A2A para chegar a outros agents, e cada agent usa MCP para chegar às suas próprias ferramentas. O Capítulo 25 traçou essa linha dentro de um processo, entre pedir a um sub-agent e passar-lhe a conversa; A2A traça-a entre organizações.
MCP face a ACP é uma comparação com uma premissa caduca, que é exatamente por isso que vale a pena responder. O Agent Communication Protocol era uma norma aberta separada para mensagens agent-to-agent. A sua própria documentação agora abre com o aviso: "ACP is now part of A2A under the Linux Foundation!"12 A resposta honesta a "MCP ou ACP?" em setembro de 2026 é que a pergunta tem uma opção a menos do que as páginas que ranqueiam para ela sugerem.
E a comparação que as pessoas mais pedem, mcp vs api, tem a resposta menos interessante: MCP é uma API. O que acrescenta não é poder, são convenções — um conjunto fixo de nomes de métodos, uma chamada de descoberta, uma hierarquia de controlo sobre os primitivos, e um modelo de isolamento. Abdica da liberdade de desenhar a sua própria interface e recebe todos os hosts que falam o protocolo, que é a troca que todos os protocolos sempre ofereceram.
Para onde isto segue
Ligação para a secção: Para onde isto segueAgora consegue ler a especificação sem tradutor, distinguir um recurso de uma ferramenta e de um prompt por quem manda nele, escrever um pedido à mão quando uma biblioteca de cliente lhe está a mentir, e datar qualquer artigo sobre MCP que leia pelas funcionalidades deprecated que ainda ensina como atuais.
O que ainda não fez foi enviar um para produção. O Capítulo 27 escreve o mesmo server duas vezes — TypeScript e Python, lado a lado, porque MCP é o único território genuinamente bilingue deste curso e os números dizem-no nos dois sentidos. Cobre corretamente os dois transportes vivos, o inspector, packaging, e a metade do protocolo que este capítulo deixou deliberadamente de lado: autorização. Porque no momento em que o seu server é remoto em vez de um subprocesso no seu próprio portátil, o cliente de um estranho apresentará um token, e a regra da especificação sobre o que pode fazer com ele é invulgarmente rigorosa.
O que levanta a pergunta a que o próximo capítulo tem de responder, e não é uma pergunta amigável: se um token chega ao seu server e foi emitido para a audience de outra pessoa, o que o impede exatamente de o encaminhar?
Fontes e método
Ligação para a secção: Fontes e métodoTodas as citações, nomes de métodos, códigos de erro e regras deste capítulo foram lidos na especificação do Model Context Protocol, revisão 2026-07-28, em 7 de setembro de 2026. Todos os traces foram produzidos localmente em Node 22: o server de calendário de brinquedo tem 101 linhas sem dependências, e o server de referência é o pacote npm publicado com o nome abaixo. Nenhuma API paga foi chamada para escrever este capítulo — nada aqui precisa de um modelo, o que é em si o ponto.
As medições: @modelcontextprotocol/server-everything@2026.8.31, publicado a 31 de agosto de 2026, construído sobre @modelcontextprotocol/sdk@1.30.0, publicado a 27 de julho de 2026 — um dia antes da revisão que este capítulo descreve. Responde a server/discover com -32601, negoceia 2025-11-25 quando lhe pedem 2026-07-28, e serve tools/list sem handshake nenhum. O seu catálogo tem 13 ferramentas em 7.663 bytes; as contagens de tokens são o200k_base via tiktoken, sobre o name, description e inputSchema de cada definição, que é o que um provider renderiza no seu prompt e não o que pesa o frame JSON-RPC.
Anthropic, Code execution with MCP: building more efficient agents, 4 de novembro de 2025, é a fonte do valor de 150.000 para 2.000, citado e usado no Capítulo 24 e apenas referenciado aqui.
Referências
Ligação para a secção: Referências-
Specification,
modelcontextprotocol.io/specification/latest(a redirecionar 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 é "based on the TypeScript schema inschema.ts"; do resumo do protocolo base ("Stateless, self-contained requests", "Per-request capability negotiation"); da lista de extensões (Tasks, Skills over MCP, MCP Apps) e da afirmação de que as extensões "are always opt-in and require explicit support from both client and server"; e dos princípios de Security and Trust & Safety, incluindo "Hosts must obtain explicit user consent before invoking any tool" e o tratamento de anotações de ferramentas como não fiá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 secção Statelessness e da sua nota de que um processo stdio aberto não é uma sessão; da tabela de chaves reservadas_metae do estado obrigatório/opcional de cada campo por pedido; da regra-32602para um campo obrigatório em falta; 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 newline, do requisito de pureza destdout, da permissão destderr, e da sonda de retrocompatibilidade em três resultados — incluindo o aviso de que alguns servers legacy processam métodos era-ambiguous sem handshake, que a medição neste capítulo reproduz. ↩ ↩2 ↩3 -
Transports overview,
modelcontextprotocol.io/specification/2026-07-28/basic/transports. Fonte do enquadramento "a transport is a binding" e da afirmação de que servers não iniciam pedidos JSON-RPC e clientes não enviam respostas JSON-RPC. ↩ ↩2 -
Discovery,
modelcontextprotocol.io/specification/2026-07-28/server/discover. Fonte do estatuto obrigatório deserver/discover, da forma deDiscoverResult, e do campoinstructionsdescrito como "optional natural-language guidance for LLMs on how to use this server effectively". ↩ -
Architecture,
modelcontextprotocol.io/specification/2026-07-28/architecture. Fonte das definições de host/client/server, da regra 1:1 de cliente-para-server, dos quatro princípios de design, dos quais o princípio de isolamento é citado aqui sem o quinto bullet, "Host process enforces security boundaries", e da secção de negociação de capacidades. ↩ ↩2 -
Elicitation,
.../client/elicitation, e Sampling,.../client/sampling. Fonte dos dois modos de elicitation e do seu schema restrito; da proibição de pedir credenciais através do modo formulário; da definição de sampling, do seu requisito human-in-the-loop, e do aviso de depreciação anexado. ↩ -
Key Changes,
modelcontextprotocol.io/specification/2026-07-28/changelog, e Feature lifecycle and deprecation policy,.../community/feature-lifecycle. Fonte de todas as linhas da tabela de alterações: 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 de retomabilidade de streams (SEP-2575); depreciação de Roots, Sampling e Logging (SEP-2577); reclassificação de HTTP+SSE (SEP-2596); depreciação de Dynamic Client Registration a favor de Client ID Metadata Documents; renumeração dos códigos de erro; e 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 controlo reproduzida acima; das formastools/listetools/call; da distinçãoisErrorentre erros de protocolo e erros de execução de ferramenta; das regras de nomes de ferramentas e da nota de namespace que recomenda "prefixing tool names with a server identifier"; 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 é atual, e das regras de negociação por pedido. A tabela de tiers de 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 ferramentas-contra-agents, da afirmação de que os dois protocolos "address distinct but highly complementary needs", 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 acrescentado acima de uma especificação que continua a ser servida por inteiro — architecture, agent manifest, agent discovery, message structure, stateful agents, run lifecycle e a lista de endpoints REST ainda respondem todos 200. A especificação não desapareceu; o projeto desapareceu. ↩