Ves al contingut
26/30Capítol 26 de 30

MCP explicat des de l’especificació: què és realment un servidor

Una línia de JSON entra en un subprocés i tornen tretze definicions d’eines, llegides contra la revisió 2026-07-28.

En aquesta pàgina

Instal·la un servidor MCP publicat, envia-li una línia de JSON i llegeix què torna.

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}

Tretze definicions d’eines, en una sola línia, d’un procés que ha llegit una línia de la seva entrada estàndard. Acabes de parlar el Model Context Protocol, sense SDK, sense biblioteca de client i sense framework. Això és tot: un transport, un format de missatge i un petit conjunt de mètodes amb nom.

El Capítol 18 definia una eina com dues coses: un JSON Schema que veu el model i un endpoint al teu codi que el model no veu mai. El Capítol 23 construïa un harness que en conserva un catàleg. Cap dels dos responia la pregunta que decideix si res d’això és reutilitzable: qui escriu l’esquema i com arriba des de qui l’ha escrit fins al teu prompt? MCP és una resposta a aquesta pregunta, i val la pena llegir-la a l’original, perquè gairebé tot el que se n’ha escrit descriu una revisió que ja no existeix.

Hi ha tres coses equivocades en l’ordre que acabes d’executar, i cadascuna és una secció d’aquest capítol. No portava cap versió del protocol, així que un servidor conforme l’hauria rebutjada. Tot i així va rebre una resposta, per una raó que l’especificació qualifica de perill i no de funcionalitat. I va demanar una de tres primitives sense descobrir mai que les altres dues existien.

El problema que resol, i l’analogia que fa la mateixa especificació

Enllaç a la secció: El problema que resol, i l’analogia que fa la mateixa especificació

Abans del cable, l’aritmètica. Tens NN aplicacions d’IA i MM coses a les quals haurien de poder arribar: un calendari, un gestor de tiquets, una base de dades de magatzem, una eina de disseny. Sense un contracte compartit, algú escriu N×MN \times M integracions, i cadascuna és un esquema més un endpoint més una història d’autenticació més una càrrega de manteniment. Amb un contracte, el proveïdor de l’eina escriu un servidor, el proveïdor de l’aplicació escriu un client, i el total és N+MN + M.

No és una observació nova, i l’especificació diu de qui era la idea:

MCP s’inspira en certa manera en el Language Server Protocol, que estandarditza com afegir suport per a llenguatges de programació en tot un ecosistema d’eines de desenvolupament. De manera semblant, MCP estandarditza com integrar context i eines addicionals a l’ecosistema d’aplicacions d’IA.1

Pren-te aquesta comparació literalment, no com un compliment. Abans d’aquell protocol, donar suport a un llenguatge en un editor volia dir un plugin per editor; després, l’equip del llenguatge enviava un servidor i tots els editors el rebien. La mesura de l’èxit no era l’elegància, sinó que el recompte d’integracions deixava de multiplicar-se. Aquí passa el mateix: el valor és en el nombre d’implementacions, no en el disseny. Un protocol que només parlen dos productes és un format de dades amb cerimònia extra.

Els missatges MCP són JSON-RPC 2.0. Una petició és un objecte amb jsonrpc, un id, un method i params opcional; una resposta porta el mateix id i o bé result o bé error; una notificació és una petició sense id i no rep resposta. L’especificació hi afegeix tres restriccions: el id ha de ser una cadena o un nombre i no pot ser null, no pot col·lidir amb una altra petició encara en curs, i cada resultat ha de portar un camp resultType.2

Al transport stdio —el que ha utilitzat l’ordre de dalt—, la regla d’emmarcat és una línia per missatge:

Els missatges es delimiten amb salts de línia i MUST NOT contenir salts de línia incrustats. […] El servidor MUST NOT escriure res al seu stdout que no sigui un missatge MCP vàlid.3

Aquesta última clàusula és la manera més habitual que un servidor casolà es trenqui, i es trenca en silenci: un console.log perdut, una barra de progrés, un avís de deprecació d’una dependència, i l’analitzador de línies del client topa amb alguna cosa que no és JSON. La via d’escapament és a la mateixa secció: el servidor pot escriure el que vulgui a stderr, i el client no ho hauria de tractar com un error. El servidor de referència de dalt imprimeix Starting default (STDIO) server... a cada arrencada, a stderr, i per això el pipe va continuar funcionant.

L’altre transport estàndard és Streamable HTTP: cada missatge és un POST a un sol endpoint, i la resposta és o bé un objecte JSON o bé un flux de Server-Sent Events lligat a la petició —el format de cable que el Capítol 14 va analitzar a mà. La semàntica és idèntica en tots dos, perquè un transport és una vinculació: defineix emmarcat i lliurament, no significat.4

La primera cosa equivocada: no hi havia versió

Enllaç a la secció: La primera cosa equivocada: no hi havia versió

L’ordre de dalt va enviar tools/list i res més. Amb la revisió actual, aquesta petició està mal formada, i un servidor conforme l’ha de rebutjar.

Des del 2026-07-28, MCP és un protocol sense estat, i l’especificació ho diu sense matisos:

El Model Context Protocol (MCP) és un protocol sense estat: tota la informació necessària per processar una petició és dins de la mateixa petició. Un servidor processa cada petició de manera independent; no s’ha d’inferir cap estat de peticions anteriors, ni tan sols de les que arriben per la mateixa connexió o el mateix flux.2

Així, cada petició porta la seva pròpia versió del protocol i les seves pròpies capacitats de client, dins d’un objecte reservat _meta a params. Dos d’aquests camps són obligatoris en absolutament cada petició; una petició a la qual en falti qualsevol dels dos està mal formada i el servidor ha de respondre -32602:2

clau _metaobligatoriquè és
io.modelcontextprotocol/protocolVersionla revisió que parla aquesta petició, p. ex. "2026-07-28"
io.modelcontextprotocol/clientCapabilitiesquè pot fer el client per al servidor en aquesta petició
io.modelcontextprotocol/clientInfono (però hauria)nom i versió del client, només per mostrar i per logs
io.modelcontextprotocol/logLevelnoel nivell mínim de log que el servidor hauria d’emetre per a aquesta petició

Escrit sencer, un tools/list correcte és això —i és l’última vegada que aquest capítol mostra les metadades completes, perquè a partir d’aquí són a cada petició:

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"}}}}

L’objecte de capacitats és la negociació. Ja no hi ha cap pas de negociació separat: el client declara què pot fer a cada petició, el servidor declara què pot fer al resultat, i cap de les dues parts pot utilitzar una funcionalitat que l’altra no hagi declarat. Un servidor que necessiti una capacitat que el client no ha declarat ha de respondre -32021 i anomenar la capacitat que falta a data.requiredCapabilities. Un servidor que no parli la versió demanada ha de respondre -32022 i llistar les versions que sí que parla.2

Els clients que vulguin la resposta d’entrada poden demanar-la: server/discover és un RPC obligatori que retorna versions compatibles, capacitats, identitat i un bloc opcional de instructions en un sol viatge d’anada i tornada.5 Cridar-lo és opcional. Implementar-lo no ho és.

La segona cosa equivocada: el servidor era legacy

Enllaç a la secció: La segona cosa equivocada: el servidor era legacy

L’ordre va funcionar. Amb la revisió actual no hauria d’haver-ho fet, i la raó per la qual ho va fer val més com a mesura que com a paràgraf, perquè és l’estat de tot l’ecosistema en una línia.

Sondeja el servidor de referència com l’especificació diu que ho ha de fer un client modern:

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"}}

Aquesta és la tercera branca de la regla de compatibilitat: un DiscoverResult vol dir modern, un error modern reconegut vol dir modern-però-versió-equivocada, i qualsevol altra cosa —inclòs -32601— vol dir legacy, torna al handshake initialize.3 Així que fes-ho, demanant la revisió actual:

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":"…"}}

El client va demanar 2026-07-28 i el servidor va respondre 2025-11-25. El 7 de setembre de 2026, el servidor oficial de referència —paquet npm @modelcontextprotocol/server-everything, versió 2026.8.31, publicat el 31 d’agost de 2026— no implementa la revisió actual. Tampoc, segons les dates, ho fa l’SDK TypeScript sobre el qual està construït: la release 1.30.0 va sortir el 27 de juliol de 2026, el dia abans de la revisió.

Llegeix-ne la conseqüència, no el xafardeig. Gairebé tot el que s’ha escrit sobre MCP descriu un protocol amb un handshake initialize, una sessió, una petició roots/list que el servidor envia al client, i un transport HTTP+SSE. Les quatre coses han desaparegut o estan desapareixent. Quan llegeixis qualsevol cosa sobre MCP, inclosa aquesta pàgina, el primer que has de buscar és un número de revisió.

I la raó per la qual la primera ordre de totes va funcionar està indicada a l’especificació com un perill, no com una funcionalitat:

alguns servidors legacy no validen que una petició arribi després de initialize i processarien un mètode ambigu d’època (com ara tools/call) sota semàntica legacy. El sondeig produeix un error determinista en canvi.3

Mesurat: enviar tools/list a aquell servidor sense cap handshake retorna tot el catàleg. Es va servir un mètode que s’hauria d’haver rebutjat, que és exactament per això que l’especificació diu de sondar amb server/discover primer encara que només admetis versions modernes.

Tres rols, i la frase que cal citar de tot el document

Enllaç a la secció: Tres rols, i la frase que cal citar de tot el document

MCP té tres parts, i la distinció entre les dues primeres és la que la gent col·lapsa:

Host. L’aplicació: el producte de xat, l’editor, l’agent. És propietari de la conversa, el model, les credencials i el consentiment de l’usuari. Crea clients i imposa el límit de seguretat entre ells.

Client. Un connector dins del host. Cada client parla amb exactament un servidor —una relació estricta 1:1— i adjunta la versió del protocol i les capacitats a cada petició que encamina.

Servidor. Un procés o un servei que exposa recursos, eines i prompts. Pot ser local o remot, opera de manera independent, i tota la seva feina és una àrea enfocada.6

Aquesta regla d’«exactament un servidor» no és comptabilitat. És el que fa implementable el principi de disseny de sota, i aquesta és la frase que t’has d’emportar de l’especificació si només te n’emportes una:

Els servidors no haurien de poder llegir tota la conversa, ni «veure dins» d’altres servidors. Els servidors reben només la informació contextual necessària. L’historial complet de la conversa es queda amb el host. Cada servidor manté l’aïllament. Les interaccions entre servidors són controlades pel host.6

Això capgira el model mental amb què arriba la majoria de gent. Un servidor del temps que connectes al teu assistent no veu què has preguntat. Veu un tools/call amb els arguments que ha triat el model, i res més: ni els torns anteriors, ni el teu system prompt, ni els resultats que el servidor de calendari ha retornat fa un moment. Si dos servidors han de cooperar, el host porta un valor de l’un a l’altre, deliberadament, perquè el model ho ha demanat. Per això l’aïllament és la propietat de seguretat en què es recolza el Capítol 30: un servidor compromès té un radi d’explosió petit i definit, i ampliar-lo exigeix que el host cooperi.

La tercera cosa: tres primitives, ordenades per qui mana

Enllaç a la secció: La tercera cosa: tres primitives, ordenades per qui mana

La primera ordre va demanar eines a aquell servidor i en va rebre tretze. Fes-li les altres dues preguntes i també les respon: resources/list en retorna set, prompts/list en retorna quatre. Cap no va aparèixer, perquè ningú no ho va demanar. I això ens porta a l’espina pedagògica de MCP, asseguda dins de l’especificació com una taula que gairebé ningú cita:

PrimitivaControlDescripcióExemple
PromptsControlat per l’usuariPlantilles interactives invocades per elecció de l’usuariOrdres slash, opcions de menú
RecursosControlat per l’aplicacióDades contextuals adjuntades i gestionades pel clientContingut de fitxers, historial git
EinesControlat pel modelFuncions exposades a l’LLM per executar accionsPeticions POST d’API, escriptura de fitxers

No són «tres maneres d’exposar una capacitat». Són tres respostes a qui decideix que això passa. El model decideix cridar una eina. L’aplicació decideix adjuntar un recurs. La persona decideix executar un prompt. Si t’equivoques aquí, la funcionalitat encara funciona, però funciona en el moment equivocat i per la raó equivocada.

La manera més clara de notar-ho és un calendari. Aquí tens un servidor que exposa el mateix calendari tres vegades, una com cada primitiva, en cent línies de Node pur sense dependències:

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" });
}

Executa’l i pregunta-li de les tres maneres. Sortida real, un missatge per línia al cable, ajustada aquí per a la pàgina, amb la petició _meta i el bloc d’identitat del servidor elidits:

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}

Tres mètodes, tres formes, un calendari. Ara el punt:

S’adreça amb un URI, és inert, i l’aplicació decideix si l’adjunta a la conversa. Res al protocol permet que el model l’agafi pel seu compte. El resultat porta ttlMs i cacheScope, nous en aquesta revisió, perquè el client pugui cachejar la setmana durant un minut en lloc de fer polling.

Té un esquema, té efectes secundaris, i el model decideix quan cridar-la. El seu resultat porta isError, que és el camp que el Capítol 18 defensava: una fallada de validació torna com a resultat d’eina que el model pot llegir i corregir, no com a error de protocol.

És una plantilla amb nom i arguments que la persona invoca: l’ordre slash del menú. Retorna missatges, no una resposta. És una manera perquè l’autor d’un servidor enviï la formulació que funciona amb les seves pròpies eines, que és exactament el coneixement que té l’autor del servidor i que l’usuari no té.

Gairebé tothom converteix totes tres coses en eines. El resultat és un catàleg on una lectura que l’aplicació hauria d’haver adjuntat en silenci competeix per l’attention del model amb una escriptura que necessita aprovació, i on l’única cosa per a la qual una persona volia un botó queda enterrada en un esquema. Fer-ho bé no costa res, i es decideix abans d’escriure una línia.

L’eina de calendari té un argument obligatori, title, i un d’opcional, startsAt. Demana-li que creï un esdeveniment sense data, i torna una cosa interessant:

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=="}

El servidor no ha enviat cap petició. Ha respost la que li havien fet, amb resultType: "input_required" i una descripció del que encara necessita. El client recull la resposta de la persona i després torna a enviar la crida original —amb un id nou, portant inputResponses i repetint de tornada l’requestState opac:

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}

Això és Multi Round-Trip Requests, introduït en la revisió actual, i va substituir el disseny anterior en què els servidors enviaven peticions JSON-RPC de tornada als clients. L’especificació de transport ara enuncia la regla de manera plana: «els servidors no inicien peticions JSON-RPC i els clients no envien respostes JSON-RPC».4 Hi ha una sola direcció d’iniciativa, i pertany al host.

Dues funcionalitats del costat del client viatgen sobre aquest mecanisme, i una d’elles té un nom que et farà ensopegar.

Elicitation és el servidor demanant alguna cosa a la persona: un formulari amb un JSON Schema deliberadament restringit —objectes plans, propietats primitives, sense anidament— perquè qualsevol client el pugui renderitzar sense motor de layout. Porta una regla estricta: els servidors no han d’utilitzar el mode formulari per demanar «contrasenyes, claus d’API, access tokens o credencials de pagament», i han d’utilitzar el mode URL per a això, que envia l’usuari a una pàgina que el client no llegeix mai.7

Sampling és el servidor demanant una generació al model del host, perquè un servidor pugui ser intel·ligent sense tenir una clau d’API. I aquí va l’avís de vocabulari, perquè aquesta paraula ja vol dir una altra cosa en aquest curs: això no és el sampling del Capítol 17. Res d’aquí tracta sobre temperatura, top-p o la forma d’una distribució de probabilitat. És una crida de model niada que viatja cap enrere a través d’un protocol.

Hi ha una segona raó per no córrer a utilitzar-ho: a partir d’aquesta revisió, sampling està deprecated, juntament amb roots i logging, sota SEP-2577, amb una migració suggerida sense embuts: «integra directament amb les API dels proveïdors d’LLM en lloc de Sampling».8 La idea no va fallar tècnicament; no va justificar la seva superfície, i un protocol que pot eliminar coses és més sa que un que no pot.

Trenca-ho expressament: les connexions no són sessions

Enllaç a la secció: Trenca-ho expressament: les connexions no són sessions

L’absència d’estat sona com un detall de format de cable fins que ho proves. Agafa l’intercanvi de tres missatges de dalt i executa cada missatge en un procés separat: un node calendar.mjs fresc, sense memòria compartida, sense res arrossegat:

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)

El procés B, que no havia vist mai la pregunta, va completar una crida de múltiples viatges d’anada i tornada que el procés A havia iniciat. Aquest és el punt de requestState: la continuació viatja dins del missatge, així que res no depèn que el procés sigui el mateix.

El procés C és el fracàs. L’esdeveniment es va crear i no hi és, perquè el servidor de joguina manté EVENTS en un array a nivell de mòdul, i un array a nivell de mòdul és estat de connexió. La nota de l’especificació posa nom a l’error amb precisió:

una connexió oberta, com ara un procés STDIO, no és una conversa ni una sessió: els clients poden intercalar peticions no relacionades en el mateix transport, i un servidor no ha de tractar la identitat de connexió o de procés com un substitut de la continuïtat de conversa o de sessió.2

La solució prescrita no és una sessió. És un handle explícit: una eina de creació retorna un identificador opac, i cada crida posterior el pren com un argument normal. El protocol no en té cap concepte: «des de la perspectiva del cable, un handle és una cadena ordinària en un resultat d’eina i un argument ordinari per a crides d’eina posteriors».9 Això posa el model a càrrec de portar-lo, i posa el servidor a càrrec de validar que aquest cridador té permís per utilitzar-lo en absolutament cada crida, perquè un handle és un nom i no un permís.

Cada eina que exposa un servidor és un esquema que entra al teu prompt en cada petició, i el Capítol 24 va mesurar què fa això a una finestra. MCP afegeix una segona partida que és fàcil de passar per alt, així que val la pena comptar-les totes dues al servidor de referència de dalt.

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

Dues observacions. La primera és aritmètica: connecta cinc servidors d’aquesta mida i aproximadament vuit mil tokens de la teva finestra queden compromesos en cada torn, per sempre, tant si el model en fa servir cap com si no; aquest és el mecanisme darrere de la reducció de 150.000 a 2.000 que citava el Capítol 24, i la raó per la qual existeix el descobriment d’eines just-in-time.

La segona és una nota de seguretat disfressada de comptabilitat. instructions és text en llenguatge natural, escrit per l’autor del servidor, que aterra al prompt del host, i les descripcions d’eina del costat són el mateix. L’especificació diu què cal fer-ne als seus propis principis de seguretat: les anotacions i descripcions d’eina «s’han de considerar no fiables, llevat que s’obtinguin d’un servidor de confiança», i els hosts «han d’obtenir consentiment explícit de l’usuari abans d’invocar qualsevol eina».1 Connectar un servidor MCP no és afegir una dependència. És concedir a un desconegut 1.619 tokens del teu system prompt i el dret de ser cridat. El Capítol 30 és el que passa quan aquest desconegut és hostil.

Secció datada: la revisió 2026-07-28, i què trenca

Enllaç a la secció: Secció datada: la revisió 2026-07-28, i què trenca

Tot en aquesta secció és cert de la revisió del protocol 2026-07-28, l’actual, llegida el 7 de setembre de 2026. Les revisions van datades YYYY-MM-DD i la data és l’última vegada que es va fer un canvi incompatible cap enrere.10 El document normatiu és un fitxer TypeScript, schema/2026-07-28/schema.ts; el JSON Schema del costat se’n genera, i per això aquí l’especificació es llegeix en TypeScript i per això ensenyar MCP des de qualsevol altra cosa és ensenyar una traducció.

Què ha canviatAbans eraAra ésTrenca
El handshakeinitialize + notifications/initialized, un cop per connexióeliminat; cada petició porta versió _meta i capacitatstots els clients escrits abans d’aquesta revisió
Sessionscapçalera Mcp-Session-Id, estat per connexióeliminades; l’estat viatja en handles explícits encunyats pel servidorendpoints de llista que variaven per connexió
Descobrimentinferit del resultat initializeserver/discover, que els servidors han d’implementarres, però ara és obligatori d’implementar
Crides del servidor al clientel servidor enviava roots/list, sampling/createMessage, elicitation/createInputRequiredResult i un reintent del clienttots els servidors que empenyien una petició cap a un client
Forma del resultatqualsevol objecteresultType obligatori: "complete" o "input_required"res: un camp absent s’ha de llegir com "complete"
Subscripcionsflux HTTP GET, resources/subscribeun flux subscriptions/listen amb tipus opt-inl’endpoint GET ha desaparegut
Represa de fluxrepetició Last-Event-ID a Streamable HTTPeliminada; un flux trencat perd la petició, torna-la a emetre amb un id nouclients que depenien del relliurament
Rootsuna funcionalitat de client que els servidors podien demanardeprecated (SEP-2577); passa camins com a arguments d’eina o URI de recursres encara: finestra de dotze mesos
Sampling i loggingfuncionalitats de clientdeprecated (SEP-2577)res encara: finestra de dotze mesos
Transport HTTP+SSEdeprecated des de 2025-03-26Deprecated sota la política de cicle de vida (SEP-2596)migra a Streamable HTTP
Registre de clientOAuth 2.0 Dynamic Client Registration, RFC 7591deprecated a favor de Client ID Metadata Documentsconservat per a servidors d’autorització que no en tenen
Codis d’error-32002 per recurs no trobat-32602; -32020-32099 reservats per a l’especificaciócodis nous -32020, -32021, -32022

El canvi de governança sota aquesta taula importa més que qualsevol fila concreta. Aquesta revisió va adoptar una política de cicle de vida de funcionalitats i de deprecació: les funcionalitats són Active, Deprecated o Removed, una funcionalitat deprecated documenta el seu camí de migració i es queda a l’especificació com a mínim dotze mesos abans de ser elegible per eliminar-se, i hi ha un registre que llista tot el que actualment és en estat Deprecated.8 Abans d’aquesta política, «deprecated» en un protocol d’IA volia dir el que digués l’últim post del blog. Ara vol dir una data.

Mostra els detalls

Extensions, que són la part de què encara no ha escrit ningú.

Més enllà del nucli, MCP defineix extensions opcionals: «sempre opt-in i requereixen suport explícit tant del client com del servidor», declarades mitjançant un camp extensions a les capacitats del client i del servidor.1 Val la pena conèixer-ne tres pel nom:

  • Tasks (io.modelcontextprotocol/tasks), traslladada del protocol nucli a una extensió oficial en aquesta revisió: execució asíncrona d’operacions llargues, amb polling mitjançant tasks/get, entrada a mig vol mitjançant tasks/update i handles duradors. És la resposta a una eina que triga vint minuts, que el Capítol 23 gestionava amb un esdeveniment de progrés i un senyal que arriba a l’eina.
  • Skills over MCP, un grup de treball que fa que les agent skills —tema del Capítol 28— siguin descobribles i consumibles a través del protocol.
  • MCP Apps, interfície d’usuari interactiva renderitzada dins de la conversa: gràfics, formularis, reproductors de vídeo.

I fixa’t què vol dir ara «negociat»: no hi ha inicialització on negociar, així que una extensió es declara per petició com tota la resta.

On encaixa MCP respecte de tot allò amb què es confon

Enllaç a la secció: On encaixa MCP respecte de tot allò amb què es confon

Aquest és el vocabulari de tot el bloc en un sol lloc.

Què ésQui parla amb quiQuan és la resposta
Una API planaUna interfície per a un programael teu codi ↔ un serveiEscrius el cridador. Controles l’esquema, l’auth i la gestió d’errors, i no hi ha cap problema de descobriment per resoldre.
MCPUn protocol per exposar eines, dades i plantilles a una aplicació d’IAhost ↔ servidor, un client cadascunAlgú altre ha escrit la capacitat i molts hosts l’haurien de poder utilitzar sense una integració a mida.
RAGUna tècnica per trobar text i posar-lo al promptel teu codi ↔ el teu índexEl model necessita saber alguna cosa. Capítol 19. MCP és una manera de lliurar un recuperador; no és un recuperador.
Agent skillsUna carpeta amb un SKILL.md que el model llegeixmodel ↔ un documentEl coneixement és procedimental —com nosaltres fem això— i és prosa, no una funció. Capítol 28.
A2AUn protocol perquè agents col·laborin com a igualsagent ↔ agentL’altra banda raona, planifica i manté estat al llarg d’una tasca llarga, en lloc de respondre una crida.
ACPEra un protocol separat de comunicació entre agentsJa no és una comparació viva. Mira més avall.

Dos d’aquests mereixen una frase cadascun, perquè és on realment viu la confusió.

MCP contra A2A no és una rivalitat, i totes dues especificacions ho diuen. La documentació d’A2A traça la línia segons què hi ha a l’altre extrem: MCP «defineix com un AI agent interactua amb eines i recursos individuals i els utilitza, com ara una base de dades o una API», on una eina executa «funcions específiques, sovint sense estat»; A2A s’adreça a agents, «sistemes més autònoms» que «raonen, planifiquen, utilitzen múltiples eines, mantenen estat en interaccions més llargues i participen en diàlegs complexos, sovint de múltiples torns». El seu propi resum és la frase que cal recordar: «A2A tracta d’agents que s’associen en tasques, mentre que MCP tracta més d’agents que utilitzen capacitats».11 Els dos s’encaixen: una aplicació utilitza A2A per arribar a altres agents, i cada agent utilitza MCP per arribar a les seves pròpies eines. El Capítol 25 traçava aquesta línia dins d’un sol procés, entre preguntar a un sub-agent i passar-li la conversa; A2A la traça entre organitzacions.

MCP contra ACP és una comparació amb una premissa caducada, i justament per això val la pena respondre-la. L’Agent Communication Protocol era un estàndard obert separat per a missatgeria agent-a-agent. La seva pròpia documentació ara obre amb l’avís: «ACP is now part of A2A under the Linux Foundation!»12 La resposta honesta a «MCP o ACP?» el setembre de 2026 és que la pregunta té una opció menys del que suggereixen les pàgines que hi posicionen.

I la comparació que més demana la gent, mcp vs api, té la resposta menys interessant: MCP és una API. El que afegeix no és potència, sinó convencions: un conjunt fix de noms de mètode, una crida de descobriment, una jerarquia de control sobre les primitives i un model d’aïllament. Renuncies a la llibertat de dissenyar la teva pròpia interfície i reps tots els hosts que parlen el protocol, que és el tracte que tots els protocols han ofert sempre.

Ara pots llegir l’especificació sense traductor, distingir un recurs d’una eina i d’un prompt segons qui en té el control, escriure una petició a mà quan una biblioteca de client t’està mentint, i datar qualsevol article sobre MCP que llegeixis segons quines funcionalitats deprecated encara ensenya com si fossin actuals.

El que no has fet és enviar-ne un a producció. El Capítol 27 escriu el mateix servidor dues vegades —TypeScript i Python, costat a costat— perquè MCP és l’únic territori genuïnament bilingüe d’aquest curs i les xifres ho diuen en totes dues direccions. Cobreix bé els dos transports vius, l’inspector, l’empaquetat i la meitat del protocol que aquest capítol ha deixat deliberadament de banda: autorització. Perquè en el moment que el teu servidor és remot i no un subprocés al teu propi portàtil, el client d’un desconegut presentarà un token, i la regla de l’especificació sobre què en pots fer és inusualment estricta.

Això planteja la pregunta que el capítol següent ha de respondre, i no és amable: si arriba un token al teu servidor i s’ha emès per a l’audience d’algú altre, què t’impedeix exactament reenviar-lo?


Cada cita, nom de mètode, codi d’error i regla d’aquest capítol s’ha llegit de l’especificació del Model Context Protocol, revisió 2026-07-28, el 7 de setembre de 2026. Cada traça s’ha produït localment sobre Node 22: el servidor de calendari de joguina té 101 línies i cap dependència, i el servidor de referència és el paquet npm publicat que s’anomena a sota. No s’ha cridat cap API de pagament per escriure aquest capítol: res d’aquí necessita un model, que ja és part del punt.

Les mesures: @modelcontextprotocol/server-everything@2026.8.31, publicat el 31 d’agost de 2026, construït sobre @modelcontextprotocol/sdk@1.30.0, publicat el 27 de juliol de 2026 —un dia abans de la revisió que descriu aquest capítol. Respon server/discover amb -32601, negocia 2025-11-25 quan se li demana 2026-07-28, i serveix tools/list sense cap handshake. El seu catàleg és de 13 eines en 7.663 bytes; els recomptes de token són o200k_base via tiktoken, sobre els name, description i inputSchema de cada definició, que és el que un proveïdor renderitza dins del teu prompt i no el que pesa el marc JSON-RPC.

Anthropic, Code execution with MCP: building more efficient agents, 4 de novembre de 2025, és la font de la xifra de 150.000 a 2.000, citada i utilitzada al Capítol 24 i només referenciada aquí.

  1. Specification, modelcontextprotocol.io/specification/latest (redirigint a /2026-07-28), llegida el 7 de setembre de 2026. Font de la comparació amb Language Server Protocol; l’afirmació que l’especificació està «based on the TypeScript schema in schema.ts»; el resum del protocol base («Stateless, self-contained requests», «Per-request capability negotiation»); la llista d’extensions (Tasks, Skills over MCP, MCP Apps) i l’afirmació que les extensions «are always opt-in and require explicit support from both client and server»; i els principis de Security i Trust & Safety, incloent-hi «Hosts must obtain explicit user consent before invoking any tool» i el tractament de les anotacions d’eina com a no fiables. 2 3

  2. Base Protocol, modelcontextprotocol.io/specification/2026-07-28/basic. Font de les restriccions JSON-RPC (id no nul, no reutilització d’id, resultType obligatori); la secció Statelessness i la seva nota que un procés stdio obert no és una sessió; la taula de claus reservades _meta i l’estat obligatori/opcional de cada camp per petició; la regla -32602 per a un camp obligatori que falta; la regla MissingRequiredClientCapability (-32021); i la política d’assignació de codis d’error. 2 3 4 5

  3. stdio transport, modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio. Font de les regles d’emmarcat delimitat per salts de línia, el requisit de puresa de stdout, el permís de stderr, i el sondeig de compatibilitat cap enrere de tres resultats, incloent-hi l’avís que alguns servidors legacy processen mètodes ambigües d’època sense handshake, cosa que la mesura d’aquest capítol reprodueix. 2 3

  4. Transports overview, modelcontextprotocol.io/specification/2026-07-28/basic/transports. Font de l’enquadrament «un transport és una vinculació» i de l’afirmació que els servidors no inicien peticions JSON-RPC i els clients no envien respostes JSON-RPC. 2

  5. Discovery, modelcontextprotocol.io/specification/2026-07-28/server/discover. Font del caràcter obligatori de server/discover, la forma de DiscoverResult, i el camp instructions descrit com a «optional natural-language guidance for LLMs on how to use this server effectively».

  6. Architecture, modelcontextprotocol.io/specification/2026-07-28/architecture. Font de les definicions de host/client/servidor, la regla 1:1 de client a servidor, els quatre principis de disseny, dels quals aquí se cita el principi d’aïllament sense el cinquè punt, «Host process enforces security boundaries», i la secció de negociació de capacitats. 2

  7. Elicitation, .../client/elicitation, i Sampling, .../client/sampling. Font dels dos modes d’elicitation i el seu esquema restringit; la prohibició de demanar credencials a través del mode formulari; la definició de sampling, el seu requisit de human-in-the-loop i l’avís de deprecació que hi va adjunt.

  8. Key Changes, modelcontextprotocol.io/specification/2026-07-28/changelog, i Feature lifecycle and deprecation policy, .../community/feature-lifecycle. Font de cada fila de la taula de canvis: eliminació de sessions i la capçalera Mcp-Session-Id (SEP-2567); absència d’estat i eliminació de initialize (SEP-2575); server/discover (SEP-2575); subscriptions/listen (SEP-2575); Multi Round-Trip Requests i resultType (SEP-2322); eliminació de la represa de fluxos (SEP-2575); deprecació de Roots, Sampling i Logging (SEP-2577); reclassificació d’HTTP+SSE (SEP-2596); deprecació de Dynamic Client Registration a favor de Client ID Metadata Documents; renumeració de codis d’error; i la finestra de deprecació de dotze mesos. 2

  9. Tools, modelcontextprotocol.io/specification/2026-07-28/server/tools, i Server Features, .../server. Font de la taula de jerarquia de control reproduïda més amunt; les formes tools/list i tools/call; la distinció isError entre errors de protocol i errors d’execució d’eina; les regles de noms d’eina i la nota de namespace que recomana «prefixing tool names with a server identifier»; i la guia no normativa «Stateful Tools» sobre handles explícits.

  10. Versioning, modelcontextprotocol.io/specification/versioning. Font de l’esquema YYYY-MM-DD, els estats de revisió Draft/Current/Final, la confirmació que 2026-07-28 és current, i les regles de negociació per petició. La taula de nivells d’SDK a modelcontextprotocol.io/docs/sdk llista TypeScript, Python, C#, Go i Rust al Tier 1, Java i Ruby al Tier 2, i Swift, PHP i Kotlin al Tier 3.

  11. A2A Protocol, versió 1.0.0, a2a-protocol.org —l’especificació i la pàgina A2A and MCP: Relationship and Distinction, llegides el 7 de setembre de 2026. Font de la distinció eines-contra-agents, l’afirmació que els dos protocols «address distinct but highly complementary needs», i la formulació partnering/using.

  12. Agent Communication Protocol, agentcommunicationprotocol.dev, llegit el 7 de setembre de 2026: «ACP is now part of A2A under the Linux Foundation!», un bàner afegit sobre una especificació que encara se serveix sencera: arquitectura, manifest d’agent, descobriment d’agent, estructura de missatges, agents amb estat, cicle de vida d’execució i la llista d’endpoints REST encara responen 200. L’especificació no va desaparèixer; el projecte sí.

A punt per deixar que triï LIA?

Crea amb tots els models d'IA en un sol lloc — comença gratis avui mateix.