Start / Seminare / MCP & Agentic Software Engineering
Modul
Einen lokalen MCP-Server entwickeln
5 Kapitel in diesem Modul-Video · Laufzeit
Transkript
Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.
Einen lokalen MCP-Server entwickeln
0:00 Jetzt bauen wir. Und die gute Nachricht vorweg: Ein lauffähiger MCP-Server ist in zwanzig Zeilen geschrieben. Die Spezifikation nennt es sogar als Entwurfsprinzip, dass Server leicht zu bauen sein sollen. Die eigentliche Arbeit liegt woanders — nämlich darin, den Server so zu bauen, dass ein Sprachmodell ihn versteht. Das ist eine ungewohnte Zielgruppe: Ihr Gegenüber liest keine Dokumentation, hat kein Gedächtnis für Konventionen und entscheidet allein anhand dessen, was im Schema steht.
Einen lokalen MCP-Server entwickeln
0:30 In diesem Modul entsteht der Server, der uns durch das ganze Seminar begleitet: anliegen-mcp. Am Ende kann er das Architekturhandbuch liefern und in den Anforderungen suchen. Er kann bewusst noch nichts verändern — schreibende Operationen kommen erst am dritten Tag dazu, wenn wir wissen, wie man sie absichert. Das ist kein didaktischer Trick, sondern die Reihenfolge, die ich auch im echten Projekt empfehlen würde.
Projektstruktur und offizielles SDK
0:54 Fangen wir mit dem Gerüst an. Es ist erfreulich wenig — und eine Entscheidung darin lohnt sich, von Anfang an richtig zu treffen. Das offizielle TypeScript-SDK liegt im Paket mit dem Namen server unter dem Model-Context-Protocol-Namensraum. Achten Sie auf den Paketnamen — er hat sich geändert, und ältere Anleitungen nennen einen anderen.
1:15 Der Server entsteht als Objekt mit Name und Version, und die Transportanbindung ist davon getrennt: Sie wird erst beim Start gewählt. Diese Trennung ist keine Formalie, sondern der Grund, warum derselbe Server später ohne Änderung entfernt laufen kann. Zwei Abhängigkeiten, ein Objekt — mehr ist es nicht. Interessant ist, was hier nicht steht: kein Transport, keine Werkzeuge, keine Konfiguration.
1:39 Das Serverobjekt kennt nur seinen Namen und seine Version. Nehmen Sie die Version ernst, auch wenn sie hier wie Dekoration aussieht; sie wandert später in jede Antwort und ist im Betrieb das Einzige, woran Sie erkennen, welcher Stand gerade antwortet. Die Dokumentation setzt Node in Version 20 oder neuer voraus. Das ist die Entscheidung, die ich vorhin meinte, und sie kostet Sie jetzt fünf Minuten und spart später Tage.
2:05 Die Werkzeugfunktion soll nichts tun, außer eine normale Funktion Ihrer Anwendung aufzurufen. Dann bleibt die Fachlogik ohne Protokoll testbar — und das ist die Voraussetzung für alles, was wir in Modul 6 über automatisierte Tests besprechen. Wer die Fachlogik in die Werkzeugfunktion schreibt, kann sie nur noch über das Protokoll testen.
2:24 Und Tests über das Protokoll sind langsam, umständlich und decken Grenzfälle schlecht ab. Der letzte Punkt ist der, den jeder einmal erlebt: Eine Ausgabe landet auf stdout, und die Verbindung ist tot. Bei stdio läuft das Protokoll über genau diesen Kanal — eine einzige Debug-Zeile zerstört ihn. Wohin die Ausgaben stattdessen gehören, klären wir im nächsten Modul.
2:46 Und der zweite Punkt klingt harmlos, ist es aber nicht: Eine Version, die auf eins-null-null stehen bleibt, sagt nach dem dritten Deployment nichts mehr aus. Das merkt man an dem Tag, an dem man wissen will, welche Fassung gerade Unsinn antwortet.
Das erste Tool registrieren
3:01 Kommen wir zum Kernstück. Ein Werkzeug anzumelden ist trivial — es gut zu beschreiben, ist die eigentliche Aufgabe. Ein Tool trägt einen eindeutigen Namen, eine Beschreibung und ein Eingabeschema. Optional kommt ein Ausgabeschema dazu, und das ist eine Überlegung wert: Ist es gesetzt, muss der Server ein passendes strukturiertes Ergebnis liefern, und Clients sollen es prüfen.
3:24 Sie geben also eine Zusage ab, die überprüfbar ist. Das ist mehr Aufwand und deutlich mehr Wert — vor allem, wenn die Ergebnisse weiterverarbeitet statt nur gelesen werden. Schauen Sie auf die Beschreibungen in den Parametern, nicht auf die Syntax. Der Suchbegriff bekommt ein Beispiel mitgeliefert — Kostenstelle. Das klingt nach einer Kleinigkeit und ist der wirksamste Hebel, den Sie haben: Ein Modell, das ein Beispiel sieht, trifft die Form des Aufrufs deutlich zuverlässiger.
3:53 Ebenso die Obergrenze bei der Trefferzahl und der Vorgabewert. Jede dieser Angaben ist eine Entscheidung, die Sie dem Modell abnehmen — und jede Entscheidung, die Sie ihm abnehmen, kann es nicht falsch treffen. Hier ist der Perspektivwechsel, um den es in diesem Modul geht. Das Schema ist nicht Validierung, das Schema ist Dokumentation — für einen Leser, der nichts anderes hat.
4:16 Deshalb führen Aufzählungen sicherer als freie Zeichenketten: Wer drei erlaubte Werte anbietet, bekommt einen dieser drei. Wer ein Textfeld anbietet, bekommt alles. Und ein Detail, das gern falsch gemacht wird: Ein Werkzeug ohne Parameter bekommt ein leeres Objektschema, nicht null. Die Spezifikation ist da ausdrücklich.
4:37 Der erste Punkt begegnet mir am häufigsten: Die Beschreibung ist aus dem Funktionskommentar kopiert und erklärt die Implementierung. Ein Modell will wissen, wozu ein Werkzeug da ist und wann man es nimmt — nicht, wie es intern arbeitet. Der letzte Punkt ist sicherheitsrelevant und betrifft eine Funktion, die wir in Modul 16 genauer ansehen: Parameter lassen sich in HTTP-Header spiegeln, damit Zwischenstellen routen können.
5:01 Für sensible Werte ist das die falsche Idee — Header sehen unterwegs viele Systeme.
Eine Resource bereitstellen
5:07 Von den Werkzeugen zu den Ressourcen. Der Unterschied ist einer der Wirkung: Eine Resource tut nichts, sie ist da. Eine Resource ist über eine Adresse eindeutig identifiziert und trägt Name, optional einen Anzeigetitel und eine Beschreibung sowie einen Inhaltstyp. Der Inhalt kommt als Text oder als kodierter Binärblock. Und wenn Sie mehrere ähnliche Inhalte anbieten wollen — etwa jede Datei eines Verzeichnisses —, gibt es Vorlagen mit Platzhaltern in der Adresse.
5:34 Das ist die elegante Antwort auf die Frage, wie man tausend Dateien anbietet, ohne tausend Einträge zu pflegen. Die interessante Zeile ist die letzte. Annotationen sind optional und werden deshalb oft weggelassen — dabei stecken dort drei nützliche Angaben. Die Zielgruppe unterscheidet, ob ein Inhalt für den Menschen oder für das Modell gedacht ist.
5:55 Die Priorität sagt dem Client, wie wichtig dieser Inhalt ist, auf einer Skala von null bis eins. Und das Änderungsdatum erlaubt es, nach Aktualität zu sortieren. Für einen Client, der entscheiden muss, was er in ein begrenztes Kontextfenster packt, sind das genau die drei Angaben, die er braucht. Die erste Regel ist die wichtigste und wird am häufigsten verletzt: Der Zuschnitt entscheidet über das Kontextbudget, nicht die Quelle.
6:21 Ein Handbuch mit hundert Seiten als eine Resource anzubieten ist technisch korrekt und praktisch unbrauchbar. Die vierte Regel ist eine Spezifikationsvorgabe, die man kennen sollte: Eine nicht vorhandene Ressource wird mit einem Fehler abgelehnt — und ausdrücklich nicht mit einer leeren Inhaltsliste. Denn leer ist mehrdeutig: Gibt es sie nicht, oder ist sie nur leer?
6:42 Der zweite Punkt ist ein klassisches Sicherheitsthema in neuem Gewand: Pfade werden nicht bereinigt, und schon lässt sich aus dem erlaubten Verzeichnis herausklettern. Die Spezifikation verlangt ausdrücklich, Dateipfade zu säubern. Der letzte Punkt ist der, an den man zuletzt denkt und der am meisten Ärger macht: Personenbezogene Inhalte aus Serviceanfragen liegen ungefiltert in einer Resource.
7:04 Ab dem Moment sind sie im Kontext eines Sprachmodells — und die Frage, wo sie danach landen, beantwortet Ihnen niemand mehr zufriedenstellend.
Einen wiederverwendbaren Prompt anbieten
7:12 Bleibt das dritte Primitive, das am seltensten genutzt wird und erstaunlich viel Nutzen bringt. Ein Prompt ist eine benannte Vorlage mit optionalen Argumenten. Der Client listet die verfügbaren Vorlagen auf und holt die ausgefüllte Fassung ab; heraus kommt eine Folge von Nachrichten. In vielen Clients erscheinen Prompts als Schrägstrich-Befehle — das ist die Form, in der Ihre Kolleginnen und Kollegen ihnen begegnen.
7:36 Und darin liegt der eigentliche Wert: Ein Prompt ist die Möglichkeit, eine bewährte Arbeitsweise einmal aufzuschreiben, statt sie in zwanzig Chatverläufen zu wiederholen. Vier Felder, und das entscheidende ist das Argument mit seiner Pflichtkennzeichnung. Fehlt ein Pflichtargument, antwortet der Server mit einem Fehler — die Vorlage ist also nicht nur Text, sie hat einen Vertrag.
7:58 Beachten Sie auch den Titel neben dem Namen: Der Name ist für die Maschine, der Titel für die Oberfläche. Diese Trennung zieht sich durch alle drei Primitives und ist der Grund, warum man technische Namen nicht schön machen muss. Hier liegt der eigentliche Gewinn, und er ist organisatorischer Natur. Eine Vorlage im Repository hat eine Historie, sie ist überprüfbar, und Änderungen an ihr laufen über einen Pull Request wie jede andere Änderung auch.
8:24 Vergleichen Sie das mit dem Normalzustand: Jeder hat seinen eigenen Textbaustein in einer Notiz, niemand weiß, welcher der aktuelle ist. Eine Vorlage im Server macht aus einer privaten Gewohnheit eine Teampraxis — und das, ohne dass jemand eine Richtlinie schreiben musste. Der erste Punkt ist der, vor dem ich am deutlichsten warnen möchte: Die Vorlage enthält Anweisungen, die eigentlich Berechtigungen regeln sollen.
8:49 Sätze wie „lösche nichts ohne Rückfrage" gehören nicht in einen Prompt, sondern in den Server. Der zweite ist handwerklich: Argumente werden ungeprüft in den Text eingesetzt — das ist eine Einladung zur Injektion, und sie kommt nicht einmal von außen, sondern über Ihre eigene Vorlage. Die Spezifikation verlangt ausdrücklich, Ein- und Ausgaben von Prompts sorgfältig zu prüfen.
Übung
9:11 Jetzt bauen Sie. Am Ende steht ein Server, der etwas kann — und der bewusst etwas nicht kann. Eine Resource, zwei lesende Werkzeuge. Schreibende Operationen lassen wir ausdrücklich weg, obwohl es technisch nichts kosten würde, sie zu ergänzen. Das ist die Reihenfolge, die ich auch außerhalb des Seminars empfehle: Erst der lesende Zugriff, dann die Absicherung, dann die Wirkung.
9:35 Umgekehrt baut man sich eine Schuld auf, die man später unter Zeitdruck abtragen muss. Der Server liefert das Architekturhandbuch als Resource und bietet zwei Werkzeuge: eines für die Suche in den Anforderungen, eines für die Ermittlung betroffener Komponenten. Prüfen Sie am Ende im Inspector, ob alle drei mit gültigen, schemakonformen Ergebnissen antworten — den Inspector schauen wir uns gleich im nächsten Modul genauer an.
10:00 Wer früher fertig ist, ergänzt die Vorlage für den Änderungsbericht als Prompt mit einem Pflichtargument. Der erste Punkt ist die Versuchung, der man widerstehen sollte: Schreibzugriff gleich mitzunehmen, weil es nur eine Zeile mehr wäre. Der dritte ist der, der sich erst später rächt — der Server wird nur gegen den eigenen Client getestet. Dann funktioniert er genau dort und sonst nirgends.
10:22 Und der vierte ist die Brücke zum nächsten Modul: Fehlerfälle liefern einen leeren Treffer statt einer Aussage. Ein Agent kann mit „nichts gefunden" arbeiten und mit einer leeren Liste, die auch einen Ausfall bedeuten könnte, eben nicht.
Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →