MCP Engineering

Server Contracts: Fähigkeiten stabil veröffentlichen

Ein neues Pflichtfeld validiert sauber, eine nutzerspezifische Toolliste wird öffentlich gecacht und eine Änderungsnotification gilt als Migrationsplan. Formal spricht alles MCP — fachlich brechen dennoch mehrere Hosts gleichzeitig.

Lehrtext · 10 Abschnitte · zuletzt geprüft: 2026-09-04

Vom Backend zur veröffentlichten Fähigkeit

Dieses Modul setzt voraus, dass du die MCP-Rollen und Primitives kennst. Jetzt geht es um den Vertrag innerhalb eines Servers: Was darf ein Host entdecken, wie versteht er die Bedeutung einer Eingabe, und was bleibt trotz eines stabilen Namens veränderbar? Ein MCP-Vertrag ist eine absichtlich kleine, veröffentlichte Sicht auf eine Fähigkeit — nicht ein Spiegelbild der internen Datenbank, Queue oder REST-API.

SERVER-INTERN · austauschbarBackendDB · Queue · interne IDsVERÖFFENTLICHTER VERTRAGTools + SchemasResources + URIsPrompts + WorkflowsHost-Policyanzeigen · freigeben
Die veröffentlichte Capability bleibt eine schmale, stabile Grenze zwischen internem Backend und Host-Policy.
Interne Implementierung
Kann Tabellen, Jobnamen, Auth-Provider und Fehlerdetails ändern
Veröffentlichter MCP-Vertrag
Beschreibt stabile Operationen, Argumente, Ressourcen und Capability-Signale
Host-Policy
Entscheidet separat, was aus dem Angebot sichtbar oder ausführbar wird
MerksatzEin guter Vertrag schützt beide Seiten vor unnötiger Kopplung: Der Server darf sich intern ändern, der Host bekommt eine verlässliche Bedeutung.

Der Vertrag hat zwei Schichten. Die Drahtform legt Namen, JSON-Schema, URI, Argumente und Ergebnisfelder fest. Die fachliche Semantik sagt, welche Entität gemeint ist, welche Wirkung ein Aufruf hat und welche Fehler der Konsument erwarten darf. Ein Schema kann unverändert bleiben und trotzdem brechen, wenn status: complete plötzlich einen anderen Geschäftsprozess bezeichnet. Umgekehrt kann eine additive Schemaerweiterung kompatibel sein, wenn alte Eingaben dieselbe Bedeutung behalten. Beide Schichten gehören ins Release-Review.

Der Vertrag beginnt mit Discovery

Tools, Resources und Prompts werden über ihre jeweiligen Listen sichtbar. Der Host kann dabei paginieren und Ergebnisse cachen. Diese Liste ist deshalb nicht bloß UI-Metadaten: Name, Beschreibung, Eingabeform und weitere veröffentlichte Felder bilden die Capability, auf die ein Host seine Auswahl, Anzeigen und Integrationslogik stützt.

Request-Version und Client-Capabilities setzenOptional server/discover lesenVollständige paginierte Liste entdeckenCachehinweise und Host-Policy anwendenFähigkeit anbieten oder aufrufen
Cache ist kein FreifahrtscheinEin Cache darf Latenz sparen. Er darf jedoch keine dauerhafte Annahme erzeugen, dass ein Server nach einem Update weiterhin dieselbe Capability anbietet.

Im modernen Core ist server/discover für Server verpflichtend und für Clients optional. Es liefert unterstützte Revisionen und grobe Capabilities; die konkreten Tools, Resources und Prompts kommen weiterhin aus ihren Listenmethoden. Listen sind paginiert und sollen deterministisch sortiert sein. Ihre Resultate tragen ttlMs und cacheScope. Ein TTL ist ein Frischehinweis, keine Garantie, dass der Bestand bis dahin unverändert bleibt. Bei cacheScope: public darf eine Antwort zwischen Autorisierungskontexten geteilt werden; diese Angabe wäre für nutzerspezifische Toollisten gefährlich.

Eine nutzerspezifische Toolliste cachen

Szenario

Administratorin A sieht acht Tools, Operator B nur drei. Beide verwenden denselben Host.

Anforderungen

  • Der Server filtert tools/list anhand der Autorisierung jedes Requests
  • Die Resultate tragen cacheScope: private
  • Der Cachekey trennt Autorisierungskontexte
  • Eine Listenänderung macht betroffene Einträge stale

Schritte

  1. Alle Seiten deterministisch lesen
  2. Empfangszeit und ttlMs speichern
  3. Toolliste nur im passenden Kontext wiederverwenden
  4. Bei Fehler oder Notification gezielt neu lesen

Merksatz: Caching optimiert einen Vertrag; es darf dessen Sichtbarkeitsgrenze nicht erweitern.

Ein veröffentlichtes Schema ist ein Kompatibilitätsversprechen

Ein Tool veröffentlicht mit inputSchema eine JSON-Schema-Beschreibung seiner Argumente. Hosts und Modelle können diese Beschreibung für Auswahl und Konstruktion verwenden. Dadurch wird die Form der Eingabe Teil des öffentlichen Vertrags: Ein neues Pflichtfeld, ein engerer Wertebereich oder dieselbe Feldbezeichnung mit neuer Bedeutung kann vorhandene Aufrufer brechen — auch wenn der Tool-Name gleich bleibt.

Kompatibel erweitern
Optionales, klar dokumentiertes Feld hinzufügen und die bisherige Bedeutung erhalten
Breaking Change
Pflichtfeld hinzufügen, Typ oder erlaubte Werte einschränken oder Feldsemantik ändern
Migration
Alten Vertrag erhalten oder eine getrennte, eindeutig benannte Capability für die neue Bedeutung veröffentlichen
Wichtige GrenzeJSON Schema beschreibt eine Form, keine Release-Policy. MCP schreibt keine allgemeine Versionierungs- oder Deprecation-Strategie vor; der Server muss seine Kompatibilitätszusage bewusst gestalten.

Ohne explizites $schema gilt JSON Schema 2020-12; Implementierungen müssen mindestens diesen Dialekt unterstützen. inputSchema eines Tools bleibt ein Objekt, outputSchema darf im modernen Protokoll jedes JSON-Schema beschreiben und structuredContent entsprechend auch Array, String, Zahl, Boolean oder Null sein. Externe $ref-Ziele dürfen nicht automatisch aus dem Netz geladen werden. Ein opt-in Resolver braucht Allowlist, Netzgrenzen, Timeout und Größenlimit. Auch lokale Komposition mit oneOf oder allOf braucht Tiefen- und Zeitbudgets, sonst wird Vertragsvalidierung selbst zur Ressourcenangriffsfläche.

Kompatibilität muss in beide Richtungen konkret benannt werden. Ein älterer Client sendet unbekannte neue optionale Felder nicht; der Server braucht dafür ein Verhalten mit derselben bisherigen Bedeutung. Ein neuer Client kann zusätzliche Felder senden; ein älterer Server kennt sie möglicherweise nicht. additionalProperties: false macht solche Erweiterungen bewusst streng und kann eine parallele Capability nötig machen. Ein permissiveres Schema erleichtert Erweiterung, akzeptiert aber Tippfehler leichter. Es gibt keinen universellen Gewinner: Der Vertrag muss festlegen, ob unbekannte Felder abgelehnt, ignoriert oder über eine eigene Erweiterungsfläche getragen werden.

Resources brauchen adressierbare Bedeutung

Eine Resource wird durch eine URI referenziert. Eine Resource Template beschreibt eine wiederverwendbare URI-Form mit Argumenten. Die URI ist damit ein Vertragsschlüssel: Sie sollte die fachliche Identität transportieren, nicht eine flüchtige interne Dateistruktur, einen zufälligen Cache-Pfad oder ein implizites URL-Routing des aktuellen Frameworks.

Stabil
inventory://tenant/acme/services/payments steht für eine fachliche Resource
Fragil
file:///tmp/export-8472.json leakt eine temporäre Umsetzung
Template
Eine dokumentierte URI-Form macht variable Teile sichtbar und vervollständigbar
Nicht jede URI ist ein NetzwerklinkMCP lässt unterschiedliche URI-Schemata zu. Entscheidend ist, dass Server und Host dieselbe Identität und Lesesemantik verstehen.

Ein Resource-Vertrag umfasst mehr als die URI: name, optionaler Titel, Beschreibung, mimeType, Größe und Annotations helfen dem Host bei Auswahl und Darstellung. resources/read kann mehrere Inhalte zurückgeben, deren jeweilige URI zur angeforderten Resource passt. Ein Template macht Variablen mit RFC-6570-Syntax sichtbar, ersetzt aber keine Autorisierung. Eine syntaktisch passende URI darf nicht genügen, um einen fremden Tenant oder privaten Pfad zu lesen. Stabilität und Zugriffskontrolle sind getrennte Zusagen.

Prompts sind ausgewählte Workflow-Verträge

Ein Prompt bietet einen vom Nutzer wählbaren Einstieg in einen Workflow. Er kann Argumente definieren; für Prompt- und Resource-Template-Argumente kann ein Server optional Vervollständigungen anbieten. Das ist ein interaktiver Vertrag: Argumentnamen und ihre Bedeutung müssen stabil genug sein, dass ein Host eine verständliche Auswahloberfläche und sichere Vorbelegung erzeugen kann.

Prompt
Nutzer wählt einen benannten Workflow und füllt dessen Argumente
Completion
Server schlägt kontextuelle Werte vor, wenn die Capability ausgehandelt wurde
Tool
Modell kann eine Operation vorschlagen; das ist keine Prompt-Alternative nur wegen ähnlicher Parameter
ProduktentscheidungWähle einen Prompt, wenn eine sichtbare Nutzerentscheidung und ein verständlicher Ablauf Teil des Vertrags sind — nicht nur, weil Text erzeugt wird.

Prompt-Argumente sind benannte Stringwerte, kein beliebig tiefes Tool-Schema. Das begrenzt die Komplexität einer nutzergesteuerten Vorlage und ist ein Signal gegen versteckte Maschinen-APIs im Prompt. Der Server liefert bei prompts/get Nachrichten mit Rollen und Inhalt; der Host entscheidet, wie er sie zeigt und in eine Modellinteraktion übernimmt. Namen, Argumente und gelieferte Rollen sind deshalb ein Nutzervertrag. Wer einen Argumentnamen umdeutet oder eine assistierende Nachricht plötzlich als Nutzeranweisung liefert, ändert Semantik auch ohne Schemafehler.

Capabilities sind veröffentlichte Zusagen des Servers

Im modernen MCP bringt jeder Client-Request seine Client-Capabilities mit. Server-Capabilities sind über server/discover auffindbar. Für einen Server ist das mehr als Dekoration: Wer tools.listChanged oder resources.subscribe deklariert, signalisiert optionale Interaktionen, die der Client gezielt verwenden kann. Eine implementierte, aber nicht deklarierte Funktion ist kein verlässlicher Teil des veröffentlichten Vertrags; eine deklarierte Funktion muss der Server tatsächlich bedienen.

Optionale Funktion implementierenPassende Server-Capability in server/discover veröffentlichenClient öffnet nur unterstützte InteraktionServer hält Verhalten und Deklaration konsistent
Producer-PflichtDie Protokollversion allein veröffentlicht keine optionalen Features. Der Server muss seine tatsächliche Unterstützung präzise deklarieren, damit Hosts keine versteckten Annahmen treffen müssen.

Capabilities sind keine Berechtigungen. tools: {} sagt, dass der Server die Toolmethoden spricht; es sagt nicht, dass jeder authentifizierte Aufrufer jedes Tool sehen oder ausführen darf. Die konkrete Liste darf mit der Autorisierung des Requests variieren, solange sie nicht von einer Verbindung oder früheren Aufrufen abhängt. Ebenso darf ein Server keine Client-Fähigkeit voraussetzen, die im aktuellen Request fehlt. Dann muss er den definierten Fehler MissingRequiredClientCapabilityError liefern, statt still auf Connection-State zurückzugreifen.

Ein Konsument prüft Capabilities an der Stelle, an der er die optionale Interaktion plant. Für Listenänderungen reichen tools und ein grundsätzlich erreichbarer Server nicht: listChanged: true muss veröffentlicht sein, und der Client öffnet einen subscriptions/listen-Stream mit dem passenden Filter. Der Server bestätigt zuerst, welche Teilmenge er tatsächlich bedient. Diese Bestätigung verhindert, dass der Client aus seiner Anfrage eine Zusage ableitet. Preis: Jede optionale Kombination erweitert die Testmatrix aus Server-Capability, Client-Capability, Autorisierung, Subscription und Fallback.

Annotations helfen bei Darstellung, nicht bei Freigabe

Tools, Resources und Prompts können Beschreibungen und Annotations tragen. Bei Tools enthalten Annotations unter anderem Hinweise wie readOnlyHint, destructiveHint, idempotentHint oder openWorldHint. Laut Spezifikation sind diese Hinweise untrusted und unverbindlich. Sie unterstützen Ranking, Darstellung und Risikohinweise, dürfen aber keine Autorisierungs-, Approval- oder Sandbox-Policy ersetzen.

Annotation
Hinweis für Host oder UI, etwa zur erwarteten Wirkung
Serverdurchsetzung
Tatsächliche Validierung und Berechtigung vor Ausführung
Host-Policy
Unabhängige Freigabe, Allowlist, Nutzerbestätigung und Kontextgrenze
VertrauensregelEin Server darf seine eigene Gefährlichkeit nicht verbindlich klassifizieren. Hinweise können nützlich sein, aber die Kontrolle muss außerhalb des Hinweises liegen.

Dasselbe gilt für clientInfo und serverInfo: Beide sind selbst gemeldete Implementierungsdaten für Anzeige, Logging und Diagnose. Die Spezifikation untersagt, daraus sicherheitsrelevantes Verhalten abzuleiten. Ein Servername ist außerdem nicht global eindeutig und eignet sich nicht zur Auflösung kollidierender Toolnamen. Der Host braucht eine eigene stabile Serveridentität aus Konfiguration, Installation oder autorisierter Herkunft. Beschreibende Metadaten können diese Identität ergänzen, aber nicht erzeugen.

Auch Toolnamen sind nur innerhalb eines Servers eindeutig. Aggregiert ein Host zwei Server mit jeweils search, braucht er eine eigene Disambiguierungsstrategie, etwa einen stabilen konfigurierten Namespace. Den selbst gemeldeten serverInfo.name als Sicherheitsnamespace zu verwenden wäre falsch: Zwei Server dürfen denselben Namen melden. Die Anzeige darf freundlich bleiben, während interne IDs Herkunft und Installation eindeutig halten. Nachteil: Präfixe und interne Identitäten erschweren Migrationen; ohne sie kann ein Modell oder Nutzer jedoch nicht zuverlässig erkennen, welche Vertrauensdomäne eine gleichnamige Fähigkeit ausführt.

Releases brauchen einen Semantik- und Migrationsplan

MCP standardisiert Tool-Beschreibung und Discovery, aber keine allgemeine SemVer-, Deprecation- oder Migrationspolitik für deine fachliche API. Ein Release, das ein Pflichtargument ergänzt, einen Rückgabewert anders interpretiert oder eine Wirkung erweitert, ist deshalb eine Produkt- und Kompatibilitätsentscheidung des Serverteams. notifications/tools/list_changed kann interessierte Clients über eine veränderte Liste informieren, löst aber keine Migration aus.

  • Additiv: Neue optionale Fähigkeit mit klarer Bedeutung veröffentlichen und bestehende Aufrufe erhalten.
  • Breaking: Alten Vertrag weiter bedienen oder eine getrennte Capability für die neue Semantik anbieten.
  • Deprecation: Übergangszeit, Kommunikation und Entfernung bewusst im eigenen Release-Prozess festlegen.
Trade-offLange Parallelunterstützung senkt Integrationsbruch, erhöht aber Test- und Betriebsaufwand. Eine schnelle Ablösung spart Pflege, zwingt Hosts jedoch zu koordinierten Upgrades.

In Revision 2026-07-28 erhält ein Client Änderungsnotifications nur über einen von ihm geöffneten subscriptions/listen-Stream und nur für angeforderte, vom Server unterstützte Typen. Eine Notification ist ein Invalidierungssignal: Der Client liest den Vertrag neu, statt die Änderung aus der Nachricht zu erraten. Caching bleibt komplementär. Ein frischer Cache wird bei relevanter Notification sofort stale; ohne Stream endet seine angenommene Frische spätestens nach ttlMs. Bei paginierten Listen ist jede Seite separat cachebar, aber es gibt keine seitenübergreifende Snapshot-Garantie.

Eine Listenänderung und eine semantische Migration sind verschiedene Ereignisse. Das Signal sagt nur, dass der Konsument neu listen sollte. Es übermittelt keinen Diff und beweist nicht, dass alte Aufrufe noch funktionieren. Bei einem inkompatiblen Pflichtfeld braucht das Serverteam daher weiterhin eine Übergangsstrategie: alte Form akzeptieren, sicheren Default dokumentieren oder eine getrennte neue Capability veröffentlichen. Erst wenn unterstützte Clients migriert und beobachtet sind, kann der alte Vertrag entfallen. Preis: Paralleler Betrieb erhöht Code- und Testlast; ein sofortiger Bruch verlagert diese Last unkontrolliert auf alle Hosts.

Ein Vertrags-Review vor dem Release

Prüfe einen Serververtrag in vier Fragen: Bleibt die veröffentlichte Bedeutung unabhängig von der Backend-Implementierung? Kann ein Host vollständige Fähigkeiten entdecken und nur nach Negotiation nutzen? Werden Schema, URI und Prompt-Argumente auf beiden Seiten gleich verstanden? Und erhält jede Änderung einen expliziten Policy- und Kompatibilitätsschritt?

  • Mache Namen, URIs, Argumente und Seiteneffekte für den Konsumenten verständlich.
  • Halte interne IDs, Dateipfade und unkontrollierte Backend-Fehler aus dem öffentlichen Vertrag heraus.
  • Kopple Vertrauensentscheidungen nie an Beschreibungen oder Annotations des Servers.
AbgrenzungWie du den Serverprozess implementierst, transportierst und testest, folgt in den nächsten Modulen. Hier trainierst du die veröffentlichte Bedeutung, auf der diese Arbeit aufbaut.

Vertragsreview für search_docs

Szenario

Ein Release ergänzt Mandantenfilter, strukturierte Treffer und eine dynamische Toolliste.

Anforderungen

  • Alte Aufrufe ohne Filter behalten ihre dokumentierte Bedeutung
  • outputSchema beschreibt die neuen strukturierten Treffer
  • Nutzerspezifische Listen bleiben cacheScope: private
  • Änderungen invalidieren nur Clients mit passender Subscription

Schritte

  1. Drahtschema gegen JSON Schema 2020-12 prüfen
  2. fachliche Semantik alt gegen neu vergleichen
  3. Cache- und Notification-Vertrag festlegen
  4. Migration mit alten und neuen Hosts testen

Merksatz: Schema, Semantik, Sichtbarkeit und Frische sind vier getrennte Vertragsachsen.

Gleich entscheidest du acht Vertragsgrenzen

Die Checks folgen derselben Linie: erst eine stabile Capability statt eines Backend-Leaks, dann Discovery und Schema, anschließend Resources und Prompts, danach präzise deklarierte Server-Capabilities, unverbindliche Annotations und bewusst migrierte Releases. Entscheidend ist jeweils nicht, was ein Server technisch senden kann, sondern welche Aussage ein Host belastbar als Vertrag verwenden darf.

ZielEin MCP-Vertrag soll Funktionen auffindbar und nutzbar machen, ohne dass Discovery zu impliziter Berechtigung oder ein internes Detail zu einer dauerhaften externen Zusage wird.

Du entscheidest gleich über Discovery, Capability-Deklaration, additive Schemaänderungen, stabile Resource-URIs, Prompt-Argumente, untrusted Annotations, Cache-Invalidierung und eine kontrollierte Semantikmigration. Prüfe jeweils zuerst, welche Zusage ein Konsument vernünftigerweise ableitet. Danach trennst du Form, Bedeutung, Autorisierung und Aktualität. Wer diese Ebenen vermischt, bekommt Verträge, die formal validieren und im Betrieb dennoch falsche Aktionen oder Daten erzeugen.

Nutze für jede Antwort denselben Review-Satz: Wer darf was in welcher Form unter welcher Bedeutung wie lange als aktuell ansehen? inputSchema und outputSchema beantworten die Form. Beschreibung, URI und dokumentierte Seiteneffekte tragen Bedeutung. Autorisierung und Host-Policy bestimmen Sichtbarkeit und Ausführung. ttlMs, cacheScope und Subscriptions steuern Aktualität. Keine einzelne dieser Achsen ersetzt die anderen. Ein belastbarer Serververtrag benennt sie getrennt und macht ihre jeweiligen Nachteile sichtbar. Schreibe die erwartete Reaktion auf unbekannte Felder, abgelaufene Cacheeinträge, entfernte Capabilities und nicht unterstützte Revisionen ausdrücklich in Contract-Tests. Das verhindert, dass nur der glückliche Pfad dokumentiert ist. Ein Host muss einen veralteten Vertrag verwerfen können, ohne eine ungeprüfte Ersatzfähigkeit zu erfinden; ein Server muss einen ungültigen Request ablehnen können, ohne seine interne Implementierung offenzulegen. Diese Fehlerpfade sind Teil der veröffentlichten Bedeutung und nicht bloß Betriebsdetails.

Jetzt anwenden

Diesen Stoff gibt es als Modul mit bewerteten Entscheidungs-Checks — dieselbe Einführung, danach die Übungen.

Zum Modul →
Quellen & Aktualität10 Primärquellen · zuletzt geprüft:
  1. 01modelcontextprotocol.io/specification/2026-07-28/basic/index
  2. 02modelcontextprotocol.io/specification/2026-07-28/basic/versioning
  3. 03modelcontextprotocol.io/specification/2026-07-28/server/discover
  4. 04modelcontextprotocol.io/specification/2026-07-28/server/tools
  5. 05modelcontextprotocol.io/specification/2026-07-28/server/resources
  6. 06modelcontextprotocol.io/specification/2026-07-28/server/prompts
  7. 07modelcontextprotocol.io/specification/2026-07-…er/utilities/caching
  8. 08modelcontextprotocol.io/specification/2026-07-…lities/subscriptions
  9. 09json-schema.org/draft/2020-12/json-schema-validation
  10. 10modelcontextprotocol.io/specification/2026-07-…utilities/completion