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

MCP von Hand: JSON-RPC über stdio

Nach dieser Lektion: Ich kann die Nachrichten lesen und schreiben, die ein Werkzeugserver und sein Client austauschen.

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

Was ein Werkzeugserver wirklich sendet

Das Model Context Protocol (MCP) ist ein Standardweg, auf dem ein Agent Werkzeuge eines anderen Programms findet und aufruft. Seine Nachrichten sind schlichtes JSON, eine pro Zeile, über Standardeingabe und -ausgabe. Wer die Nachrichten lesen kann, kann jeden Werkzeugserver untersuchen.

Läuft ein Werkzeugserver für sich allein, aber nicht mit Ihrem Agenten, sendet er meist eine Nachricht in falscher Form.

Am Ende dieser Lektion

Notiz

Ich kann die Nachrichten lesen und schreiben, die ein Werkzeugserver und sein Client austauschen.

Schlüsselwörter

BegriffWas er bedeutetBeispiel
JSON-RPCein Nachrichtenformat zum Aufrufen von Methoden, in JSON
Anfrageeine Nachricht mit id, die eine Antwort erwartet
Benachrichtigungeine Nachricht ohne id und ohne Antwort
stdioStandardeingabe und -ausgabe eines Prozesses
Fehlercodeeine Zahl, die die Art des Fehlers nennt-32601

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

JSON-RPC kennt drei Arten von Nachrichten

Eine Anfrage hat eine id, einen Methodennamen und optionale Parameter. Eine Antwort übernimmt diese id und enthält entweder ein Ergebnis oder einen Fehler. Eine Benachrichtigung hat keine id, also antwortet nichts darauf.

Über stdio ist jede Nachricht eine Zeile JSON. Der Server schreibt nur Nachrichten auf seine Ausgabe und schickt Logs auf seinen Fehlerkanal.

Ausgearbeitetes Beispiel: drei Nachrichten

ArtBeispielAntwort
Anfrage{"jsonrpc":"2.0","id":2,"method":"tools/list"}Eine Antwort mit id 2
Antwort{"jsonrpc":"2.0","id":2,"result":{"tools":[]}}Keine
Benachrichtigung{"jsonrpc":"2.0","method":"notifications/initialized"}Keine

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

Das ist die Form, nicht das ganze Protokoll

Wichtig

Der Server unten hat die Form des echten Protokolls, nur kleiner. Ein echter Server nutzt das offizielle SDK, das auch Versionen, Abbruch, weitere Inhaltsarten und viele weitere Methoden behandelt. Hier wird nichts installiert.

Den Werkzeugserver schreiben, Teil 1

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const PREISE = { brezel: 90, semmel: 45 };' 'const WERKZEUGE = [{ name: \"preis_lesen\", description: \"Preis eines Produkts der Bäckerei in Cent\", inputSchema: { type: \"object\", properties: { produkt: { type: \"string\" } }, required: [\"produkt\"] } }];' 'function senden(nachricht) { process.stdout.write(JSON.stringify(Object.assign({ jsonrpc: \"2.0\" }, nachricht)) + \"\n\"); }' 'function antworten(id, result) { senden({ id: id, result: result }); }' 'function scheitern(id, code, text) { senden({ id: id, error: { code: code, message: text } }); }' 'function inhalt(woerter, isError) { return { content: [{ type: \"text\", text: woerter }], isError: isError }; }' > server.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.

Den Werkzeugserver schreiben, Teil 2

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function aufrufen(id, params) {' '  if (params.name === \"preis_lesen\") {' '    const preis = PREISE[(params.arguments || {}).produkt];' '    if (preis === undefined) return antworten(id, inhalt(\"Unbekanntes Produkt\", true));' '    return antworten(id, inhalt(preis + \" Cent\", false));' '  }' '  return scheitern(id, -32602, \"Unbekanntes Werkzeug: \" + params.name);' '}' 'function behandeln(msg) {' '  if (msg.id === undefined) return;' '  if (msg.method === \"initialize\") return antworten(msg.id, { protocolVersion: \"2024-11-05\", capabilities: { tools: {} }, serverInfo: { name: \"baeckerei\", version: \"0.1\" } });' '  if (msg.method === \"tools/list\") return antworten(msg.id, { tools: WERKZEUGE });' '  if (msg.method === \"tools/call\") return aufrufen(msg.id, msg.params || {});' '  return scheitern(msg.id, -32601, \"Methode nicht gefunden: \" + msg.method);' '}' >> server.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.

Den Werkzeugserver schreiben, Teil 3

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'require(\"readline\").createInterface({ input: process.stdin }).on(\"line\", function (zeile) {' '  try { behandeln(JSON.parse(zeile)); } catch (fehler) { scheitern(null, -32700, \"Analysefehler\"); }' '});' >> server.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.

Den Client mit Drehbuch schreiben, Teil 1

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const server = require(\"child_process\").spawn(\"node\", [\"server.js\"]);' 'const aufruf = function (n, name, args) { return { id: n, method: \"tools/call\", params: { name: name, arguments: args } }; };' 'const drehbuch = [' '  { id: 1, method: \"initialize\", params: { protocolVersion: \"2024-11-05\", capabilities: {}, clientInfo: { name: \"demo\", version: \"0.1\" } } },' '  { method: \"notifications/initialized\" },' '  { id: 2, method: \"tools/list\" },' '  aufruf(3, \"preis_lesen\", { produkt: \"semmel\" }),' '  aufruf(4, \"preis_lesen\", { produkt: \"kiwi\" }),' '  aufruf(5, \"alles_loeschen\", {}),' '  { id: 6, method: \"resources/list\" },' '];' > client.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.

Den Client mit Drehbuch schreiben, Teil 2

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'let offen = 6;' 'require(\"readline\").createInterface({ input: server.stdout }).on(\"line\", function (zeile) {' '  console.log(\"<- \" + zeile);' '  offen -= 1;' '  if (offen === 0) server.stdin.end();' '});' 'drehbuch.forEach(function (m) {' '  const ganz = Object.assign({ jsonrpc: \"2.0\" }, m);' '  console.log(\"-> \" + JSON.stringify(ganz));' '  server.stdin.write(JSON.stringify(ganz) + \"\n\");' '});' >> client.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.

Den Client gegen den Server starten

Befehl
docker exec -w /home/node/project agent node client.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.

Eine mögliche Ausgabe

AnfrageAntwort
initializeEin Ergebnis mit Protokollversion und Servernamen
tools/listEin Ergebnis, das preis_lesen auflistet
preis_lesen für eine SemmelEin Ergebnis mit dem Text 45 Cent
preis_lesen für eine KiwiEin Ergebnis mit isError true und Unbekanntes Produkt
alles_loeschenEin Fehler mit Code -32602
resources/listEin Fehler mit Code -32601

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

Eine Sitzung folgt einer Reihenfolge

Der Client sendet zuerst initialize, und der Server antwortet mit dem, was er kann. Dann sendet der Client die Benachrichtigung, dass er bereit ist. Erst danach fragt er tools/list ab und nutzt tools/call.

Der Agent zeigt dem Modell die aufgelisteten Werkzeuge. Verlangt das Modell eines, sendet der Client tools/call.

Zwei Arten von Fehlern

Ein Protokollfehler ist eine JSON-RPC-Fehlerantwort. Die Anfrage selbst war falsch: unbekannte Methode, unbekanntes Werkzeug oder unlesbares JSON. Jeder hat einen Code, etwa -32601 für eine fehlende Methode.

Ein Werkzeugfehler ist ein normales Ergebnis mit isError auf true. Der Aufruf war in Ordnung, aber das Werkzeug konnte es nicht tun. Das Modell liest den Text und kann etwas anderes versuchen.

Ein häufiger Fehler

Warnung

Viele glauben, jeder Fehler müsse ein JSON-RPC-Fehler sein. Eine Fehlerantwort sagt, dass die Anfrage falsch gebaut ist. Ein Werkzeug, das lief und das Produkt nicht fand, soll ein Ergebnis mit isError true liefern. So sieht das Modell den Grund und kann sich fangen.

Ü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.