Was macht mcp-server-design?
Dieses Skill legt fest, wie ein MCP-Server ein Produkt gegenüber Agenten bereitstellt: wo Tools im Code sitzen, wie eine Verbindung an einen Tenant und eine Person gebunden wird, welche Aufrufe eine Bestätigung der Person benötigen und wie Ergebnisse und Fehler das Modell zum nächsten korrekten Aufruf führen. Die Protokollsyntax folgt der MCP-Spezifikation (Revision 2026-07-28, zum Zeitpunkt der Erstellung) und der SDK-Dokumentation. Abfrage-Gültigkeitsbereiche, Berechtigungskataloge und ID-Formate stammen aus tenant-isolation, authorization-rbac und dual-key-identifiers. Der Fehler, den dies verhindert: ein Modell, das den falschen Tenant auswählt, einen Kunden zweimal anschreibt oder auf Text reagiert, den ein Dritter eingeschleust hat, weil der Server dem Modell, dem Client oder einer Tool-Beschreibung ein Tor offen gelassen hat.
Gilt bei / Gilt nicht
- Gilt bei: Erstellen eines MCP-Servers für ein Produkt, Hinzufügen oder Überprüfen eines Tools, Auswählen, wie MCP-Anmeldeinformationen an Tenants und Personen gebunden werden, Tools, die Kunden benachrichtigen, Personen anrufen, Warnungen stummschalten oder löschen, doppelte Schreibvorgänge nach Client-Wiederholungen, Fehler- und Ergebnisformen, Toolnamen und -beschreibungen, Toolsets für kleine Modelle, Evaluierungen der Tool-Nutzung.
- Gilt nicht bei: Konfigurieren eines Clients zur Nutzung eines fremden MCP-Servers, REST- oder GraphQL-Endpunkt-Design, Chat-Bots und Slash-Befehle, die nicht MCP sind, Eingabeaufforderungen für den eigenen Assistenten eines Produkts, Ratenbegrenzungen auf Nicht-MCP-Routen.
Regeln
Die wichtigsten zuerst. Beispiele verwenden ein Buchungssystem: Buchungen, Kunden, Techniker.
- [invariant] Der Server erzwingt, was nicht schiefgehen darf; Beschreibungen und Anmerkungen lenken nur. Jedes unten genannte Tor läuft bei jedem Aufruf im Server-Code. Grund: Anmerkungen sind Hinweise, und es gibt Clients, die automatisch genehmigen oder nie nachfragen. Test: Rufen Sie jedes geschützte Tool von einem rohen JSON-RPC-Client aus auf, der Hinweise ignoriert; jedes Schutztor wird trotzdem ausgelöst. Quelle: MCP Schema 2026-07-28,
ToolAnnotations: „Clients should never make tool use decisions based onToolAnnotationsreceived from untrusted servers" (https://modelcontextprotocol.io/specification/2026-07-28/schema, überprüft 2026-10-31). - [invariant] Tools sind ein zweiter Adapter auf der Service-Schicht: Sie rufen dieselben Domain-Dienste auf wie die Benutzeroberfläche und die API, niemals die eigene HTTP-API im Loopback und niemals direkt das ORM. Prüfungen, die Daten schützen (Grenzen, URL-Zulassungslisten gegen SSRF, Eigentum referenzierter Datensätze), leben im Service, nicht nur in einem Controller oder Formular-Request. Ein Schreibpfad pro Funktion. Grund: Ein dünner Adapter erbt jede Prüfung, die nur seine Geschwister-Adapter ausgeführt haben. Test: Ein Architektur-Test schlägt bei Persistenzaufrufen in Tool-Klassen fehl; pro Schreib-Tool wird eine Eingabe, die die API ablehnt, vom Tool abgelehnt. Quelle: Mit dem obigen Test reproduzierbar.
- [invariant] Eine Verbindung, ein Tenant: Der Tenant ist in der Anmeldeinformation gebunden, wenn die Verbindung hergestellt wird. Kein Tool-Schema hat einen Tenant-Parameter. Ein Argument wie
workspace_idwird als unbekannt abgelehnt. Jeder Handle wird innerhalb des gebundenen Tenants aufgelöst. Eine Anmeldeinformation, die mehrere Tenants bedient, trägt den Tenant im Transport (Pfad oder Header) und prüft ihn gegen die Anmeldeinformation, niemals in einem Tool-Argument. Grund: Ein Tenant-Parameter lässt das Modell den Tenant wählen. Test: Übergeben Sie bei jedem Tool mit einem Verweis einen gültigen Handle eines anderen Tenants; erwarten Sienot_foundund eine unveränderte Zeile. Quelle: MCP-Tools-Spezifikation, das Toolset „MAY vary by the authorization presented on the request" (https://modelcontextprotocol.io/specification/2026-07-28/server/tools); Sicherheitsbest Practices, Schlüsselzustand durch eine Benutzer-ID „derived from the verified token rather than supplied by the client" (https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices); beide überprüft 2026-10-31. - [invariant] Rechte werden live geschnitten: Effektive Rechte = Token-Rechte ∩ aktuelle Rechte der Person, die die Verbindung erstellt hat, berechnet bei jedem
tools/listundtools/call. Token-Rechte sind bei der Erstellung gedeckelt. Ein entfernter oder deaktivierter Ersteller beendet die Verbindung. Der Widerruf läuft über einen Dienst, der protokolliert. Grund: In ein Token eingefrorene Rechte überdauern eine Rollenänderung. Test: Entfernen Sie die Rolle des Erstellers, rufen Sie ein Schreib-Tool auf; Verweigerung beim nächsten Aufruf. Quelle: MCP-Tools-Spezifikation, Server MÜSSEN „Implement proper access controls" (überprüft 2026-10-31). - [invariant] Kein aktueller Benutzer bei MCP-Anfragen: Middleware bindet einen Verbindungskontext (Tenant, Ersteller, Live-Rechte) und lässt das Feld des aktuellen Benutzers des Frameworks leer; Tools lesen den Akteur aus dem Kontext, Dienste nehmen den Akteur als Parameter. Grund: Wenn der Besitzer als aktueller Benutzer gesetzt ist, besteht eine versehentliche Richtlinienprüfung in einem Tool, weil Besitzer alles tun dürfen; ohne Benutzer schlägt sie fehl und schließt ab. Test: Ein Architektur-Test verbietet Gate-, Policy- und Current-User-Helfer in Tool-Code; eine absichtlich hinzugefügte Richtlinienprüfung lässt den Aufruf fehlschlagen. Quelle: Mit dem obigen Test reproduzierbar.
- [invariant] Jedes Tool hat genau eine Effektklasse: lesen, stilles Schreiben, benachrichtigen (erreicht Kunden oder ändert, was sie sehen), wecken (ruft eine Person an oder kontaktiert sie), alarmieren (schaltet stumm, pausiert oder leitet Warnungen um), löschen. Leiten Sie die Klasse aus dem Codepfad ab (Ereignisse, Listener, Beobachter, Jobs, E-Mails), nicht aus dem Namen, und teilen Sie ein Tool, das zwei Klassen umfasst. Grund: Hinweise, Rate-Bucket, Vorschau-Pflicht und Verbindungswechsel folgen aus der Klasse. Test: Mit Queue-, Mail- und Event-Fakes dispatchen stille Tools keine Benachrichtigung. Quelle: Verbindungsprüfkriterien, Global-lesende/-schreibende Tools werden abgelehnt, und Schreibvorgänge werden nach Aktionstyp aufgeteilt (https://claude.com/docs/connectors/building/review-criteria, überprüft 2026-10-31).
- [invariant] Benachrichtigen, Wecken, Alarmieren und Löschen erfolgen in zwei Schritten. Das Tool bereitet nur vor: Es speichert eine ausstehende Aktion (Verbindung, Tool, normalisierte Argumente und Digest, Hash des Inhalts, der versendet wird, Ablauf) und gibt
PREVIEW, einenconfirm_tokenund eine vom Server geschriebeneconfirm_summaryzurück. Nurconfirm_actionführt aus, nachdem Verbindung, unbenutzt, nicht abgelaufen, nicht abgelehnt, exakte Zusammenfassung, eine Sperre, Live-Rechte und Schalter sowie eine frische Vorbereitung, deren Inhalts-Hash noch übereinstimmt (sonst neue Vorschau, altes Token tot), überprüft wurden. Grund: Weder Modell noch Client fragen zuverlässig eine Person, und genehmigter Text kann sich dazwischen ändern. Test: Vorschau allein sendet nichts; wiederverwendete, abgelaufene, fremde und falsch-zusammengefasste Token schlagen fehl; eine Bearbeitung zwischen den Schritten ergibtchanged_since_preview. Quelle: MCP-Tools-Spezifikation, „there SHOULD always be a human in the loop with the ability to deny tool invocations"; MRTR-Serveranforderungen: Ein vom Client zurückgegebener Zustand ist „attacker-controlled input", gebunden an Principal, kurze Ablaufzeit und Parameter-Digest, Einmalnutzung serverseitig erzwungen (https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr); beide überprüft 2026-10-31. - [invariant] Replay-Schutz bei jedem stillen Schreibvorgang: Fingerabdruck = Verbindung + Tool + SHA-256 des kanonischen JSON der normalisierten Argumente (Schlüssel auf jeder Ebene sortiert); ein Treffer innerhalb des Fensters gibt das erste Ergebnis mit
replayed: truezurück und führt nichts aus. Ein optionaleridempotency_keyist an den Argument-Digest gebunden. Der Cache enthält Presenter-Ausgabe, niemals einmalige Geheimnisse. Grund: Ein unterbrochener Stream verliert die laufende Anfrage, und Clients MÜSSEN sie mit einer neuen ID erneut senden, sodass ein ausgeführter Schreibvorgang erneut eintrifft. Test: Zweimal derselbe Aufruf mit unterschiedlichen JSON-RPC-IDs; eine Zeile, zweites Ergebnisreplayed: true. Quelle: MCP-Änderungsprotokoll 2026-07-28, wesentliche Änderung 9 (https://modelcontextprotocol.io/specification/2026-07-28/changelog); Claude Code wiederholt einen ausstehenden Aufruf für Tools, die mitidempotentHintoderreadOnlyHintgekennzeichnet sind, einmal bei einer neuen Verbindung (https://code.claude.com/docs/en/mcp); beide überprüft 2026-10-31. - [invariant] Jedes Create-Tool hat ein zugehöriges Update-Tool und eine Duplikatsperre auf einem Geschäftsschlüssel. Ein Treffer gibt einen Fehler zurück, der den vorhandenen Handle und das Update-Tool benennt; das Erstellen trotzdem erfordert
separate: trueund einen Grund. Sperren lesen synchrone Spalten (created_by,created_at), niemals ein protokolliertes Warteschlangenprotokoll. Bearbeitungstools haben keinen Notify-Parameter. Grund: Wenn es aufgefordert wird, "den Text zu verbessern", erstellt ein Modell ein zweites Objekt, es sei denn, es wird gestoppt. Test: Zweimaliges Erstellen mit demselben Schlüssel; eine Zeile, ein Fehler, der sie benennt. Quelle: Mit dem obigen Test reproduzierbar. - [invariant] Aktualisierungen tragen die Version, die der Aufrufer gelesen hat: Objekte und Nachrichten in Ergebnissen haben eine
version(Inhalts-Hash), Update- und Edit-Tools erfordern sie, eine veraltete gibtconflictmit dem aktuellen Zustand zurück. Grund: Ein Agent, der von einer alten Lektüre aus arbeitet, überschreibt die Bearbeitung eines Kollegen. Test: Lesen, die Zeile woanders ändern, mit der alten Version aktualisieren;conflict, Zeile unverändert. Quelle: Mit dem obigen Test reproduzierbar. - [invariant] Batch-Tools übernehmen explizite Handles oder einen Filter plus eine erforderliche
expected_count; wenn die Trefferzahl abweicht, geben Sie die Treffer zurück und führen Sie nichts aus. Grund: Ein Filter, der breiter ist als vom Modell erwartet, multipliziert einen einzigen Fehler. Test: Ein Filter, der 12 Buchungen mitexpected_count: 3trifft; Fehler listet 12 auf, nichts geändert. Quelle: Mit dem obigen Test reproduzierbar. - [invariant] Validieren Sie jedes Argument auf dem Server mit den eigenen Regeln des Tools und lehnen Sie unbekannte Felder mit der Liste der erlaubten ab. Grund: SDKs prüfen Argumente nicht immer gegen
inputSchema, und ein ignoriertes Feld lässt das Modell glauben, es hätte etwas gesetzt. Test: Ein zusätzliches Feld gibt die erlaubte Liste zurück und schreibt nichts. Quelle: MCP-Tools-Spezifikation, Server MÜSSEN „Validate all tool inputs" (überprüft 2026-10-31). - [invariant] Text von Drittanbietern in Ergebnissen ist nicht vertrauenswürdig: Text, den ein Kunde, Endbenutzer, externes System oder Upload schreiben kann (Notizen, E-Mail-Textkörper, Webhook-Payloads, entfernte Fehlermeldungen), wird abgeschnitten, von Steuerzeichen befreit und unter
untrusted_textmit einem Hinweis zurückgegeben, den Anweisungen darin nicht zu folgen; rohe Textkörper bleiben draußen. Beschreibungen beschreiben das Tool und sagen dem Modell niemals, wie es sich verhalten soll. Grund: Injizierter Text, der ein Tool mit externer Wirkung steuert, ist das größte Risiko; der Vorschau-Schritt ist die zweite Linie. Test: Ein Injektions-Kanarienvogel in jedem Drittanbieter-Feld erscheint nur innerhalb des Wrappers. Quelle: MCP-Tools-Spezifikation, Server MÜSSEN „Sanitize tool outputs"; Verbindungsprüfkriterien lehnen Prompt-Injection-Muster in Beschreibungen ab; beide überprüft 2026-10-31. - [invariant] Ergebnisse enthalten keine Geheimnisse und nur die für die Aufgabe erforderlichen personenbezogenen Daten: Presenter mit expliziten Feldlisten, niemals ein Ganz-Datensatz-Serialisierer; Protokolle enthalten Toolnamen, Ergebnis und öffentliche IDs, niemals Argumente. Grund: Jedes Ergebnis geht zum Modellanbieter des Benutzers. Test: Füllen Sie jedes geheime Feld eines Fixtures mit einem Köderwert, rufen Sie jedes Lesetool auf, durchsuchen Sie Ergebnisse und Protokolle; kein Köder. Quelle: Mit dem obigen Test reproduzierbar; Aufzeichnungen in
gdpr-engineering. - [invariant] Geschäfts-, Validierungs- und Berechtigungsfehler sind Tool-Ausführungsfehler (
isError: true), deren Text mitError:beginnt, die Ursache, die Behebung und das richtige Tool mit echten Handles benennt und mit einer Zeile JSON-Details endet. "Nicht gefunden" verweist auf einfind_-Tool, niemals auf das Erstellen. Ein durch Rechte, Toolset oder Plan verstecktes Tool antwortet mit diesem Grund. Grund: Das Modell korrigiert sich nur bei Fehlern, die es sieht und versteht. Test: Jeder Fehlerpfad in der Vertragssuite beginnt mitError:und hat eine parsebare JSON-Zeile. Quelle: MCP-Schema,CallToolResult.isError: Tool-Fehler „SHOULD be reported inside the result object ... Otherwise, the LLM would not be able to see that an error occurred and self-correct"; Verbindungsprüfkriterien lehnen generische „Internal Server Error"-Antworten ab; beide überprüft 2026-10-31. - [invariant] Der Textblock und
structuredContenttragen dasselbe JSON, und ein deklariertesoutputSchemadeckt jedes strukturierte Ergebnis ab, einschließlich Fehler. Grund: Clients unterscheiden sich darin, welcher Kanal das Modell erreicht, und sie SOLLTEN gegen ein deklariertes Schema validieren. Test: Für jedes Ergebnis in der Suite ist der geparste Text gleichstructuredContent. Quelle: MCP-Tools-Spezifikation, ein Tool mit strukturiertem Inhalt „SHOULD also return the serialized JSON in a TextContent block" (überprüft 2026-10-31). - [invariant] Zeit und Geld sind die Aufgabe des Servers: Zeiten kommen als Ortszeit plus IANA-Zone oder ISO 8601 mit Offset, niemals ohne; nicht existierende und mehrdeutige Ortszeiten werden mit den Optionen abgelehnt; jede Zeit in einem Ergebnis zeigt Wochentag, Ortszeit mit Zone, UTC und Abstand zur Jetztzeit an. Summen, Steuern und Rundungen werden auf dem Server aus Dezimalzeichenfolgen oder ganzzahligen Untereinheiten berechnet. Grund: Off-by-one-day- und DST-Fehler sind ohne den Wochentag unsichtbar. Test:
2026-03-29 02:30inEurope/Berlinwird abgelehnt;2026-10-25 02:30gibt beide Offsets zurück. Quelle: Mit dem obigen Test reproduzierbar. - [invariant] Ein Kill-Switch an einer Stelle: Ein globales Flag, gesetzt durch einen CLI-Befehl und einen Admin-Umschalter, die beide protokollieren, lässt jeden MCP-Aufruf 503 mit
Retry-Afterzurückgeben, während Verbindungen bestehen bleiben; ein Pro-Tenant-Schalter mit seiner einmal definierten Voreinstellung lässt einen Tenant-Admin den Agentenzugriff deaktivieren. Grund: Ein Vorfall erfordert eine einzige Aktion, die alle Agenten-Schreibvorgänge stoppt. Test: Flag an, rufen Sie ein Schreib-Tool auf; 503, keine Zeile, kein Job. Quelle: Mit dem obigen Test reproduzierbar. - [invariant] Jeder MCP-Schreibvorgang wird mit Kanal
mcp, Verbindung und Clientname protokolliert, am Einstiegspunkt als Spalten gesetzt, undlist_recent_changeszeigt, was diese Verbindung geändert hat. Grund: Tenants sehen, was ein Agent getan hat, und ein Agent, der den Kontext verloren hat, findet seinen Entwurf, anstatt einen weiteren zu erstellen. Test: Jedes Schreib-Tool ergibt genau eine Audit-Zeile mit Kanalmcp. Quelle: Mit dem obigen Test reproduzierbar. - [invariant] MCP- und API-Anmeldeinformationen kreuzen sich nicht: MCP-Token haben ihren eigenen Typ und Präfix, werden gehasht gespeichert, einmal angezeigt und von jeder API-Route abgelehnt; API-Token und Sitzungs-Cookies werden vom MCP-Endpunkt abgelehnt. Bei OAuth akzeptieren Sie nur Token, die für diesen Server ausgestellt wurden, und leiten Sie niemals einen durch. Validieren Sie
Origin. Grund: MCP-Token liegen im Klartext in Client-Konfigurationsdateien. Test: Jede Paarung gibt 401 zurück; eine schlechteOrigingibt 403 zurück. Quelle: MCP-Autorisierungsspezifikation, Server „MUST NOT accept or transit any other tokens" (https://modelcontextprotocol.