Guida
MCP 2026-07-28: la revisione senza stato, e cosa chiede al vostro server
Fondatore di Epovest
Il 28 luglio 2026 il Model Context Protocol ha ricevuto la sua revisione più ampia dall'aggiunta dell'autorizzazione. Una sola frase la riassume quasi per intero: il protocollo non ha più una stretta di mano. La versione, l'identità del client e le sue capacità viaggiano ora su ogni richiesta, e il server accetta o rifiuta ogni richiesta per conto suo.
Tutto il resto discende da quella frase. Ecco che cosa la revisione toglie, che cosa la sostituisce, e la manciata di requisiti facili da mancare perché nulla si rompe rumorosamente quando li si salta. Abbiamo portato il nostro server MCP a 2026-07-28 il 2 agosto 2026: l'elenco di controllo in fondo è quello che abbiamo seguito.
Che cosa la revisione toglie
- Le sessioni di protocollo e l'intestazione
Mcp-Session-Id. I risultati di elenco non variano più da una connessione all'altra. Un server che ha bisogno di stato tra due chiamate conia una chiave esplicita e la fa circolare come un normale argomento di strumento. - La stretta di mano
initializee la confermanotifications/initializedche la chiudeva. ping,logging/setLevelenotifications/roots/list_changed. Il livello di registro si imposta ora per richiesta, dentro_meta.- Il flusso GET indipendente. Le notifiche di cambiamento passano da un'unica richiesta
subscriptions/listendi lunga durata, e il client si abbona ai tipi che vuole ricevere. - La ripresa di un flusso interrotto.
Last-Event-IDe gli identificatori di evento SSE spariscono. Un flusso spezzato perde la richiesta in volo, e il client la riemette con un identificatore nuovo.
La ragione dichiarata riguarda la forma del dispiegamento. Un server che non conserva stato di sessione si mette dietro un bilanciatore di carico ordinario e scala come qualunque altro servizio HTTP, senza archivio condiviso né instradamento appiccicoso. Era l'obiettivo annunciato nella tabella di marcia 2026, e questa revisione è il punto in cui atterra.
Che cosa sostituisce la stretta di mano
server/discover. I server DEVONO implementarla. Risponde in una sola chiamata con le versioni del protocollo che il server serve, le sue capacità e la sua identità. Un client PUÒ chiamarla per prima per scegliere la versione in anticipo, oppure farne a meno e trattare un errore di versione strada facendo.
I metadati per richiesta. Ogni richiesta porta il proprio contesto:
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
Su HTTP la stessa versione è ripetuta nell'intestazione MCP-Protocol-Version, e le due devono coincidere.
Gli scambi in più giri. Un server che ha bisogno di un campionamento, di una domanda all'utente o dell'elenco delle radici non manda più una propria richiesta su un flusso. Restituisce un risultato con resultType: "input_required" e un campo inputRequests, e il client ripete la richiesta originale con gli inputResponses corrispondenti. La richiesta emessa dal server, come forma, esce dal protocollo.
I task diventano un'estensione. I task sperimentali lasciano il nucleo e diventano l'estensione ufficiale io.modelcontextprotocol/tasks, con un tasks/get da interrogare al posto di un tasks/result bloccante.
Cinque requisiti facili da mancare
Sono quelli che superano una revisione del codice e falliscono davanti a un client rigoroso.
resultTypesu ogni risultato. Un risultato ordinario porta"complete". Un client deve leggere l'assenza del campo, su un server rimasto a una revisione precedente, come un"complete".- Gli indizi di cache sono richiesti, non facoltativi.
ttlMsecacheScopeappartengono ai risultati diserver/discover,tools/list,prompts/list,resources/list,resources/templates/listeresources/read.ttlMsè una durata di freschezza in millisecondi;cacheScopevale"public"o"private"e decide se un intermediario condiviso può conservare la risposta. - Due intestazioni di richiesta, che il server deve sorvegliare.
Mcp-Methodsu ogni richiesta,Mcp-Namesutools/call,resources/readeprompts/get. Rispecchiano valori del corpo perché un gateway possa instradare e autorizzare senza leggerlo, ed è esattamente per questo che un server DEVE rifiutare con400ogni disaccordo tra intestazione e corpo. Un valore che non entra in un'intestazione ASCII stampabile viaggia codificato in base64 tra=?base64?e?=, e il server lo decodifica prima di confrontarlo. - Nuovi codici di errore, in un intervallo riservato alla specifica.
-32020per un'intestazione che contraddice il corpo,-32021per una capacità del client richiesta e assente,-32022per una versione di protocollo non servita. L'ultimo conta più di quanto sembri: PORTA l'elenco delle versioni che il server serve, ed è quell'elenco a permettere al client di riprovare invece di concludere che il server è rotto. La risorsa non trovata passa inoltre da-32002allo standard-32602. - Un metodo sconosciuto risponde
404, con l'errore JSON-RPC nel corpo. È questa coppia a dire a un client che sonda di stare parlando con un server aggiornato, e non con un punto di ingresso che semplicemente non ospita quella rotta.
L'autorizzazione
La registrazione dinamica dei client è deprecata a favore dei Client ID Metadata Documents. L'identificatore del client diventa un URL https con un percorso, che punta a un documento JSON ospitato e mantenuto dal client stesso. Il server di autorizzazione legge quel documento, verifica che il client_id contenuto sia proprio l'URL da cui proviene, e convalida l'indirizzo di ritorno contro l'elenco che dichiara. Niente da registrare prima del primo flusso, niente da ripulire dopo, e lo stesso identificatore vale presso ogni server di autorizzazione. Un server annuncia la capacità con client_id_metadata_document_supported nei suoi metadati.
Una conseguenza merita di essere detta chiaramente, dato che la specifica la lascia allo stato di considerazione e non di regola: questo meccanismo fa leggere al server di autorizzazione un URL scelto da chi chiama, e su un punto di ingresso dei token pubblico chi chiama può essere chiunque. Risolvete voi stessi l'indirizzo, rifiutate tutto ciò che non sta sull'internet pubblica, e fissate l'indirizzo risolto nella richiesta uscente invece di limitarvi a verificarlo. Verificare senza fissare lascia che il nome venga risolto una seconda volta dal client HTTP, ed è tutto il meccanismo di un attacco di riassociazione DNS. Rifiutate i reindirizzamenti, limitate il corpo, tenete corti i tempi di attesa, e mettete il risultato in cache per una durata fissa anziché per quella che il documento chiede.
Due aggiunte più discrete nello stesso ambito: la risposta di autorizzazione DOVREBBE portare il parametro iss della RFC 9207, che il client DEVE convalidare quando è presente e che chiude l'attacco per confusione contro un client collegato a più server di autorizzazione; e il client DEVE inviare application_type alla registrazione dinamica, poiché un server OIDC legge un valore assente come "web" e rifiuta poi gli indirizzi di ritorno di un'applicazione nativa.
Che cosa è deprecato, e per quanto
La revisione introduce anche un ciclo di vita delle funzionalità: attiva, deprecata, rimossa, con almeno dodici mesi tra una deprecazione e la prima rimozione possibile, più un registro pubblico di tutto ciò che è deprecato. Radici, campionamento, registrazione degli eventi, trasporto HTTP+SSE e registrazione dinamica dei client sono oggi in quello stato. Continuano a funzionare. Un'implementazione nuova non li adotta.
Servire le due ere da un solo punto di ingresso
La maggior parte dei server parlerà la revisione nuova e quelle vecchie insieme per un po', e nulla vieta di servirle nello stesso posto. La regola: è la versione DICHIARATA a scegliere l'era, e nient'altro. Nessuna dichiarazione vale l'era della stretta di mano; una richiesta che dichiara 2026-07-28 ottiene quella senza stato.
Due dettagli decidono se regge.
initialize non deve MAI negoziare 2026-07-28. Un client che manda initialize non parla una revisione che non ha più la stretta di mano, qualunque versione vi chieda. Concedergliela lo lascerebbe ad attendere campi che non arriverebbero mai. Tenete due elenchi: le versioni che servite, quelle che server/discover annuncia, e le versioni che initialize può negoziare, cioè il primo elenco meno quella senza stato.
Rispondete l'errore di versione PRIMA del controllo della chiave. Chi arriva con una versione non servita e senza autenticazione deve leggere l'errore di versione. Un 401 non gli insegna nulla di azionabile, e l'elenco delle versioni servite è comunque pubblico, dato che server/discover lo restituisce senza autenticazione.
L'elenco di controllo
Da passare sul vostro server.
server/discoverrisponde, e senza chiave se gli altri vostri metodi pubblici rispondono senza chiave?- Ogni risultato porta il suo
resultType? server/discoveretools/listportano il lorottlMse il lorocacheScope?- Convalidate
MCP-Protocol-Versioncontro il corpo, eMcp-MethodeMcp-Namecontro i loro valori nel corpo, con-32020in caso di disaccordo? - Una versione non servita restituisce
400e-32022, portando le versioni che servite? - Un metodo sconosciuto restituisce
404con-32601? initializerisponde ancora ai client più vecchi, e non restituisce mai2026-07-28?- Se tenete voi il server di autorizzazione: annuncia
client_id_metadata_document_supported, e fissa l'indirizzo risolto prima di andare a leggere un documento di client?
Il server MCP di Epovest risponde in 2026-07-28 come in 2025-06-18, 2025-03-26 e 2024-11-05 sullo stesso punto di ingresso, e il riferimento completo è su epovest.com/docs/api.md. Per collegarvi un assistente, la nostra guida per fare di Claude il vostro analista GEO personale descrive i due modi per collegarsi.