Saltar para o conteúdo
26/30Capítulo 26 de 30

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.

terminalBASH
npm i @modelcontextprotocol/server-everything@2026.8.31
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
  | npx @modelcontextprotocol/server-everything stdio
TEXT
{"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 faz

Antes do wire, a aritmética. Tem NN aplicações de IA e MM 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 N×MN \times M 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 é N+MN + M.

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.

As 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 stdout that 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

O 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 _metaobrigatórioo que é
io.modelcontextprotocol/protocolVersionsima revisão que este pedido fala, por exemplo "2026-07-28"
io.modelcontextprotocol/clientCapabilitiessimo que o cliente consegue fazer pelo server neste pedido
io.modelcontextprotocol/clientInfonão (mas deve)nome e versão do cliente, apenas para apresentação e logs
io.modelcontextprotocol/logLevelnãoo 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:

one line, split for the pageTEXT
{"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 é.

O 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:

terminalBASH
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
TEXT
{"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:

TEXT
→ {"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 initialize and would process an era-ambiguous method (such as tools/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.

MCP 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 manda

O 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:

PrimitivoControloDescriçãoExemplo
PromptsControlado pelo utilizadorTemplates interativos invocados por escolha do utilizadorComandos slash, opções de menu
RecursosControlados pela aplicaçãoDados contextuais anexados e geridos pelo clienteConteúdos de ficheiros, histórico git
FerramentasControladas pelo modeloFunções expostas ao LLM para executar açõesPedidos 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:

calendar.mjs — the parts that matterJS
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:

TEXT
→ 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:

É 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.

Tem 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.

É 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.

A 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:

TEXT
→ 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:

TEXT
→ 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.

A 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:

TEXT
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.

Cada 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.

o200k_base tokensTEXT
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 tokens

Duas 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.

Tudo 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 mudouEraAgora éParte
O handshakeinitialize + notifications/initialized, uma vez por ligaçãoremovido; cada pedido transporta versão _meta e capacidadestodos os clientes escritos antes desta revisão
Sessõescabeçalho Mcp-Session-Id, estado com âmbito de ligaçãoremovidas; o estado viaja em handles explícitos cunhados pelo serverendpoints de listagem que variavam por ligação
Descobertainferida a partir do resultado initializeserver/discover, que servers têm de implementarnada, mas agora é obrigatório implementar
Chamadas server-para-clienteo server enviava roots/list, sampling/createMessage, elicitation/createInputRequiredResult e uma nova tentativa do clientetodos os servers que empurravam um pedido para um cliente
Forma do resultadoqualquer objetoresultType obrigatório: "complete" ou "input_required"nada: um campo ausente tem de ser lido como "complete"
Subscriçõesstream HTTP GET, resources/subscribeuma stream subscriptions/listen com tipos opt-ino endpoint GET desapareceu
Retoma de streamreplay Last-Event-ID em Streamable HTTPremovida; uma stream partida perde o pedido, reemita com um novo idclientes que dependiam de reentrega
Rootsuma funcionalidade de cliente que servers podiam pedirdeprecated (SEP-2577); passe caminhos como argumentos de ferramenta ou URIs de recursonada ainda — janela de doze meses
Sampling e loggingfuncionalidades de clientedeprecated (SEP-2577)nada ainda — janela de doze meses
Transporte HTTP+SSEdeprecated desde 2025-03-26Deprecated segundo a política de ciclo de vida (SEP-2596)migre para Streamable HTTP
Registo de clienteOAuth 2.0 Dynamic Client Registration, RFC 7591deprecated a favor de Client ID Metadata Documentsmantido para authorization servers sem eles
Códigos de erro-32002 para recurso não encontrado-32602; -32020-32099 reservados para a especificaçãonovos 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 de tasks/get, input a meio da execução através de tasks/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.

Este é o vocabulário de todo o bloco num só lugar.

O que éQuem fala com quemQuando é a resposta
Uma API simplesUma interface para um programao seu código ↔ um serviçoEstá a escrever o chamador. Controla o schema, a auth e o tratamento de erros, e não há problema de descoberta para resolver.
MCPUm protocolo para expor ferramentas, dados e templates a uma aplicação de IAhost ↔ server, um cliente para cadaOutra pessoa escreveu a capacidade e muitos hosts devem conseguir usá-la sem uma integração à medida.
RAGUma técnica para encontrar texto e pô-lo no prompto seu código ↔ o seu índiceO modelo precisa de saber algo. Capítulo 19. MCP é uma forma de entregar um retriever; não é um retriever.
Agent skillsUma pasta com um SKILL.md que o modelo modelo ↔ um documentoO conhecimento é procedimental — como nós fazemos isto — e é prosa, não uma função. Capítulo 28.
A2AUm protocolo para agents colaborarem como paresagent ↔ agentO outro lado raciocina, planeia e mantém estado ao longo de uma tarefa longa, em vez de responder a uma chamada.
ACPEra um protocolo separado de comunicação entre agentsJá 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.

Agora 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?


Todas 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.

  1. 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 in schema.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

  2. Base Protocol, modelcontextprotocol.io/specification/2026-07-28/basic. Fonte das restrições JSON-RPC (id não null, sem reutilização de id, resultType obrigató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 _meta e do estado obrigatório/opcional de cada campo por pedido; da regra -32602 para um campo obrigatório em falta; da regra MissingRequiredClientCapability (-32021); e da política de alocação de códigos de erro. 2 3 4 5

  3. stdio transport, modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio. Fonte das regras de framing delimitado por newline, do requisito de pureza de stdout, da permissão de stderr, 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

  4. 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

  5. Discovery, modelcontextprotocol.io/specification/2026-07-28/server/discover. Fonte do estatuto obrigatório de server/discover, da forma de DiscoverResult, e do campo instructions descrito como "optional natural-language guidance for LLMs on how to use this server effectively".

  6. 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

  7. 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.

  8. 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çalho Mcp-Session-Id (SEP-2567); statelessness e remoção de initialize (SEP-2575); server/discover (SEP-2575); subscriptions/listen (SEP-2575); Multi Round-Trip Requests e resultType (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

  9. Tools, modelcontextprotocol.io/specification/2026-07-28/server/tools, e Server Features, .../server. Fonte da tabela de hierarquia de controlo reproduzida acima; das formas tools/list e tools/call; da distinção isError entre 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.

  10. Versioning, modelcontextprotocol.io/specification/versioning. Fonte do esquema YYYY-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 em modelcontextprotocol.io/docs/sdk lista TypeScript, Python, C#, Go e Rust no Tier 1, Java e Ruby no Tier 2, e Swift, PHP e Kotlin no Tier 3.

  11. 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.

  12. 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.

Pronto para deixar a LIA escolher?

Construa com todos os modelos de IA num só sítio — comece grátis hoje.