BeiträgeFachartikel

MCP, was ohne Sitzung übrig bleibt

Die Protokollfassung 2026-07-28 des Model Context Protocol streicht Handshake, Sitzung und Wiederaufnahme. Was an ihre Stelle tritt, wer davon profitiert, und welche Paarungen aus Client und Server danach schlicht nicht mehr funktionieren.

FachartikelStand Lesezeit 8 min

Ein Handshake ist eine kleine Sache mit großer Wirkung. Zwei Gegenstellen tauschen einmal aus, wer sie sind und was sie können, und danach kann jede folgende Nachricht kurz sein, weil beide Seiten den Kontext schon haben. Genau das hat das Model Context Protocol seit November 2024 getan, und genau das ist in der Fassung 2026-07-28 gestrichen.

Der Verzicht klingt nach einer Optimierung für Rechenzentren. Er ist eine Entscheidung darüber, wo Zustand liegen darf, und er verschiebt Arbeit von den Servern zu den Clients. Dieser Text geht die Änderungen der Reihe nach durch, mit den Stellen aus der Spezifikation, an denen sie stehen.

Was bisher galt

Bis einschließlich der Fassung 2025-11-25 lief eine Verbindung so ab: Der Client schickt initialize, der Server antwortet mit seinen Fähigkeiten, der Client bestätigt mit notifications/initialized. Über HTTP konnte der Server dabei eine Sitzung vergeben, sichtbar als Header Mcp-Session-Id, die der Client fortan mitschickte. Ein zweiter Kanal stand offen: Per HTTP GET konnte der Client einen dauerhaften Ereignisstrom öffnen, über den der Server von sich aus Anfragen stellen durfte. Riss die Verbindung, ließ sich der Strom über Last-Event-ID an der Abbruchstelle wieder aufnehmen.

Für den Betrieb hieß das: Anfragen desselben Clients mussten auf derselben Instanz landen, oder alle Instanzen brauchten einen gemeinsamen Sitzungsspeicher. Wer vor den Server einen Übergang stellte, musste in die Nachrichten hineinsehen, um zu wissen, was durchgeht. Das ist der Aufwand, gegen den sich die neue Fassung richtet.

Was jetzt in jeder Anfrage steht

Der Handshake entfällt ersatzlos, ebenso die Sitzung. Was einmal ausgetauscht wurde, reist jetzt bei jedem Aufruf mit. Über HTTP sieht ein Tool Call so aus, hier gekürzt aus dem Transportabschnitt der Spezifikation:

POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "location": "Seattle, WA" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

Drei Dinge sind daran neu. Erstens die Angaben im Feld _meta, die früher aus dem Handshake kamen. Zweitens die Header Mcp-Method und Mcp-Name, die Werte aus dem Nachrichtenkörper spiegeln, damit ein Lastverteiler routen kann, ohne die Nachricht zu lesen. Drittens die Pflicht, dass beide Angaben übereinstimmen. Tun sie es nicht, muss der Server mit 400 Bad Request und dem Fehlercode -32020 ablehnen.

Diese dritte Regel ist die interessanteste, weil sie eine Angriffsfläche schließt, die mit der zweiten erst entsteht. Sobald ein Übergang nach dem Header entscheidet und der Server nach dem Inhalt handelt, gibt es zwei Wahrheiten über dieselbe Anfrage. Die Spezifikation begründet die Prüfpflicht genau damit. Wer eine Regel „dieser Mandant darf dieses Tool nicht“ am Übergang durchsetzt, muss sicher sein, dass der Server dasselbe liest.

Für Tool-Parameter gibt es dieselbe Spiegelung als Wahlmöglichkeit: Ein Server kann einzelne Parameter über x-mcp-header als Header Mcp-Param-{Name} ausweisen lassen, etwa eine Region. Werte, die sich nicht als reines ASCII darstellen lassen, werden dabei in einer eigenen Base64-Schreibweise übertragen.

Aushandeln ohne Aushandlung

Ohne Handshake gibt es keinen Moment, in dem sich beide Seiten auf eine Fassung einigen. Die Versionierungsseite sagt das unmissverständlich: „There is no negotiation handshake.“ Jede Anfrage nennt ihre Fassung, und der Server nimmt sie an oder lehnt sie ab. Lehnt er ab, antwortet er mit UnsupportedProtocolVersionError und listet auf, was er kann. Der Client sucht sich daraus etwas aus und stellt die Anfrage erneut.

Wer es vorher wissen will, ruft server/discover. Diese Methode muss jeder Server anbieten, jeder Client darf sie benutzen, keiner muss. Damit ist der Handshake nicht wirklich verschwunden, er ist zur Wahlmöglichkeit geworden.

Die eigentliche Umkehr: der Server fragt nicht mehr

Die tiefste Änderung steht nicht bei den Headern. Bisher konnte ein Server den Client um etwas bitten, während er an einer Aufgabe arbeitete: um eine Modellantwort (Sampling), um eine Rückfrage an den Menschen (Elicitation), um die Liste der zugänglichen Verzeichnisse (Roots). Solche Anfragen liefen über den offenen Ereignisstrom. Ohne dauerhaften Kanal gibt es diesen Weg nicht mehr.

An seine Stelle tritt ein Muster mit dem Namen Multi Round-Trip Requests. Der Server antwortet auf die Anfrage mit einem Zwischenergebnis, das sagt, was ihm fehlt:

{
  "resultType": "input_required",
  "inputRequests": {
    "confirm": {
      "type": "elicitation",
      "message": "Delete 3 files?",
      "schema": { "type": "boolean" }
    }
  },
  "requestState": "eyJzdGVwIjoxLCJmaWxlcyI6WyJhIiwiYiIsImMiXX0="
}

Der Client besorgt die Antwort und stellt die ursprüngliche Anfrage noch einmal, diesmal mit den Antworten und dem zurückgereichten requestState. Der Server verpackt darin, was er sich merken muss, weil er es sich nicht mehr merken darf.

Daraus folgt eine kleine, leicht zu übersehende Pflicht: Jedes Ergebnis hat jetzt ein Feld resultType. Ergebnisse von Servern älterer Fassungen, denen das Feld fehlt, müssen Clients als abgeschlossen behandeln.

Für Benachrichtigungen über Änderungen, etwa wenn sich die Tool-Liste ändert, gibt es weiterhin einen langlebigen Strom. Er wird nur anders geöffnet: mit einer Anfrage subscriptions/listen, deren Antwort selbst der Strom ist. Der Client meldet dabei an, welche Arten von Meldungen er hören will.

Was der Betrieb gewinnt

Drei Punkte, die zusammen den Anlass für die ganze Umstellung bilden.

Beliebige Verteilung. Ohne Sitzung darf jede Anfrage auf jeder Instanz landen. Die Ankündigung formuliert es als das Ende einer Sonderbehandlung: Was bisher haftende Zuordnung, gemeinsamen Sitzungsspeicher und Paketinspektion brauchte, „can now run behind a plain round-robin load balancer“.

Caching. Ergebnisse von Listenabfragen bekommen künftig zwei Pflichtfelder, ttlMs als Hinweis auf die Haltbarkeit und cacheScope mit den Werten public oder private. Das ist die Übertragung von Cache-Control auf das Protokoll. Zusätzlich sollen Server ihre Tool-Liste in stabiler Reihenfolge ausgeben, weil das die Trefferquote im Prompt-Cache der Modelle erhöht.

Nachvollziehen. Für die Weitergabe von Ablaufverfolgung sind die W3C-Schlüssel traceparent, tracestate und baggage in _meta festgelegt. Damit ist ein Tool Call über Systemgrenzen hinweg messbar, mit vorhandener Technik statt mit protokolleigener.

Was verloren geht

Die Wiederaufnahme. Der Satz aus dem Transportabschnitt ist so knapp wie seine Folge: „Resumable SSE streams via Last-Event-ID are not supported.“ Reißt die Verbindung während einer laufenden Anfrage, ist die Anfrage verloren, und der Client muss sie mit neuer Kennung neu stellen. Bei einem Tool, das Sekunden braucht, ist das eine Fußnote. Bei einem Aufruf, der Minuten läuft und Nebenwirkungen hat, ist es eine Entwurfsfrage: Wiederholbarkeit muss jetzt in der Anwendung stecken.

Das Abbruchsignal. Über HTTP gibt es keine Abbruchmeldung mehr. Das Schließen des Antwortstroms ist das Signal: „Closing the SSE response stream MUST be treated by the server as cancellation of that request.“ Für einen Server heißt das, dass er auf geschlossene Verbindungen achten muss, wenn er lange Arbeiten nicht ins Leere laufen lassen will.

Der Zustand. Er ist umgezogen. Die Änderungsliste beschreibt den Ersatz: „Servers that need cross-call state use explicit, server-minted handles passed as ordinary tool arguments.“ Ein Warenkorb bekommt also eine Kennung, die als gewöhnliches Argument durch die Tool Calls wandert. Das ist saubere HTTP-Praxis. Es heißt aber auch, dass diese Kennung durch das Modell hindurchgeht, und ein Modell, das eine Kennung verwechselt oder erfindet, ist ein Fehlerbild, das es vorher nicht gab.

Wer nach dem Umstieg nicht mehr miteinander spricht

Die Versionierungsseite führt eine Matrix über alle Kombinationen aus alter und neuer Gegenstelle. Zwei Zeilen darin lauten schlicht „Fails“: ein neuer Client an einem alten Server, und ein alter Client an einem neuen Server. Für den zweiten Fall gilt der Satz: Alte Clients haben keinen Weg nach vorn. Sie schicken initialize, und ein rein moderner Server kennt diese Methode nicht.

Der Ausweg heißt Zweigleisigkeit. Ein Server darf beide Zeitalter bedienen und entscheidet anhand der ersten Anfrage, welches gemeint ist. Ein Client darf erst modern anfragen und beim Fehlschlag prüfen, ob die Fehlerantwort selbst modern aussieht. Wichtig ist dabei eine Feststellung, die Fehlversuche spart: „The era determination is a property of the server, not of an individual request.“ Wer es einmal weiß, soll es sich merken.

Abgekündigt, mit Frist

Drei Bestandteile sind als abgekündigt markiert: Roots, Sampling und Logging. Sie funktionieren weiter, „These features remain fully functional during the deprecation window but new implementations should not add support for them.“ Vorgeschlagen wird jeweils ein gewöhnlicher Ersatz: Verzeichnisse als Tool-Parameter oder Ressourcenadresse statt Roots, die direkte Anbindung an eine Modell-Schnittstelle statt Sampling, Ausgabe nach stderr oder OpenTelemetry statt Logging.

Neu ist dabei weniger die Abkündigung als die Politik dahinter: Die Fassung führt einen Lebenszyklus mit den Zuständen aktiv, abgekündigt und entfernt ein, mit mindestens zwölf Monaten zwischen den letzten beiden. Für ein Protokoll, das Ende 2024 gestartet ist und seither in schneller Folge Fassungen ausgeliefert hat, ist eine verbindliche Frist die eigentliche Nachricht. Sie macht Planung möglich.

Ebenfalls gestrichen, ohne Frist: ping, logging/setLevel und die Meldung über geänderte Roots. Der Protokollstand für Meldungen wird jetzt je Anfrage gesetzt.

Was das praktisch heißt

Wer MCP nur benutzt, merkt davon zunächst wenig. Die Arbeit liegt bei denen, die Server und Clients bauen. Vorabfassungen der Bibliotheken für Python, TypeScript, Go und C# gibt es seit dem 29. Juni 2026. Für Python empfiehlt die Ankündigung ausdrücklich, in Abhängigkeiten eine Obergrenze zu setzen, damit die neue Hauptversion nicht ungefragt einzieht. Für TypeScript liegt ein Werkzeug bei, das den Quelltext umschreibt.

Die nüchterne Einschätzung für eigene Umgebungen: Lokale Server über stdio sind von der Skalierungsfrage nicht betroffen, wohl aber vom Wegfall des Handshakes. Wer Server im Netz betreibt, gewinnt sofort etwas, sobald mehr als eine Instanz läuft. Und wer Tools gebaut hat, die sich zwischen zwei Aufrufen etwas merken, hat Arbeit vor sich, weil dieses Merken jetzt sichtbar durch die Aufrufe wandern muss.

Was dieser Text nicht sagt

Alle Angaben stammen aus der Änderungsliste, dem Transport- und dem Versionierungsabschnitt der Spezifikation sowie aus der Ankündigung vom 21. Mai 2026, abgerufen am 28.07.2026. Die Verweise zeigen auf die feste Fassung 2026-07-28 statt auf den Entwurfspfad: Der wandert mit der nächsten Fassung weiter und belegt deshalb nichts.

Hier steht keine Erfahrung mit der neuen Fassung im Betrieb. Ob das Wiederholungsmuster bei Rückfragen in der Praxis angenehm zu programmieren ist, ob Modelle mit durchgereichten Kennungen zuverlässig umgehen, und wie viele Server die Zweigleisigkeit tatsächlich anbieten, lässt sich am Tag der Veröffentlichung nicht sagen. Es lässt sich messen, später.

Quellen

6 Einträge, davon 2 Schlüsselarbeitenalle erreichbar

Erreichbarkeit automatisch geprüft

Zurück zu allen Beiträgen

Tippen Sie los.

↑↓ auswählenEnter öffnenDie Suche läuft im Browser. Nichts wird übertragen.