Start / Seminare / MCP & Agentic Software Engineering

Modul

MCP-Architektur: Host, Client und Server

5 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

MCP-Architektur — Host, Client und Server

0:00 Jetzt wird es konkret. Drei Rollen, zwei Schichten und ein Nachrichtenformat — mehr ist die Architektur von MCP nicht. Das klingt nach wenig, und das ist auch so gewollt. Aber diese wenigen Bausteine muss man sauber auseinanderhalten können, denn fast jeder Fehler, der Ihnen später im Betrieb begegnet, lässt sich genau einem von ihnen zuordnen.

0:20 Wer weiß, ob ein Problem in der Datenschicht oder im Transport sitzt, hat die Fehlersuche schon halbiert.

MCP-Architektur — Host, Client und Server

0:27 In diesem Modul bauen wir noch nichts, aber wir legen das Vokabular fest, mit dem wir den Rest des Seminars bestreiten. Achten Sie besonders auf zwei Dinge: auf die Trennung zwischen dem, was gesagt wird, und dem, wie es übertragen wird — und auf die Fehlercodes im dritten Kapitel. Die sehen Sie morgen im Inspector wieder, und dann sparen sie Ihnen zwanzig Minuten Suchen.

Die drei Rollen

0:48 Beginnen wir mit den Rollen. Sie sind schnell erklärt, und die eigentliche Aussage steckt in ihrer Beziehung zueinander — nicht in den Rollen selbst. Denken Sie an einen Browser mit mehreren Tabs. Der Browser ist der Host: Er verwaltet alles, setzt die Regeln durch und weiß als Einziger, was insgesamt los ist. Jeder Tab ist ein Client, und jeder Tab spricht mit genau einer Seite — dem Server. Was ein Tab sieht, sieht der andere nicht.

1:14 Genau so ist MCP gebaut: Ein Host erzeugt beliebig viele Clients, jeder Client hält die Verbindung zu genau einem Server, und jeder Server liefert seinen abgegrenzten Ausschnitt an Werkzeugen, Kontext und Vorlagen. Vier Stationen, und der Pfeil geht in beide Richtungen. Was hier so selbstverständlich aussieht, ist der Grund, warum wir in Modul 14 ein Bedrohungsmodell brauchen, das genau diese vier Stationen abläuft.

1:39 Halten Sie sich an dieser Stelle vor allem den letzten Übergang vor Augen: Zwischen Server und Zielsystem verlässt die Anfrage die Welt des Protokolls. Ab dort gelten wieder die Regeln Ihrer Datenbank, Ihrer API, Ihres Dateisystems — und die kennen keinen Agenten. Die interessante Information steht in der Fußzeile: Die Eins-zu-eins-Beziehung zwischen Client und Server ist die technische Form der Isolation.

2:04 Das ist der Satz, den man sich merken sollte. Man könnte einen Client bauen, der mit drei Servern spricht — technisch spräche nichts dagegen. Die Spezifikation verlangt es anders, weil sonst die Grenze zwischen den Servern verschwimmt. Isolation ist hier also nicht nachträglich aufgesetzt, sondern in der Struktur angelegt.

2:22 Solche Entscheidungen erkennt man daran, dass sie unbequem sind und trotzdem getroffen wurden. Vier Aussagen, die alle in dieselbe Richtung zeigen. Ein Server soll den Gesprächsverlauf nicht lesen können. Er soll auch nicht sehen, was andere Server liefern. Der vollständige Verlauf bleibt beim Host. Und Server sollen fokussiert bleiben, damit man sie zusammensetzen kann.

2:45 Der praktische Nutzen wird sofort klar, wenn Sie sich fragen, unter welchen Umständen Sie einen fremden Server einbinden würden. Ohne diese Isolation: unter keinen. Mit ihr: unter überschaubaren. Das ist der eigentliche Zweck — sie senkt die Schwelle, Fremdes zu nutzen, ohne alles zu zeigen.

Daten- und Transportschicht

3:04 Kommen wir zur zweiten Trennlinie. Sie ist weniger sichtbar als die Rollen, aber im Alltag mindestens so nützlich. Die Unterscheidung ist dieselbe wie zwischen einem Brief und der Post. Die Datenschicht ist der Inhalt: welche Nachrichten es gibt, was Werkzeuge und Ressourcen sind, wie Fähigkeiten ausgehandelt werden. Die Transportschicht ist der Zustellweg: wie die Nachricht verpackt ist, wie eine Verbindung entsteht, wie Abbruch und Autorisierung funktionieren.

3:31 Der entscheidende Satz der Spezifikation lautet: Die Protokollsemantik ist auf jedem Transport identisch. Ein Transport ist eine Bindung, kein Bedeutungsträger — er definiert nicht, was die Nachrichten heißen. Drei Ebenen, und die oberste ist die, auf die es hier besonders ankommt. Die Anwendung — also Modellsteuerung und Kontextaufbau — liegt außerhalb von MCP.

3:53 Sie ist mitgezeichnet, weil sie in jedem realen System existiert, aber sie ist nicht Teil des Protokolls. Wenn also im Team die Frage aufkommt, warum MCP nicht regelt, welches Werkzeug ausgewählt wird: Es liegt eine Etage höher, und diese Etage bauen Sie selbst oder kaufen sie mit dem Host ein. Der praktische Gewinn zeigt sich spätestens beim Umzug. Derselbe Server läuft lokal und entfernt, ohne dass die Logik sich ändert — das ist unser Weg in Modul 16.

4:21 Ein Transport darf Metadaten in Header spiegeln, ohne die Bedeutung zu verändern; und dabei gilt eine Regel, die Sie sich merken sollten: Der Nachrichtenkörper bleibt immer die maßgebliche Quelle. Der Header ist eine Kopie für Zwischenstellen, nicht die Wahrheit. Wer das verdreht, baut sich genau die Sicherheitslücke, gegen die die Spezifikation einen eigenen Fehlercode vorsieht.

4:43 Der erste Punkt ist der häufigste Architekturfehler: Fachlogik wandert in den Transport und bindet den Server damit an HTTP. Spätestens wenn jemand denselben Server lokal starten will, fällt das auf. Der zweite Punkt ist der sicherheitsrelevante — der Header wird zur Wahrheit statt der Nachrichtenkörper. Und der dritte ist einer, den man erst unter Last merkt: Abbruch wird transportspezifisch gedacht und im Server schlicht vergessen.

5:08 Der Server arbeitet dann weiter an einer Anfrage, für die sich längst niemand mehr interessiert.

JSON-RPC als Nachrichtengrundlage

5:14 Jetzt zu den Nachrichten selbst. Hier hat sich mit der aktuellen Spezifikationsversion etwas Grundlegendes geändert — und das sollten Sie wissen, wenn Sie ältere Beispiele im Netz finden. Die Grundlage ist JSON-RPC in der Version 2.0, also nichts Exotisches. Requests tragen eine Kennung und lösen eine Antwort aus, Notifications tragen keine und werden nicht beantwortet.

5:37 Und jetzt die Änderung, die alles betrifft: Server senden keine eigenen Requests mehr. Wenn ein Server eine Eingabe braucht, fragt er nicht zurück — er antwortet mit einem Zwischenergebnis, das sagt, was ihm fehlt. Der Client besorgt es und stellt die Frage neu. Das dreht den Nachrichtenfluss um und macht ihn deutlich einfacher zu betreiben.

5:59 Schauen Sie nicht auf die Klammern, sondern auf das Feld ganz unten. Jeder einzelne Aufruf trägt in seinen Metadaten die Protokollversion mit — und, was hier aus Platzgründen fehlt, auch die Fähigkeiten des Clients. Das ist der sichtbare Ausdruck der Zustandslosigkeit: Die Anfrage bringt alles mit, was der Server zu ihrer Bearbeitung braucht. Früher stand das einmal im Verbindungsaufbau.

6:21 Heute steht es in jeder Nachricht. Fehlt es, lehnt der Server ab — und zwar mit dem Code für ungültige Parameter, was beim ersten Mal verwirrend ist. Diese vier Codes ersparen Ihnen echte Suchzeit. Der erste ist der Allzweckcode für alles, was formal nicht stimmt — fehlendes Pflichtfeld, unbekannte Ressource. Die anderen drei sind neu und sehr spezifisch. Header und Rumpf widersprechen sich: Das trifft nur den HTTP-Transport und zeigt auf eine falsch konfigurierte Zwischenstelle.

6:51 Fehlende Client-Fähigkeit: Der Server braucht etwas, das der Client nicht angemeldet hat. Und die nicht unterstützte Protokollversion, die ihre unterstützten Versionen gleich mitliefert. Wichtig ist die Fußzeile: Der Bereich ist reserviert. Eigene Codes gehören woandershin. Der erste Punkt — ein eigener Fehlercode im reservierten Bereich — passiert leicht und rächt sich spät, nämlich wenn die Spezifikation denselben Code für etwas anderes vergibt.

7:19 Der zweite betrifft alle, die von einer älteren Version migrieren: Antworten tragen jetzt ein Feld, das den Ergebnistyp angibt. Fehlt es, gilt die Antwort als vollständig — das ist die Rückwärtskompatibilität. Wer es aber ignoriert, übersieht genau den Fall, in dem der Server eigentlich eine Rückfrage gestellt hat. Der vierte Punkt ist eine Erfahrung aus der Praxis: Lokale Fehler des SDK sehen aus wie Fehler der Gegenstelle, wenn man sie nicht sauber trennt.

Lokale und entfernte Transports

7:46 Bleiben die beiden Transportwege. Die Entscheidung zwischen ihnen fällt weniger technisch aus, als man denkt. Zwei Standardwege. Über stdio läuft alles über die Standardstreams eines Prozesses, den der Client selbst startet — das ist die lokale Variante, denkbar einfach, ohne Netz. Über Streamable HTTP ist jede Nachricht ein POST auf einen einzigen Endpunkt; die Antwort kommt entweder als JSON-Objekt oder als Ereignisstrom, der genau zu dieser einen Anfrage gehört.

8:15 Beachten Sie das Wort „einzigen": Es gibt einen Endpunkt, nicht viele. Die Methode steht in der Nachricht, nicht im Pfad. Die Gegenüberstellung macht die Entscheidung einfach, und sie fällt in der Regel an der letzten Zeile. Ein Client je Prozess gegen viele Clients gleichzeitig — sobald ein zweiter Mensch denselben Server braucht, ist die lokale Variante am Ende.

8:37 Interessant ist auch die zweite Zeile: Lokal kommen die Zugangsdaten aus der Umgebung, und die Autorisierungsspezifikation gilt ausdrücklich nicht. Das ist kein Versäumnis, sondern Absicht — ein lokaler Prozess läuft ohnehin mit den Rechten des Nutzers, da wäre OAuth eine Fassade. Das ist eine der praktischsten Neuerungen dieser Spezifikationsversion.

8:57 Zwei Header spiegeln, was im Rumpf steht: die aufgerufene Methode und der Name des Werkzeugs beziehungsweise der Ressource. Klingt nach Redundanz, ist aber der Unterschied zwischen einem Gateway, das JSON parsen muss, und einem, das einfach routen und zählen kann. Und damit daraus keine Sicherheitslücke wird, gibt es die Gegenprobe: Weichen Header und Rumpf voneinander ab, muss der Server ablehnen.

9:20 Sonst könnte ein Angreifer der Zwischenstelle etwas anderes erzählen als dem Server. Der erste Punkt ist der Klassiker bei jedem ersten lokalen Server: eine Logausgabe auf stdout, und das Protokoll ist zerstört. Er passiert jedem einmal, und in Modul 6 zeigen wir, wohin die Ausgaben stattdessen gehören. Der zweite und dritte gehören zusammen und sind ernst: Ein lokaler HTTP-Server, der an alle Schnittstellen bindet und den Origin-Header nicht prüft, lässt sich von einer Webseite aus ansprechen.

9:49 Die Spezifikation verlangt genau deshalb die Prüfung des Origin-Headers und empfiehlt, lokal nur an localhost zu binden.

Übung

9:57 Zum Abschluss zeichnen wir den Weg einer einzigen Anfrage vollständig nach — und tragen dann die Grenzen ein, die im Bild fehlen. Die Übung besteht aus zwei Teilen, und der zweite ist der wichtigere. Erst verfolgen Sie einen Werkzeugaufruf über alle Stationen, was noch geradeaus geht. Dann legen Sie drei Linien darüber: die Datengrenze, die Vertrauensgrenze und die Berechtigungsgrenze.

10:20 Diese drei Linien sind der Übergang zu Tag drei — jedes Sicherheitsthema, das wir dort behandeln, sitzt an einer von ihnen. Zeichnen Sie alle Stationen mit Richtung, tragen Sie die drei Grenzen ein und markieren Sie dann die erste Stelle, an der nicht vertrauenswürdiger Inhalt in den Kontext gelangt. Diese letzte Frage ist die eigentliche Übung. Ein Tipp: Die Antwort liegt früher, als die meisten vermuten.

10:44 Der Freitext einer Serviceanfrage im Anliegenbuch ist bereits fremder Inhalt — geschrieben von jemandem, der nicht in Ihrem Team sitzt, und gelesen von einem Agenten, der Text nicht von Anweisung unterscheidet. Der erste Punkt ist der häufigste Denkfehler: Die Vertrauensgrenze wird um den Server gezogen statt um die Daten.

11:03 Nicht der Server ist vertrauenswürdig oder nicht — die Inhalte sind es. Ein völlig korrekter Server kann fremden Text ausliefern. Der zweite Punkt betrifft die Vollständigkeit: Der Rückweg des Ergebnisses ins Kontextfenster fehlt im Bild fast immer, und genau dort passiert die indirekte Injektion. Und wenn Sie am Ende drei schöne Linien haben, aber keine Konsequenz daraus ziehen, war es eine Zeichenübung. Im nächsten Modul gehen wir in die Primitives.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →