CodeGym /Kurse /ChatGPT Apps /Handshake und Capabilities: wie der Client erfährt, was d...

Handshake und Capabilities: wie der Client erfährt, was der Server kann

ChatGPT Apps
Level 6 , Lektion 2
Verfügbar

1. Wozu braucht man den Handshake überhaupt

Wenn REST‑Endpunkte ein Satz einzelner Türen sind, an die man per URL klopfen kann, dann ist MCP eher ein fortlaufender Dialog über einen einzigen Kanal. Der Client schickt nicht einfach einzelne, voneinander getrennte Anfragen, sondern baut zuerst eine Sitzung auf. Der Handshake ist der Moment des Kennenlernens zu Beginn dieser Sitzung.

In MCP ist dieser Moment als spezielle Anfrage initialize umgesetzt, die der Client unmittelbar nach dem Aufbau des Transports sendet (STDIO, HTTP/stream, WebSocket – egal). In der Anfrage teilt er mit: „Ich spreche diese MCP‑Version, das kann ich, und das bin ich überhaupt.“ Der Server antwortet: „Ich unterstütze diese Version und diese Möglichkeiten, angenehm.“

Nach erfolgreichem Austausch sendet der Client die Benachrichtigung notifications/initialized und erst danach beginnt der Arbeitsalltag: tools/list, resources/list, tools/call und andere nützliche Dinge.

Zieht man eine Analogie, ist der MCP‑Handshake wie ein Mietvertrag, bevor man den Server ins Rechenzentrum bringt. Solange man sich nicht über die Regeln geeinigt hat (Protokollformat, welche Dienste das Rechenzentrum bereitstellt, wer die Kosten trägt) – ist es sinnlos, Server anzuliefern.

Aus praktischer Sicht löst der Handshake drei Aufgaben:

  1. Prüft die Kompatibilität der Protokollversionen.
  2. Deklariert, welche MCP‑„Primitiven“ der Server überhaupt unterstützt: tools, resources, prompts, Logging, Benachrichtigungen usw.
  3. Liefert Metainformationen über Client und Server – Name und Implementierungsversion.

2. Lebenszyklus einer MCP‑Verbindung: wo der Handshake stattfindet

Damit das nicht abstrakt wirkt, schauen wir uns ein typisches (vereinfachtes) Verbindungs‑Flow an:

sequenceDiagram
    participant C as Client (ChatGPT/Inspector)
    participant S as MCP-Server

    C->>S: (1) Transport aufbauen (STDIO/HTTP-stream)
    C->>S: (2) Request: "initialize"
    S-->>C: (3) Result: "initialize" (capabilities, serverInfo)
    C->>S: (4) Notification: "notifications/initialized"
    C->>S: (5) Request: "tools/list" / "resources/list"
    S-->>C: (6) Result: Listen der Tools/Ressourcen
    C->>S: (7) Request: "tools/call" usw.

Technisch sehen die Schritte so aus:

  1. Der Transport steht: Zum Beispiel startet ChatGPT euren Server als Subprocess und verbindet sich über STDIO, oder der Inspector stellt eine HTTP/stream‑Anfrage an /mcp.
  2. Der Client sendet die JSON‑RPC‑Anfrage initialize.
  3. Der Server antwortet mit einem JSON‑RPC‑Result mit den Feldern protocolVersion, capabilities und serverInfo.
  4. Der Client sendet die Notification notifications/initialized – das Signal: „Ich habe alles gelesen, wir können arbeiten.“
  5. Der Client ruft die Discovery‑Methoden auf (tools/list, resources/list, prompts/list) – abhängig davon, was er in den Server‑capabilities gesehen hat.
  6. Der Server liefert Metadaten zu Tools/Ressourcen/Prompts.
  7. Danach folgen die „Arbeits“-Requests: tools/call, resources/read usw.

Wichtig ist: Der Handshake ist lediglich ein normaler JSON‑RPC‑Call initialize. Keine Magie. Nach der Vorlesung zum MCP‑Nachrichtenformat könnt ihr solche Anfragen bereits parsen; der einzige Unterschied: Hier ist die Methode immer dieselbe, „besonders“, und sie wird als erste ausgeführt.

3. Was der Client in initialize sendet

Zerlegen wir die Anfrage initialize in Teile. So könnte eine minimale (für die Vorlesung vereinfachte) Anfrage aussehen:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "elicitation": {}
    },
    "clientInfo": {
      "name": "chatgpt-gift-client",
      "version": "2.3.0"
    }
  }
}

Dieses Beispiel liegt nahe an dem, was in der offiziellen MCP‑Dokumentation gezeigt wird. Die wichtigsten Felder in params:

protocolVersion

Eine Zeichenfolge mit der Version der MCP‑Spezifikation, meist im Datumsformat, z. B. "2025-06-18". Das ist nicht die Version eurer Anwendung, sondern die Version des Protokolls selbst. Der Client sagt: „Ich erwarte, diese MCP‑Version zu sprechen.“ Der Server muss sie in der Antwort entweder bestätigen oder einen Fehler zurückgeben, wenn er diese Version nicht kennt.

Das schützt vor der Situation „Der Client denkt das eine, der Server implementiert etwas anderes“. Wenn keine gemeinsame Version gefunden wird, sollte man die Verbindung lieber sauber trennen, statt inkompatible Nachrichten auszutauschen.

capabilities des Clients

Ein Objekt, in dem der Client deklariert, welche MCP‑Fähigkeiten er selbst unterstützt. Beispielsweise gibt der ChatGPT‑Client oft den Schlüssel elicitation an und signalisiert damit, dass er Anfragen an den Benutzer verarbeiten kann (zusätzliche Eingaben, Bestätigungen usw.).

Beispiel:

"capabilities": {
  "elicitation": {},
  "sampling": {}
}

Der Server kann diese Information nutzen, um zu verstehen, welche erweiterten Protokollfunktionen überhaupt sinnvoll sind. elicitation bedeutet zum Beispiel, dass der Client (ChatGPT) Rückfragen an den Nutzer stellen und zusätzliche Daten anfordern kann.

clientInfo

Einfache Metainformationen: Name und Version des Clients.

"clientInfo": {
  "name": "ChatGPT",
  "version": "2.0.0"
}

Aus Sicht der Serverentwickler ist das pures Gold für Logs: Ihr könnt immer sehen, welcher Client gerade verbunden ist – ChatGPT, MCP Inspector, euer eigener Test‑Client – und welche Versionsnummer er hat.

4. Was der Server antwortet: initialize result

Die Antwort auf initialize ist ein normales JSON‑RPC‑Result mit derselben id, aber im Feld result liegt die Beschreibung dessen, was der Server kann.

In der Anfrage haben wir uns die capabilities aus Sicht des Clients angesehen – was er selbst unterstützt. Jetzt betrachten wir das Spiegelobjekt in der Antwort: die capabilities des Servers, also was er beherrscht. Schematisch:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "tools": {
        "listChanged": true
      },
      "resources": {},
      "prompts": {},
      "logging": {}
    },
    "serverInfo": {
      "name": "gift-genius-backend",
      "version": "0.1.0"
    }
  }
}

Eine ähnliche Struktur findet ihr auch in der offiziellen Protokollbeschreibung und/oder in der Beschreibung des SDK. Die Hauptbestandteile:

protocolVersion in der Antwort

Der Server wiederholt entweder die vom Client vorgeschlagene Version oder (theoretisch) könnte er eine andere gemeinsame Version wählen, wenn es mehrere gibt. In typischen Implementierungen wird die Version des Clients einfach bestätigt, sofern der Server sie unterstützt. Falls nicht – muss der Server einen Fehler zurückgeben und die Kommunikation beenden.

serverInfo

Metainformationen über den Server: Name, Version.

"serverInfo": {
  "name": "gift-genius-backend",
  "version": "0.1.0"
}

Klingt unspektakulär, doch genau anhand dieser Daten filtert und sucht ihr später in Logs: „Warum kommt ChatGPT mit Version X mit unserem Server Version Y nicht klar?“

capabilities des Servers

Das interessanteste Feld. Hier deklariert der Server, welche MCP‑Primitiven und Erweiterungen er unterstützt: ob er tools/*, resources/*, prompts/* verarbeiten kann, ob er Benachrichtigungen über geänderte Listen senden kann usw.

Wenn in capabilities der Abschnitt tools fehlt, wird kein korrekt implementierter Client tools/list oder tools/call aufrufen. Genauso bedeutet das Fehlen von resources, dass der Client resources/list und resources/read nicht senden wird.

Damit sind capabilities eine leichte Form von Vertrag: „Was ist erlaubt, was nicht – mit diesem Server.“

5. Capabilities als „Liste der Superkräfte“

Im Folgenden interessiert uns nur noch die capabilities des Servers – jenes Objekt, das in der Antwort auf initialize kommt und festlegt, welche MCP‑Primitiven dieser Server überhaupt unterstützt.

Schauen wir uns die Struktur genauer an. Beispiel (vereinfacht, aber nah an der Spezifikation):

 {
"capabilities": {
  "tools": {
    "listChanged": true
  },
  "resources": {
    "subscribe": true,
    "listChanged": true
  },
  "prompts": {
    "listChanged": false
  },
  "logging": {}
}

Ein solches Beispiel wird in der offiziellen MCP‑Architektur erläutert. Entschlüsseln wir die Abschnitte.

Capabilities.tools

Das Vorhandensein des Schlüssels tools sagt: Der Server kann die Methoden tools/list und tools/call beantworten. Wenn dort außerdem das Flag listChanged: true vorhanden ist, bedeutet das, dass der Server künftig Benachrichtigungen tools/list_changed senden kann, wenn sich der Werkzeugsatz ändert.

Für ChatGPT ist das nützlich: Man kann die Werkzeugliste cachen und sie bei list_changed ohne kompletten Reconnect aktualisieren.

Capabilities.resources

Der Abschnitt resources erklärt, dass der Server mit Ressourcen arbeiten kann: resources/list, resources/read, ggf. Suche. Flags darin:

  • subscribe: true – der Client kann Änderungen an Ressourcen abonnieren (z. B. für Live‑Logs oder Datei‑Updates).
  • listChanged: true – der Server kann die Benachrichtigung resources/list_changed senden, wenn Ressourcen hinzukommen oder verschwinden.

Das ist besonders wichtig für große Verzeichnisse oder „lebende“ Daten, die sich laufend ändern.

Capabilities.prompts

Registriert der Server vordefinierte Prompts (z. B. domänenspezifische Vorlagen für Modellanfragen), erscheint in capabilities der Schlüssel prompts. Dort kann es ebenfalls ein listChanged-Flag geben.

Der Client erkennt anhand dieses Abschnitts, dass die Methode prompts/list verfügbar ist, und ggf. prompts/get.

Capabilities.logging und andere

Einige Server‑Implementierungen deklarieren auch logging – das heißt, der Server kann strukturierte Logs per MCP an den Client senden, etwa zum Debuggen.

Weitere Abschnitte können dazukommen (z. B. sampling oder spezifische Erweiterungen). Wichtig ist, dass das Protokoll von Anfang an als erweiterbar entworfen ist: Ihr könnt neue Schlüssel in den capabilities hinzufügen, und alte Clients ignorieren sie einfach, wenn sie sie nicht kennen.

Insight

Experimentell wurde festgestellt, dass die ChatGPT App gesendete listChanged-Nachrichten ignoriert. Beim Erstellen einer App könnt ihr derzeit nicht zunächst einen Satz Tools deklarieren und dann später weitere Tools hinzufügen oder entfernen – auch wenn das MCP‑Protokoll es erlaubt.

Zum Zeitpunkt der Erstellung dieses Kurses ist die Lage wie folgt: Zum Zeitpunkt der Registrierung eurer App im ChatGPT Store ruft ChatGPT die Liste der Tools und Resources von eurer App ab und cached sie dauerhaft. Die Wahrscheinlichkeit, dass sich die Situation im Laufe des Jahres 2026 ändert, ist hoch; die Wahrscheinlichkeit, dass sich im ersten Quartal 2026 etwas ändert, ist gering.

6. Discovery nach dem Handshake: wie man die Liste der Tools und Ressourcen erhält

Der Handshake beantwortet die Frage „Was kann der Server grundsätzlich?“ Der nächste Schritt ist das sogenannte Discovery: Der Client holt über konkrete Methoden Details – welche Tools es genau gibt, welche Ressourcen verfügbar sind, welche Prompts hinterlegt sind.

Dazu dienen Discovery‑Methoden: der Einfachheit halber tools/list, resources/list, prompts/list. In der MCP‑Architektur‑Dokumentation wird empfohlen, genau so zu erklären: Handshake → Discovery → Tool‑Aufrufe.

Beispielanfrage tools/list:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list",
  "params": {}
}

Die Serverantwort enthält ein Array von Tools: Namen, Beschreibungen, JSON Schema der Argumente und manchmal Metadaten wie Kategorien oder Icons.

Danach cached ChatGPT (oder ein anderer Client) die Liste und nutzt sie während des Dialogs, um:

  • ein passendes Tool für die Aufgabe des Nutzers auszuwählen;
  • zu prüfen, ob der Tool‑Name existiert;
  • Argumente zu validieren, bevor tools/call gesendet wird.

Bei Ressourcen ist es ähnlich, nur dass resources/list oft Paginierung über Cursor unterstützt, damit nicht sofort eine Million Einträge übertragen werden. Das ist ebenfalls in der MCP‑Spezifikation beschrieben und wird als typischer Fall für große Verzeichnisse behandelt.

7. Handshake und Capabilities am Beispiel unserer App GiftGen

In den vorigen Modulen haben wir eine Lern‑App gebaut, die bei der Geschenkfindung hilft. Wir haben bereits ein Widget, es gibt das Tool suggest_gifts im Backend und einen Geschenkkatalog. Jetzt stellen wir uns vor, wie der Handshake für den MCP‑Server gift-genius aussieht.

Beispiel‑Handshake für GiftGen

Anfrage vom Client:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "elicitation": {}
    },
    "clientInfo": {
      "name": "ChatGPT",
      "version": "2.1.0"
    }
  }
}

Antwort unseres Servers:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "tools": { "listChanged": true },
      "resources": { "listChanged": true },
      "prompts": {},
      "logging": {}
    },
    "serverInfo": {
      "name": "gift-genius-backend",
      "version": "0.2.0"
    }
  }
}

Im Grunde wiederholen wir fast die Beispiele aus der offiziellen MCP‑Architektur und passen lediglich die Namen an unsere App an.

Was der Client aus dieser Antwort erfährt:

  • Es gibt Tools (tools), und die Liste kann sich dynamisch ändern (listChanged: true).
  • Es gibt Ressourcen (unser Geschenkkatalog, eventuell in Dateien oder einer Datenbank gespeichert).
  • Es gibt Prompts (z. B. eine Vorlage „Formuliere eine kurze Beschreibung des Geschenks für Nutzer N“).
  • Der Server kann Logs senden (praktisch für Inspector‑Tools und Debugging).

Anschließend ruft der Client tools/list auf und sieht dort z. B. dieses Tool:

{
  "name": "suggest_gifts",
  "description": "Sammelt Geschenkideen anhand des Profils des Empfängers.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "age": { "type": "integer" },
      "relationship": { "type": "string" },
      "budget": { "type": "number" }
    },
    "required": ["age", "relationship"]
  }
}

Und nun, wenn ein Nutzer etwas schreibt wie: „Schlage ein Geschenk für die Schwester vor, 25 Jahre, Budget bis 50 Dollar“, weiß das Modell bereits: Es gibt das Tool suggest_gifts mit diesen Argumenten; es kann über tools/call aufgerufen werden.

8. Wie das SDK den Handshake versteckt (und warum es trotzdem wichtig ist, ihn zu verstehen)

Im TypeScript‑SDK für MCP (das wir in der nächsten Vorlesung verwenden) ist die ganze Geschichte mit initialize und notifications/initialized in der Methode connect gekapselt. Beispielhafter Code:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new McpServer({
  name: "gift-genius",
  version: "1.0.0",
});

// Registrierung des Tools – das SDK konfiguriert capabilities.tools daraufhin automatisch
server.tool(
  "suggest_gifts",
  {
    description: "Sammelt Geschenkideen.",
    inputSchema: {
      type: "object",
      properties: {
        age: { type: "integer" },
        relationship: { type: "string" },
        budget: { type: "number" },
      },
      required: ["age", "relationship"],
    },
  },
  async (input) => {
    // ... Logik zur Auswahl von Geschenken ...
    return { suggestions: [] };
  },
);

const transport = new StdioServerTransport();

// Hier erledigt das SDK:
// 1) es nimmt initialize vom Client entgegen,
// 2) antwortet mit serverInfo und capabilities,
// 3) wartet auf notifications/initialized,
// 4) und beginnt dann mit der Verarbeitung der tools/*-Aufrufe.
await server.connect(transport);

Das SDK sammelt die capabilities automatisch auf Basis dessen, was ihr registriert: Gibt es mindestens ein server.tool(...), fügt es in den capabilities den Abschnitt tools hinzu. Wenn ihr Ressourcen oder Prompts registriert, erscheinen resources und prompts.

Das Verständnis von Handshake und Capabilities braucht ihr nicht, um JSON per Hand zu schreiben (tut das nie), sondern um:

  • MCP‑Logs zu lesen und zu verstehen, warum der Client eure Tools „nicht sieht“;
  • Versionsinkompatibilitäten des Protokolls zu diagnostizieren;
  • bei Bedarf einen Custom‑Server oder einen nicht standardmäßigen Transport zu implementieren.

9. Protokollversionen und Evolution der Fähigkeiten

Das Feld protocolVersion im Handshake ist keine Zierde. In der MCP‑Spezifikation wird ausdrücklich betont: Es dient dazu, eine kompatible Protokollversion auszuhandeln; wenn keine gemeinsame Version gefunden wird, sollte die Verbindung beendet werden.

Typisches Szenario:

  1. Ihr rollt einen MCP‑Server in Production mit einem SDK aus, das MCP in Version "2025-06-18" implementiert.
  2. Nach einiger Zeit erscheint eine neue MCP‑Version, ihr aktualisiert den Client, aber der Server ist noch alt.
  3. Der Client sendet protocolVersion: "2026-02-01", der Server kennt diese Version nicht und liefert einen Fehler invalid protocol version (oder etwas Vergleichbares) zurück.

Die Praxis zeigt: Entwickler ignorieren dieses Feld oft und wundern sich dann, warum die Verbindung nicht zustande kommt.

Der richtige Umgang mit Versionen:

  • Immer wissen, welche MCP‑Version euer SDK unterstützt (steht normalerweise in Doku/Release Notes).
  • Beim SDK‑Update – die Protokollversion bewusst aktualisieren.
  • Logs und Monitoring sollten Initialisierungsfehler aufgrund nicht übereinstimmender protocolVersion klar anzeigen.

Auch die Erweiterung der Fähigkeiten über capabilities ist an die Evolution gebunden: Neue MCP‑Funktionen werden als neue Schlüssel in capabilities eingeführt. Alte Clients ignorieren sie, neue können sie nutzen. Genau dieses Muster beschreibt die offizielle MCP‑Dokumentation als Weg, Abwärtskompatibilität zu wahren.

10. Der Handshake aus der Sicht von ChatGPT und Inspector

Was ChatGPT beim Verbinden eines MCP tut

Wenn ihr im Dev Mode einen MCP‑Server an ChatGPT bindet, macht die Plattform „hinter den Kulissen“ ungefähr Folgendes:

  1. Öffnet den Transport (typisch HTTP/stream auf /mcp).
  2. Sendet initialize mit protocolVersion, capabilities und clientInfo (etwa „ChatGPT Enterprise, Version soundso“).
  3. Empfängt die Antwort und cached die Server‑Capabilities.
  4. Ruft tools/list, resources/list, prompts/list auf – abhängig von den gesehenen Capabilities.
  5. Während des Dialogs, wenn das Modell ein Tool aufrufen möchte, gleicht es mit diesem Cache ab: Gibt es dieses Tool, wie sieht sein Argument‑Schema aus, und wie wird der Aufruf formatiert?

Wenn die Capabilities des Servers kein tools enthalten, wird ChatGPT eure App nicht einmal als Tool anbieten. Wenn in den Capabilities resources vorhanden sind, aber darin kein listChanged-Flag, kann ChatGPT die Ressourcenliste cachen und wartet nicht auf Änderungsbenachrichtigungen.

Wie Inspector‑Tools und MCP Jam beim Debuggen helfen

Tools wie MCP Jam / MCP Inspector machen praktisch dasselbe: Sie stellen eine Verbindung her, führen den Handshake aus, zeigen euch die Capabilities des Servers und ermöglichen euch, tools/list, tools/call usw. manuell aufzurufen.

Aus Entwicklersicht ein Must‑have:

  • man sieht, welche protocolVersion der Server tatsächlich geliefert hat;
  • man sieht sofort, ob in den Capabilities tools, resources, prompts vorhanden sind;
  • man kann verstehen, warum ChatGPT die Tools nicht sieht (Capabilities nicht deklariert oder Handshake nicht abgeschlossen).

In der letzten Vorlesung dieses Moduls werdet ihr solche Tools intensiver nutzen, aber schon jetzt ist es hilfreich zu verstehen, dass sie genau auf dem Handshake arbeiten, den wir hier besprechen.

11. Typische Fehler im Umgang mit Handshake und Capabilities

In der Theorie wirkt alles recht geradlinig, in der Praxis sind aber gerade Handshake und die Deklaration der Capabilities oft die Quelle sehr einfacher Bugs – insbesondere im Dev Mode oder im MCP Inspector. Im Folgenden ein paar typische Fehler, auf die ihr mit hoher Wahrscheinlichkeit stoßen werdet – im eigenen Code oder in den Logs von Kolleginnen/Kollegen.

Fehler Nr. 1: Falsches Format der initialize‑Anfrage.
Ein sehr häufiges Problem bei einer manuellen MCP‑Server‑Implementierung ohne SDK ist, irgendein Pflichtfeld von JSON‑RPC zu vergessen. Zum Beispiel jsonrpc: "2.0" weglassen, method verwechseln (statt "initialize" "init" schreiben) oder capabilities als booleschen Wert statt als Objekt senden. Die MCP‑Spezifikation erwartet ein klares Format; Abweichungen führen zu Parserfehlern und zum Abbruch der Verbindung. Doku und Praxisguides empfehlen ausdrücklich, zuerst sicherzustellen, dass initialize strikt der Spezifikation entspricht, bevor man nach anderen Ursachen sucht.

Fehler Nr. 2: Ignorieren der protocolVersion.
Manchmal kopieren Entwickler einfach ein Beispiel aus der Doku und tragen eine beliebige Zeichenfolge ein, ohne auf die Unterstützung im SDK zu achten. Ergebnis: Client und Server sprechen unterschiedliche MCP‑Versionen, und die Verbindung kommt nicht zustande. Der Fehler kann sich als „Der Client verbindet sich gar nicht“ tarnen. Man sollte protocolVersion als echten Vertrag betrachten: Diese Version muss zwischen dem Team der Frontend/Agent‑Plattform und dem Team, das den MCP‑Server schreibt, abgestimmt werden.

Fehler Nr. 3: Vergessene Capabilities.
Klassischer Fall: Ihr habt ein Tool auf dem Server registriert, aber bei der manuellen Handshake‑Implementierung vergessen, "tools": {} in die capabilities der initialize-Antwort aufzunehmen. Im Inspector seht ihr, dass Tools existieren, aber ChatGPT zeigt „No tools available“ – denn ChatGPT vertraut den Capabilities und ruft tools/list nicht auf, wenn der Abschnitt tools dort fehlt. Troubleshooting‑Guides für das Apps SDK betonen ausdrücklich: Wenn ChatGPT keine Tools sieht, prüft zuerst die Capabilities.

Fehler Nr. 4: Verwendung von Methoden, die in den Capabilities nicht deklariert sind.
Studierende experimentieren manchmal und senden z. B. resources/list an einen Server, dessen Capabilities keinen resources-Abschnitt haben. Formal kann der Server mit Method not found antworten, korrekter ist es aber, solche Methoden gar nicht aufzurufen. MCP führt Capabilities ausdrücklich als Schutz gegen solche Versuche ein. Der Client sollte zuerst prüfen, ob der entsprechende Abschnitt in den Capabilities vorhanden ist, und erst dann Methoden aufrufen.

Fehler Nr. 5: Der Server beginnt zu „plaudern“, bevor notifications/initialized eingetroffen ist.
Wenn der Server unmittelbar nach der Antwort auf initialize beginnt, Logs oder Benachrichtigungen zu senden, ohne auf notifications/initialized zu warten, ignorieren manche Clients diese Nachrichten oder trennen sogar die Verbindung. In der offiziellen MCP‑Architektur wird betont, dass der Handshake zuerst abgeschlossen sein muss, und erst nach der Initialisierungs‑Notification beginnt der „Arbeits“-Teil.

Fehler Nr. 6: Änderung von Tool‑Schemata ohne Signal über eine geänderte Liste.
Wenn ihr das JSON‑Schema eines Tools ändert (ein Feld wird erforderlich, ein Argument wird umbenannt), den Server aber nicht neu startet oder keine Benachrichtigung darüber sendet, dass sich die Tool‑Liste geändert hat, kann der Cache des Clients noch die alte Version des Schemas enthalten. Das führt zu seltsamen Validierungsfehlern. Die Spezifikation schlägt vor, das Flag listChanged sowie die Benachrichtigungen tools/list_changed und resources/list_changed zu verwenden, um dem Client beim rechtzeitigen Cache‑Update zu helfen.

Fehler Nr. 7: Verfrühte Optimierung und „Magie“ rund um Capabilities.
Manchmal entwickeln Teams komplexe Schemata mit dynamischer Generierung der Capabilities, Versionierung nach Clients und anderen Exoten, ohne die Basismekanismen verstanden zu haben. Am Anfang reicht es, ehrlich anzugeben, was der Server kann: tools, resources, prompts, logging. Capabilities sollte man nach echter Notwendigkeit erweitern – nicht „auf Vorrat“. Das ist eher ein organisatorischer Anti‑Pattern als ein rein protokollarischer Fehler, trifft in produktiven Projekten aber sehr häufig auf.

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION