Lässt es sich mit cremefarbenem Papier, einer Tönung, mehr Kontrast oder größerer Schrift besser lesen? Wählen Sie Ihre Farben und Ihre Schrift, einmalig für alle Seiten.

Kostenlose Lektion

Der MCP-Handshake mit initialize

Nach dieser Lektion: Ich kann eine initialize-Anfrage beantworten und sagen, was mein Server kann.

Lektion, 70 Min.7 BefehleLab für KI-Coding-Agenten: mit opencode Code erklären und reparieren lassen und die Arbeit prüfen

Wie ein MCP-Server initialize beantwortet

Der Handshake ist der erste Austausch zwischen einem MCP-Client und einem Server. Der Client sendet initialize mit der Version, die er will. Der Server antwortet mit der Version, die er nutzt, und mit dem, was er kann.

Das ist wichtig, weil ein Client nur nutzt, was der Server als sein Angebot nennt. Ein Server, der zu viel behauptet, bringt den Client zum Scheitern.

Am Ende dieser Lektion

Notiz

Ich kann eine initialize-Anfrage beantworten und sagen, was mein Server kann.

Schlüsselwörter

BegriffWas er bedeutetBeispiel
Handshakeder erste Austausch, der eine Sitzung aufbaut
Protokollversiondas Datum, das eine Fassung der Regeln benennt2024-11-05
Fähigkeiteine Gruppe von Funktionen, die der Server zu haben angibttools
Zustandwas sich der Server merkt: neu, wartend oder bereit
Aushandelnsich auf eine Version einigen, die beide Seiten sprechen

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Der Server wählt eine Version, die er kennt

Der Client nennt eine Version. Der Server führt eine Liste der Versionen, die er spricht. Steht die verlangte auf der Liste, antwortet der Server mit ihr.

Wenn nicht, lehnt dieser Server mit dem Code -32602 ab. Er legt die verlangte Version und seine eigene Liste in den Fehler, damit der Client es noch einmal versuchen kann.

Beispiel: drei Clients fragen an

Client verlangtServer sprichtServer antwortet
2024-11-052025-03-26, 2024-11-05Ein Ergebnis mit 2024-11-05
2025-03-262025-03-26, 2024-11-05Ein Ergebnis mit 2025-03-26
1999-01-012025-03-26, 2024-11-05Fehler -32602 mit beiden Listen

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Ein Server meldet nur, was er tut

Das Ergebnis von initialize enthält capabilities, die Fähigkeiten. Jede ist eine Gruppe von Methoden, die der Server hat: tools, resources, prompts oder logging.

Eine Fähigkeit kann Schalter tragen. listChanged sagt, dass der Server dem Client mitteilt, wenn sich seine Liste ändert. Dieser Server tut das nie, also steht dort false. Eine Methode aus einer nicht gemeldeten Gruppe wird mit -32601 beantwortet.

Ein häufiger Fehler

Warnung

Viele melden vorsichtshalber jede Fähigkeit. Der Client ruft dann Methoden auf, die der Server nicht hat. Melden Sie nur, was Sie geschrieben und getestet haben. Eine Angabe ist ein Versprechen.

Modell-Helfer schreiben

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const basis = process.env.AI_URL || \"http://ai:4000\";' 'async function fragen(nachrichten, probe, max) {' '  try {' '    const res = await fetch(basis + \"/v1/chat/completions\", { method: \"POST\", headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" }, body: JSON.stringify({ model: \"lab\", messages: nachrichten, max_tokens: max || 80 }), signal: AbortSignal.timeout(30000) });' '    if (res.ok === false) throw new Error(\"Status \" + res.status);' '    const daten = await res.json();' '    return { text: daten.choices[0].message.content, aufgezeichnet: false };' '  } catch (fehler) {' '    console.log(\"Aufgezeichnete Probe: Kein Modell hat geantwortet (\" + fehler.message + \").\");' '    return { text: probe, aufgezeichnet: true };' '  }' '}' 'module.exports = { fragen };' > model.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Server schreiben, Teil 1

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const UNTERSTUETZT = [\"2025-03-26\", \"2024-11-05\"];' 'let zustand = \"neu\";' 'function senden(m) { process.stdout.write(JSON.stringify(Object.assign({ jsonrpc: \"2.0\" }, m)) + \"\n\"); }' 'function antworten(id, ergebnis) { senden({ id: id, result: ergebnis }); }' 'function fehler(id, code, text, daten) { senden({ id: id, error: { code: code, message: text, data: daten } }); }' 'function initialisieren(nachricht) {' '  const gewuenscht = (nachricht.params || {}).protocolVersion;' '  if (UNTERSTUETZT.indexOf(gewuenscht) < 0) return fehler(nachricht.id, -32602, \"Protokollversion nicht unterstützt\", { requested: gewuenscht, supported: UNTERSTUETZT });' '  zustand = \"wartend\";' '  antworten(nachricht.id, { protocolVersion: gewuenscht, capabilities: { tools: { listChanged: false } }, serverInfo: { name: \"mensa\", version: \"0.2\" } });' '}' 'function verarbeiten(nachricht) {' > server2.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Server schreiben, Teil 2

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  if (nachricht.id === undefined) {' '    if (nachricht.method === \"notifications/initialized\" && zustand === \"wartend\") zustand = \"bereit\";' '    return;' '  }' '  if (nachricht.method === \"ping\") return antworten(nachricht.id, {});' '  if (nachricht.method === \"initialize\") return zustand === \"neu\" ? initialisieren(nachricht) : fehler(nachricht.id, -32600, \"Schon initialisiert\");' '  if (zustand === \"neu\" || zustand === \"wartend\") return fehler(nachricht.id, -32600, \"Nicht initialisiert\");' '  if (nachricht.method === \"tools/list\") return antworten(nachricht.id, { tools: [] });' '  fehler(nachricht.id, -32601, \"Method not found: \" + nachricht.method);' '}' 'require(\"readline\").createInterface({ input: process.stdin }).on(\"line\", function (zeile) {' '  let nachricht;' >> server2.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Server schreiben, Teil 3

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  try { nachricht = JSON.parse(zeile); } catch (problem) { return fehler(null, -32700, \"Parse error\"); }' '  verarbeiten(nachricht);' '});' >> server2.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Skript-Client schreiben, Teil 1

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' 'const server = require(\"child_process\").spawn(\"node\", [\"server2.js\"]);' 'const start = function (id, version) { return { id: id, method: \"initialize\", params: { protocolVersion: version, capabilities: {}, clientInfo: { name: \"demo\", version: \"0.1\" } } }; };' 'const skript = [' '  { id: 1, method: \"tools/list\" },' '  start(2, \"1999-01-01\"),' '  start(3, \"2024-11-05\"),' '  { id: 4, method: \"tools/list\" },' '  { method: \"notifications/initialized\" },' '  { id: 5, method: \"tools/list\" },' '  { id: 6, method: \"resources/list\" },' '];' 'const gesehen = [];' 'require(\"readline\").createInterface({ input: server.stdout }).on(\"line\", function (zeile) {' '  console.log(\"<- \" + zeile);' '  gesehen.push(JSON.parse(zeile));' '  if (gesehen.length === 6) server.stdin.end();' '});' 'skript.forEach(function (m) {' > client2.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Skript-Client schreiben, Teil 2

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  const ganz = Object.assign({ jsonrpc: \"2.0\" }, m);' '  console.log(\"-> \" + JSON.stringify(ganz));' '  server.stdin.write(JSON.stringify(ganz) + \"\n\");' '});' 'server.on(\"close\", async function () {' '  const faehig = JSON.stringify(gesehen[2].result.capabilities);' '  const frage = \"Sagen Sie in einem Satz, was ein Server mit diesen Fähigkeiten kann: \" + faehig;' '  const antwort = await fragen([{ role: \"user\", content: frage }], \"Er kann Werkzeuge auflisten und sagt nicht, dass sich seine Liste ändern wird.\", 60);' '  console.log(\"Modell: \" + antwort.text);' '});' >> client2.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Client gegen den Server ausführen

Befehl
docker exec -w /home/node/project agent node client2.js

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Was das Skript sendet

Sieben Nachrichten gehen in fester Reihenfolge hinaus. Erst eine Liste zu früh und eine schlechte Version. Dann eine gute Version und eine zweite Liste zu früh.

Dann die Bereit-Benachrichtigung, eine Liste, die funktioniert, und eine Methode, die der Server nie gemeldet hat.

Ein kurzer Modellaufruf am Ende formuliert, was die Fähigkeiten bedeuten. Ohne Modell druckt er eine Aufgezeichnete Probe.

Die sechs Antworten

AnfrageAntwort
1 tools/listFehler -32600, Nicht initialisiert
2 initialize, 1999-01-01Fehler -32602, mit den zwei unterstützten Versionen
3 initialize, 2024-11-05Ein Ergebnis mit gemeldeten tools und dem Servernamen
4 tools/listFehler -32600, noch nicht bereit
5 tools/listEin Ergebnis mit leerer Liste
6 resources/listFehler -32601, nie gemeldet

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Über dieses Lab und seinen Quellcode: Lab für KI-Coding-Agenten: mit opencode Code erklären und reparieren lassen und die Arbeit prüfen

Sie unterrichten eine Gruppe? Weisen Sie dieses Modul Ihren Studierenden zu, mit Handbuch für Lehrende, automatisch geprüften Aufgaben und einem Lab für jede Person.