Zum Inhalt springen
effidevFlutter · Cloudflare-Edge · Cloud-Kostenoptimierung
Deutsch

MCP-Spezifikation 2026-07-28: Die Session ist weg — Migrationsleitfaden für den Wechsel auf Stateless

Migrationsleitfaden zur MCP-Spezifikation 2026-07-28 und zum Wechsel auf Stateless

Am 28. Juli 2026 ist eine neue Revision der Spezifikation des Model Context Protocol erschienen und damit zur aktuellen (Current) Protokollversion geworden. Acht Monate nach der vorigen Revision 2025-11-25. MCP-Mitbegründer David Soria Parra nannte das Release in der offiziellen Ankündigung “das Wichtigste, was es in MCP gegeben hat, seit vor über einem Jahr Remote MCP kam”.

In einem Satz zusammengefasst: MCP ist stateless geworden. Der initialize-Handshake ist verschwunden, der Header Mcp-Session-Id ebenfalls. Wer aktuell einen MCP-Server oder -Client betreibt, hat es hier nicht mit Release Notes zu tun, die man “irgendwann mal” liest, sondern mit Breaking Changes, die Codeänderungen erzwingen.

Die Wellen schlagen bereits. Am 6. August hat Cloudflare McpAgent — bislang der Weg, MCP-Server in Workers zu bauen — auf deprecated und feature-frozen gesetzt und empfiehlt den Umstieg auf stateless Handler. Wenn es keine Sessions mehr gibt, braucht man auch kein Durable Object mehr, das sie festhält. Darum geht es ausführlich in Abschnitt 12.

Dieser Artikel gibt nicht einfach die Liste der Spec-Änderungen wieder, sondern stellt in den Mittelpunkt, welcher Code tatsächlich angefasst werden muss. Zu jedem Punkt steht die SEP-Nummer dabei — wer die Begründung braucht, öffnet direkt den zugehörigen PR.

1. Die Session ist weg (SEP-2567)

Das ist die größte Änderung. Im Streamable-HTTP-Transport wurden Sessions auf Protokollebene und der Header Mcp-Session-Id entfernt.

Daraus folgt eine weitere Bedingung: tools/list, resources/list und prompts/list dürfen pro Verbindung keine unterschiedlichen Werte mehr zurückgeben. Früher waren Implementierungen nach dem Muster “diese Session gehört zu einem authentifizierten Nutzer, also zeigen wir auch die Admin-Tools” möglich — jetzt hängen Listenantworten nicht mehr von der Verbindung ab.

Was also tun, wenn ein Server Zustand über mehrere Aufrufe hinweg halten muss? Die Antwort der Spec ist eindeutig: Der Server stellt einen expliziten Handle aus, der als ganz normales Tool-Argument hin- und hergereicht wird.

// Vorher — eine Struktur, die sich auf den Session-Header verließ
app.post('/mcp', async (c) => {
  const sessionId = c.req.header('Mcp-Session-Id');
  const state = await sessions.get(sessionId);   // dieser Header kommt jetzt nicht mehr an
  // ...
});

// Nachher — Zustand als servergenerierter Handle, explizit über Tool-Argumente übergeben
server.tool('open_workspace', {}, async () => ({
  resultType: 'complete',
  content: [{ type: 'text', text: 'Workspace geöffnet' }],
  structuredContent: { workspaceHandle: 'ws_01J8ZQ...' },   // vom Server ausgestellt
}));

server.tool('write_file', {
  workspaceHandle: z.string(),   // der Client schickt ihn beim nächsten Aufruf unverändert mit
  path: z.string(),
  body: z.string(),
}, async ({ workspaceHandle, path, body }) => { /* ... */ });

Aus implizitem Verbindungszustand werden explizite Daten. Das macht den Betrieb mit mehreren Instanzen hinter einem Load Balancer oder serverless deutlich einfacher — es ist schlicht egal, welche Instanz die Anfrage annimmt.

2. Der initialize-Handshake ist weg (SEP-2575)

initialize und notifications/initialized wurden komplett gestrichen. Stattdessen trägt jede Anfrage die für sie selbst nötigen Informationen in _meta mit sich.

_meta-Schlüssel Richtung Pflicht Inhalt
io.modelcontextprotocol/protocolVersion Client → Server Ja Protokollversion ("2026-07-28")
io.modelcontextprotocol/clientCapabilities Client → Server Ja Für diese Anfrage relevante Client-Fähigkeiten
io.modelcontextprotocol/clientInfo Client → Server Nein (SHOULD) Name und Version des Clients
io.modelcontextprotocol/logLevel Client → Server Nein Minimales Log-Level für diese Anfrage
io.modelcontextprotocol/serverInfo Server → Client (_meta des Ergebnisses) Nein (SHOULD) Name und Version des Servers
// So sieht ab jetzt jede Anfrage aus
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_file",
    "arguments": { "path": "a.txt", "body": "hi" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": { },
      "io.modelcontextprotocol/clientInfo": { "name": "my-client", "version": "1.0.0" }
    }
  }
}

Eine Anfrage ohne Pflichtfelder ist malformed. Der Server MUSS sie mit JSON-RPC -32602 (Invalid params) ablehnen, und bei HTTP MUSS der Antwortstatus 400 Bad Request lauten. Passt die Version nicht, gibt er UnsupportedProtocolVersionError (-32022) zurück.

Auch für Capability-Deklarationen gilt eine neue Regel: Der Server DARF sich NICHT (MUST NOT) auf Fähigkeiten verlassen, die der Client nicht deklariert hat. Braucht er zur Bearbeitung einer Anfrage eine nicht deklarierte Fähigkeit, muss er MissingRequiredClientCapabilityError (-32021) zurückgeben und die fehlenden Fähigkeiten in data.requiredCapabilities auflisten.

Die Spec nagelt die Bedeutung von “stateless” sehr deutlich fest: Der Server DARF Kontext NICHT (MUST NOT) aus früheren Anfragen derselben Verbindung ableiten. Sie stellt sogar ausdrücklich klar, dass selbst ein stdio-Prozess weder eine Konversation noch eine Session ist — ein Client darf über denselben Transport völlig unabhängige Anfragen mischen, und der Server darf die Identität von Verbindung oder Prozess nicht als Ersatz für Session-Kontinuität behandeln.

Ein kompletter Handshake-Roundtrip fällt damit weg, was in Umgebungen mit häufigen Cold Starts — Edge-Runtimes oder serverless — spürbar etwas bringt. Umgekehrt muss jeder Code angefasst werden, der sich auf Informationen stützte, die “einmal beim Initialisieren” geholt und danach dauerhaft verwendet wurden.

3. server/discover: jetzt Pflichtimplementierung (SEP-2575)

Dieser RPC füllt die Lücke, die der Handshake hinterlässt. Der Server MUSS server/discover implementieren. Er dient dazu, unterstützte Protokollversionen, Fähigkeiten und Identität bekanntzugeben.

Aus Client-Sicht gibt es zwei Verwendungen:

So sieht ein DiscoverResult aus. Vorsicht bei den Feldnamen — die Liste der unterstützten Versionen heißt supportedVersions, und die Serveridentität steht nicht auf oberster Ebene des Ergebnisses, sondern in _meta.

{
  "resultType": "complete",
  "supportedVersions": ["2026-07-28", "2025-11-25"],
  "capabilities": { "tools": {}, "resources": {} },
  "_meta": {
    "io.modelcontextprotocol/serverInfo": { "name": "my-mcp-server", "version": "2.0.0" }
  }
}

Auch der Fehler, den der Server bei nicht passender Version zurückgibt, ist festgelegt. Die Liste der unterstützten Versionen muss mitgeschickt werden, damit der Client neu wählen kann.

{
  "jsonrpc": "2.0", "id": 1,
  "error": {
    "code": -32022,
    "message": "Unsupported protocol version",
    "data": { "supported": ["2026-07-28", "2025-11-25"], "requested": "1900-01-01" }
  }
}

Wer einen Server baut, sollte bei dieser Migration genau diesen Code zuerst ergänzen. Fehlt er, ist die Implementierung nicht spezifikationskonform.

Alte und neue Clients gleichzeitig bedienen

Die Spec unterscheidet drei Sorten von Implementierungen.

Begriff Bedeutung
Modern Version, Identität und Fähigkeiten reisen pro Anfrage in _meta mit (2026-07-28 und neuer)
Legacy Session wird über den initialize-Handshake aufgebaut (2025-11-25 und älter)
Dual-era Implementierung, die beides unterstützt

Ein Dual-era-Server entscheidet danach, wie der Client ihn anspricht. Kommt eine Anfrage mit modernem _meta, wird sie stateless bearbeitet; kommt initialize, greift der Legacy-Pfad. Beides darf (MAY) über denselben Endpunkt bedient werden.

Die Erkennung auf Client-Seite unterscheidet sich je nach Transport.

Das Ergebnis dieser Prüfung ist eine Eigenschaft des Servers, nicht der einzelnen Anfrage. Bei stdio SOLLTE es für die Lebensdauer des Prozesses gecacht werden, bei HTTP pro Origin.

Eine Kombination verdient besondere Aufmerksamkeit: Legacy-Client → moderner Server schlägt fehl. Ein Legacy-Client hat schlicht kein Mittel, auf eine höhere Version zu wechseln. Deshalb SOLLTE ein rein moderner Server in der Fehlermeldung auf eine initialize-Anfrage die unterstützten Versionen nennen — diese Meldung ist womöglich der einzige Hinweis, den Nutzer eines Legacy-Clients überhaupt zu sehen bekommen.

4. Subscriptions funktionieren anders (SEP-2575)

Der HTTP-GET-Endpunkt sowie resources/subscribe und resources/unsubscribe sind verschwunden und in einem einzigen subscriptions/listen zusammengeführt — ein langlebiger POST-Antwortstream.

Der Client entscheidet sich explizit (Opt-in) für die Benachrichtigungsarten, die er erhalten möchte.

Der Server bestätigt das und markiert die gesendeten Notifications mit io.modelcontextprotocol/subscriptionId.

Hier lauert eine leicht zu übersehende Stelle: Anfragebezogene Notifications wie notifications/progress und notifications/message laufen NICHT über den subscriptions/listen-Stream. Sie fließen weiterhin über den Antwortstream der ursprünglichen Anfrage. Wenn plötzlich keine Fortschrittsanzeige mehr erscheint, lohnt hier der erste Blick.

5. MRTR — wie der Server beim Client zurückfragt (SEP-2322)

Bisher gab es eine eigene Richtung, in der der Server Anfragen an den Client stellte: roots/list, sampling/createMessage, elicitation/create und Ähnliches. Um die Spec wörtlich wiederzugeben: Der Server MUSS solche Anfragen ab jetzt nach dem MRTR-Muster senden, das bisherige Muster servergetriebener Anfragen wird nicht mehr unterstützt. Das ist ein Breaking Change.

Der neue Ablauf sieht so aus.

  1. Der Client sendet eine Anfrage (id: 1)
  2. Braucht der Server mehr Informationen, antwortet er mit einem InputRequiredResult mit resultType: "input_required"
  3. Der Client fragt den Nutzer und sendet die ursprüngliche Anfrage mit einer neuen id erneut, diesmal mit der Antwort im Gepäck

An dieser Stelle geht am meisten schief: inputRequests und inputResponses sind keine Arrays, sondern Maps. Der Schlüssel ist ein vom Server vergebener Bezeichner, der Wert ein vollständiges Anfrageobjekt (method + params) vom Typ ElicitRequest, CreateMessageRequest oder ListRootsRequest.

// Schritt 2 — Antwort des Servers
{
  "jsonrpc": "2.0", "id": 1,
  "result": {
    "resultType": "input_required",
    "inputRequests": {
      "github_login": {
        "method": "elicitation/create",
        "params": {
          "mode": "form",
          "message": "Bitte geben Sie Ihren GitHub-Benutzernamen ein",
          "requestedSchema": {
            "type": "object",
            "properties": { "name": { "type": "string" } },
            "required": ["name"]
          }
        }
      }
    },
    "requestState": "AEAD-protected blob"
  }
}

Die Antwort ist eine Map mit denselben Schlüsseln, deren Werte die Ergebnisobjekte der jeweiligen Anfragen sind.

// Schritt 3 — Wiederholung mit neuer id, Antwort und requestState unverändert mitgeschickt
{
  "jsonrpc": "2.0", "id": 2,
  "method": "tools/call",
  "params": {
    "name": "delete_file",
    "arguments": { "path": "a.txt" },
    "inputResponses": {
      "github_login": { "action": "accept", "content": { "name": "octocat" } }
    },
    "requestState": "AEAD-protected blob"
  }
}

requestState — der Mechanismus, der MRTR stateless macht

requestState ist ein opaker String, der nur für den Server eine Bedeutung hat. Der Server kodiert darin den Kontext, den er braucht, schickt ihn hinunter, und der Client gibt ihn unverändert zurück. Genau deshalb braucht der Server keinen State Store.

Die Regeln sind ziemlich streng.

Besonders wichtig sind die Sicherheitsanforderungen. Dieser Wert läuft über den Client und ist damit eine von Angreifern manipulierbare Eingabe (die Spec schreibt mit MUST vor, ihn genau so zu behandeln). Wenn er Autorisierung, Ressourcenzugriff oder Geschäftslogik beeinflusst, MUSS der Server seine Integrität schützen (etwa per HMAC oder AEAD) und einen State, dessen Prüfung fehlschlägt, ablehnen. Weglassen darf man das nur, wenn eine Manipulation nichts weiter bewirkt, als dass die Anfrage fehlschlägt.

Zum Schutz vor Replay SOLLTE Folgendes in die integritätsgeschützte Payload aufgenommen und bei jedem Empfang geprüft werden.

Diese Maßnahmen verkleinern allerdings nur das Replay-Fenster und garantieren keine einmalige Verwendung. Wenn Einmalverwendung zwingend nötig ist, MUSS der Server sie separat erzwingen.

Nur drei Anfragen dürfen MRTR verwenden

Client-Anfrage InputRequiredResult erlaubt
prompts/get Ja
resources/read Ja
tools/call Ja

Bei allen anderen Anfragen DARF es NICHT (MUST NOT) gesendet werden. Außerdem darf der Server keine Anfragearten in inputRequests packen, die der Client nicht als Fähigkeit deklariert hat — hat der Client elicitation nicht deklariert, darf elicitation/create dort nicht auftauchen.

Aus einer bidirektionalen Anfrage ist ein unidirektionaler Retry geworden. Für den Transport ist das deutlich einfacher, aber der Client muss die Retry-Schleife selbst implementieren. Alle Callbacks, die bisher servergetriebene Anfragen behandelt haben, müssen auf diese Struktur umgezogen werden.

6. resultType ist in jedem Ergebnis Pflicht (SEP-2322)

Jedes Ergebnis trägt jetzt verpflichtend das Feld resultType.

Für die Abwärtskompatibilität gibt es eine ausdrückliche Regel: Lässt ein Server einer früheren Protokollversion das Feld weg, MUSS der Client es als "complete" behandeln. Wer einen Client baut, sollte diesen Zweig unbedingt einbauen.

7. Was gestrichen wurde

ping
logging/setLevel
notifications/roots/list_changed
tasks/result          (→ ersetzt durch Polling via tasks/get)
tasks/list
notifications/elicitation/complete

Das Log-Level wird jetzt pro Anfrage über io.modelcontextprotocol/logLevel in _meta festgelegt. Und: Der Server DARF für Anfragen ohne dieses Feld KEINE (MUST NOT) notifications/message senden. Wer bisher bedingungslos Logs herausgeschickt hat, muss eine Bedingung ergänzen.

Auch die Wiederaufnahme von SSE-Streams ist weg. Mit dem Entfernen des Headers Last-Event-ID und der SSE-Event-IDs aus Streamable HTTP gilt: Bricht der Antwortstream ab, ist die laufende Anfrage verloren. Der Client MUSS sie mit einer neuen Request-ID erneut senden. Code, der beim Reconnect auf ein Fortsetzen gebaut hat, geht hier stillschweigend kaputt.

8. Tasks sind vom Core in eine Extension gewandert (SEP-2663)

Die bislang experimentellen Tasks sind aus dem Kernprotokoll herausgelöst und in die offizielle Extension io.modelcontextprotocol/tasks umgezogen. Das war kein reiner Umzug — das Design wurde neu aufgesetzt.

Änderung Inhalt
tasks/result entfernt War blockierend. Ersetzt durch Polling via tasks/get
tasks/update neu Für die Übergabe von Eingaben Client → Server
tasks/list entfernt
Rückgabe von Handles Der Server darf Task-Handles ohne Opt-in pro Anfrage von sich aus zurückgeben

Extensions werden über die Map extensions in den Capabilities bekanntgegeben. Die Bezeichner folgen der Namenskonvention für _meta-Schlüssel, ein Präfix ist Pflicht.

{
  "capabilities": {
    "tools": {},
    "extensions": { "io.modelcontextprotocol/tasks": {} }
  }
}

Auch für den Fall, dass nur eine Seite die Extension unterstützt, gibt es eine Regel: Die unterstützende Seite MUSS auf das Kernverhalten zurückfallen oder mit einem passenden Fehler ablehnen.

9. Deprecated — Roots, Sampling, Logging (SEP-2577)

Drei Funktionen wurden zur Abkündigung vorgemerkt. Während der Deprecation-Phase funktionieren sie vollständig weiter, neue Implementierungen sollen sie aber nicht mehr verwenden. Die Spec empfiehlt folgenden Ersatz.

Abgekündigt Ersatz
Roots Verzeichnisse und Dateien über Tool-Parameter, Ressourcen-URIs oder Serverkonfiguration übergeben
Sampling Direkte Anbindung an die API des LLM-Anbieters
Logging Bei stdio stderr, sonst OpenTelemetry

Weitere Dinge wurden gleich mit als deprecated eingestuft.

Wichtig ist hier die ebenfalls neu eingeführte Feature-Lifecycle-Policy. Sie definiert die drei Zustände Active / Deprecated / Removed; ein abgekündigtes Feature bleibt mindestens 12 Monate in der Spec, bevor es zur Entfernung ansteht. Das gilt allerdings nicht bedingungslos — greift die Ausnahme für beschleunigte Entfernung (expedited removal), verkürzt sich die Frist auf mindestens 90 Tage. Das ist etwa bei einem aktiven Sicherheitsrisiko der Fall. Die genannten Features verschwinden also nicht schon in der nächsten Revision, aber “ein Jahr lang auf jeden Fall sicher” ist die falsche Lesart.

10. Caching und Routing — leise Änderungen mit großer Praxiswirkung

Sie stehen nicht auf der Liste der Major Changes, wirken sich auf reale Implementierungen aber sofort aus.

Listenergebnisse sind cachebar geworden (SEP-2549). Die Ergebnisse von tools/list, prompts/list, resources/list, resources/read und resources/templates/list tragen verpflichtend ttlMs und cacheScope. ttlMs ist ein Frischehinweis in Millisekunden, cacheScope legt mit "public" / "private" fest, ob zwischengeschaltete Caches das Ergebnis teilen dürfen. Ziel ist weniger Polling.

Request-Header sind Pflicht geworden (SEP-2243). Jeder Streamable-HTTP-POST MUSS Mcp-Method und Mcp-Name mitführen. So lässt sich routen, ohne den Body zu parsen. Wer MCP-Traffic vor einem Reverse Proxy oder einer WAF unterscheiden musste, schaut jetzt nur noch auf die Header.

tools/list SOLLTE in deterministischer Reihenfolge antworten. Grund sind Client-Caching und die Trefferquote des LLM-Prompt-Caches. Wer die Tool-Liste aus einer Map zieht und sie jedes Mal in anderer Reihenfolge ausgibt, sollte sortieren — der Prompt-Cache dürfte bisher jedes Mal gebrochen sein.

OpenTelemetry-Trace-Kontext ist standardisiert (SEP-414). traceparent, tracestate und baggage werden über _meta propagiert.

11. Fehlercodes wurden neu nummeriert

Es gibt jetzt eine Vergabepolitik für Fehlercodes. Der JSON-RPC-Bereich für Serverfehler wird so aufgeteilt.

Entsprechend haben sich einige Nummern geändert.

Fehler Vorher Nachher
HeaderMismatch -32001 -32020
MissingRequiredClientCapability -32003 -32021
UnsupportedProtocolVersion -32004 -32022
Ressource nicht gefunden -32002 -32602 (Invalid Params)

Hier entsteht leicht ein Missverständnis: Die ersten drei Codes sind überhaupt erst in der Draft-Phase dieser Revision entstanden und existieren in Code, der eine offiziell veröffentlichte Vorgängerversion implementiert, gar nicht. Tatsächlich in bestehendem Code stecken kann nur die letzte Zeile.

Dass “Ressource nicht gefunden” von -32002 auf -32602 (Invalid Params) wechselt, dient der Angleichung an die JSON-RPC-Spezifikation. Wer diese Version implementiert, DARF -32002 NICHT (MUST NOT) mehr senden; Clients SOLLTEN -32002 von Servern älterer Versionen aber weiterhin akzeptieren.

12. Wer Cloudflare Workers nutzt — McpAgent ist abgekündigt

Am besten lässt sich am Beispiel Cloudflare zeigen, welche Wellen diese Spec-Änderung in realen Implementierungen schlägt. Am 6. August 2026 hat Cloudflare mit “The next generation of MCP” McpAgent abgeräumt.

Warum das die logische Konsequenz ist, ahnt man nach den Abschnitten 1 und 2. Bisher waren Durable Objects faktisch Pflicht, um einen MCP-Server in Workers zu betreiben: Man musste die über Mcp-Session-Id identifizierte Session und den daran hängenden SSE-Stream am Leben halten, also brauchte man etwas, das Anfragen an dieselbe Instanz bindet. Mit dem Wegfall der Session fällt diese Voraussetzung weg.

Cloudflare formuliert es so.

This release of the MCP 2026-07-28 specification … removes the need for McpAgent. While Durable Objects remain the right primitive when an application itself needs state, MCP itself no longer requires a Durable Object to speak the protocol.

Laut Dokumentation ist der aktuelle Status von McpAgent “deprecated and feature-frozen”. Unbrauchbar ist er damit nicht von heute auf morgen, aber neue Funktionen kommen nicht mehr dazu. Der Ersatz heißt createMcpHandler; die offizielle Beschreibung lautet, er erzeuge aus einer Server-Factory des MCP SDK v2 einen aufrufbaren, stateless MCP-Request-Handler.

export default {
  fetch(request, env, ctx) {
    return createMcpHandler(createServer)(request, env, ctx);
  },
} satisfies ExportedHandler;

Keine Durable-Object-Klasse, kein Session-Routing. Pro Anfrage wird der Server neu erzeugt, die Anfrage bearbeitet, fertig.

Auch hier lauert ein Missverständnis: Durable Objects sind nicht überflüssig geworden. Weggefallen ist nur das DO, das “zum Sprechen des MCP-Protokolls” nötig war. Braucht die Anwendung selbst Zustand, ist ein DO weiterhin das richtige Werkzeug. Die offizielle Dokumentation trifft genau diese Unterscheidung.

Store cross-request data behind an authenticated handle in a Durable Object, D1, KV, or R2 rather than an MCP session ID.

Genau darum ging es beim “explizit vom Server ausgestellten Handle” aus Abschnitt 1. Der Zustand liegt weiterhin in DO, D1, KV oder R2 — nur der Schlüssel, der auf ihn zeigt, ist jetzt ein authentifizierter Handle statt einer MCP-Session-ID.

Auch der Migrationsaufwand kommt nicht auf einen Schlag. Laut Cloudflare nimmt der /mcp-Endpunkt “sowohl das neue Protokoll als auch stateless Anfragen von Streamable-HTTP-Clients aus 2025” an. Selbst wenn es noch Nutzer mit alten Clients gibt, lässt sich der Server also zuerst umziehen.

Bei den Kosten ist Vorsicht geboten. Cloudflare spricht nur qualitativ von Einsparungen “durch weniger bewegliche Teile” und nennt keine konkreten Zahlen. Dass die Rechnung ohne DO-Instanzen tendenziell sinkt, ist klar — aber man sollte nicht mit einem bestimmten Prozentwert im Kopf herangehen.

13. Migrations-Checkliste

Wer einen Server betreibt, geht sie der Reihe nach durch.

Für Clients kommen noch zwei Punkte dazu.

Fazit

Die vier Tier-1-SDKs — TypeScript, Python, Go und C# — sprechen bereits zum Release-Zeitpunkt 2026-07-28. Das Rust-SDK unterstützt sie im Beta-Status. Auch die offizielle Ankündigung räumt ein, dass “für Entwickler, die sich auf Session-Identifier verlassen haben, ein gewisser Migrationsaufwand anfällt”.

Die Richtung ist dabei eindeutig: impliziten Verbindungszustand abbauen und alles explizit in die Anfrage selbst packen. Wer MCP-Server in Umgebungen betreibt, in denen Instanzen ständig kommen und gehen — Edge, serverless —, macht mit dieser Änderung kein Minus, sondern ein Plus. Der Grund, einen Session Store festzuhalten, ist schlicht entfallen.

Die Deprecation-Frist beträgt mindestens 12 Monate, es muss also nicht heute alles umgebaut werden. Eine Ausnahme gibt es allerdings: server/discover. Das ist keine Abkündigung, sondern eine neue Pflichtanforderung — wer sagen will, dass er die neue Spec unterstützt, muss sie jetzt einbauen.