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-Werkzeuge nach Scope begrenzen

Nach dieser Lektion: Ich kann die Werkzeuge eines Servers danach begrenzen, wer fragt.

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

Wie ein MCP-Server begrenzt, wer was aufruft

Ein Werkzeug, das eine Bestellung aufgibt, und ein Werkzeug, das jede Bestellung storniert, sollten nicht demselben Aufrufer offenstehen. Ein Server begrenzt das mit Scopes: einer kurzen Bezeichnung für jede Sache, die ein Aufrufer tun darf.

Ein Server über Standardein- und -ausgabe hat keine Anmeldeseite. Wer ihn startet, sagt, welche Scopes der Aufrufer hält, und der Server prüft sie bei jedem Aufruf.

Am Ende dieser Lektion

Notiz

Ich kann die Werkzeuge eines Servers danach begrenzen, wer fragt.

Schlüsselwörter

BegriffWas er bedeutetBeispiel
Scopeeine Bezeichnung für eine Sache, die ein Aufrufer tun darfbestellungen:schreiben
Berechtigungein Scope, den der Aufrufer hält
Ablehneneinen Aufruf verweigern, weil ein Scope fehlt
Platzhaltereine Berechtigung, die jeden Scope mit demselben Anfang abdecktbestellungen:*
Prüfprotokolleine Aufzeichnung jedes Aufrufs und was entschieden wurde

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

Jedes Werkzeug nennt den Scope, den es braucht

Der Server führt eine Tabelle: jedes Werkzeug und der eine Scope, den es braucht. Der Aufrufer hält eine Liste von Berechtigungen. Ein Aufruf ist erlaubt, wenn eine Berechtigung den Scope abdeckt.

Ein Platzhalter wie bestellungen: deckt jeden Scope ab, der mit bestellungen: beginnt, und sonst nichts. Die Berechtigung deckt alles ab.

Beispiel: ein Aufrufer hält zwei Berechtigungen

WerkzeugBrauchtAufrufer hält speisekarte:lesen, bestellungen:schreibenEntscheidung
speisekarte_lesenspeisekarte:lesenAbgedecktErlauben
bestellung_aufgebenbestellungen:schreibenAbgedecktErlauben
alle_stornierenbestellungen:verwaltenNicht abgedecktAblehnen
kasse_leerenKein solches WerkzeugEntfälltUnbekannt

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

Ein Werkzeug zu verstecken heißt nicht, es abzulehnen

Der Server darf Werkzeuge aus tools/list weglassen, die der Aufrufer nicht nutzen kann. Das erspart dem Modell das Probieren. Aber ein Aufrufer kann trotzdem einen Aufruf für ein Werkzeug senden, das ihm nie gezeigt wurde.

Darum findet die Prüfung bei jedem tools/call statt, immer. Ein fehlender Scope ergibt einen Werkzeugfehler, der den Scope nennt. Ein unbekanntes Werkzeug bleibt ein Protokollfehler.

Ein häufiger Fehler

Warnung

Viele verstecken das gefährliche Werkzeug in der Liste und nennen das Sicherheit. Ein verstecktes Werkzeug ist immer noch da. Wer seinen Namen kennt, kann es aufrufen. Prüfen Sie den Scope bei jedem Aufruf und protokollieren Sie die abgelehnten Aufrufe ebenso wie die ausgeführten.

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 BRAUCHT = { speisekarte_lesen: \"speisekarte:lesen\", bestellung_aufgeben: \"bestellungen:schreiben\", alle_stornieren: \"bestellungen:verwalten\" };' 'const HABEN = (process.env.RECHTE || \"\").split(\",\");' 'let zaehler = 0;' 'function senden(m) { process.stdout.write(JSON.stringify(Object.assign({ jsonrpc: \"2.0\" }, m)) + \"\n\"); }' 'function worte(text, schlecht) { return { content: [{ type: \"text\", text: text }], isError: schlecht }; }' 'function vermerken(werkzeug, entscheidung) {' '  zaehler += 1;' '  process.stderr.write(JSON.stringify({ nr: zaehler, werkzeug: werkzeug, entscheidung: entscheidung, braucht: BRAUCHT[werkzeug] || null }) + \"\n\");' '}' 'function aufrufen(nachricht, p) {' '  if (Object.keys(BRAUCHT).indexOf(p.name) < 0) {' '    vermerken(p.name, \"unbekannt\");' > server5.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' '    return senden({ id: nachricht.id, error: { code: -32602, message: \"Unbekanntes Werkzeug: \" + p.name } });' '  }' '  if (HABEN.indexOf(BRAUCHT[p.name]) < 0) {' '    vermerken(p.name, \"ablehnen\");' '    return senden({ id: nachricht.id, result: worte(\"Nicht erlaubt: \" + p.name + \" braucht \" + BRAUCHT[p.name], true) });' '  }' '  vermerken(p.name, \"erlauben\");' '  senden({ id: nachricht.id, result: worte(\"erledigt: \" + p.name, false) });' '}' 'function sichtbar() {' '  return Object.keys(BRAUCHT).filter(function (n) { return HABEN.indexOf(BRAUCHT[n]) >= 0; }).map(function (n) {' '    return { name: n, description: \"Mensa-Werkzeug \" + n, inputSchema: { type: \"object\" } };' '  });' '}' 'function verarbeiten(nachricht) {' '  if (nachricht.id === undefined) return;' '  const p = nachricht.params || {};' >> server5.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' '  if (nachricht.method === \"initialize\") return senden({ id: nachricht.id, result: { protocolVersion: p.protocolVersion, capabilities: { tools: {} }, serverInfo: { name: \"mensa\", version: \"0.5\" } } });' '  if (nachricht.method === \"tools/list\") return senden({ id: nachricht.id, result: { tools: sichtbar() } });' '  if (nachricht.method === \"tools/call\") return aufrufen(nachricht, p);' '  senden({ id: nachricht.id, error: { code: -32601, message: \"Method not found: \" + nachricht.method } });' '}' 'require(\"readline\").createInterface({ input: process.stdin }).on(\"line\", function (zeile) { verarbeiten(JSON.parse(zeile)); });' >> server5.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 umgebung = Object.assign({}, process.env, { RECHTE: \"speisekarte:lesen,bestellungen:schreiben\" });' 'const server = require(\"child_process\").spawn(\"node\", [\"server5.js\"], { env: umgebung });' 'const aufruf = function (id, name) { return { id: id, method: \"tools/call\", params: { name: name, arguments: {} } }; };' 'const skript = [' '  { id: 1, method: \"initialize\", params: { protocolVersion: \"2025-03-26\" } },' '  { id: 2, method: \"tools/list\" },' '  aufruf(3, \"speisekarte_lesen\"), aufruf(4, \"bestellung_aufgeben\"), aufruf(5, \"alle_stornieren\"), aufruf(6, \"kasse_leeren\"),' '];' 'const gesehen = [];' 'const protokoll = [];' 'require(\"readline\").createInterface({ input: server.stderr }).on(\"line\", function (zeile) { protokoll.push(zeile); });' > client5.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' 'require(\"readline\").createInterface({ input: server.stdout }).on(\"line\", function (zeile) {' '  const m = JSON.parse(zeile);' '  const namen = m.result && m.result.tools ? \"tools: \" + m.result.tools.map(function (t) { return t.name; }).join(\", \") : null;' '  console.log(\"<- \" + (namen || (m.result && m.result.content ? m.result.content[0].text : JSON.stringify(m.error || m.result))));' '  gesehen.push(m);' '  if (gesehen.length === 6) server.stdin.end();' '});' 'skript.forEach(function (m) { server.stdin.write(JSON.stringify(Object.assign({ jsonrpc: \"2.0\" }, m)) + \"\n\"); });' 'server.on(\"close\", async function () {' '  protokoll.forEach(function (l) { console.log(\"Protokoll \" + l); });' '  const ablehnung = gesehen[4].result.content[0].text;' '  const frage = \"Erklären Sie diese Ablehnung einem Studierenden in einem kurzen Satz: \" + ablehnung;' >> client5.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 3

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  const antwort = await fragen([{ role: \"user\", content: frage }], \"Ihr Konto hat keine Berechtigung, alle Bestellungen zu stornieren.\", 60);' '  console.log(\"Modell: \" + antwort.text);' '});' >> client5.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 client5.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 tut

Der Client startet den Server mit den Scopes speisekarte:lesen und bestellungen:schreiben in seiner Umgebung. Er listet die Werkzeuge auf und ruft dann drei auf, die es gibt, und eines, das es nicht gibt.

Zuletzt druckt er das Protokoll des Servers. Ein kurzer Modellaufruf erklärt eine Ablehnung. Ohne Modell druckt er eine Aufgezeichnete Probe.

Was jeder Aufruf zurückgibt und protokolliert

AufrufAntwortEntscheidung im Protokoll
tools/listNur speisekarte_lesen und bestellung_aufgebenKein Werkzeugaufruf, also nicht protokolliert
speisekarte_lesenerledigt: speisekarte_lesenerlauben
bestellung_aufgebenerledigt: bestellung_aufgebenerlauben
alle_stornierenNicht erlaubt: alle_stornieren braucht bestellungen:verwaltenablehnen
kasse_leerenProtokollfehler -32602unbekannt

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.