Mein erster MCP-Server hat vier Stunden gebraucht. Es hätten vierzig Minuten sein sollen. Den Rest habe ich damit verbracht, ein Problem zu debuggen, das gar nicht existierte — weil ich nicht verstanden hatte, was MCP eigentlich ist, bevor ich angefangen habe zu tippen. Also lass mich dir diesen Nachmittag ersparen.
MCP — das Model Context Protocol — ist einfach eine Möglichkeit, Claude Code neue Tools zu geben. Das ist alles. Dein Editor gibt Claude bereits Dateizugriff und eine Shell. Ein MCP-Server gibt ihm mehr: eine Datenbank, die es abfragen kann, eine API, die es aufrufen kann, dein Linear-Board, dein Postgres, was auch immer. Der Server läuft als eigener Prozess. Claude kommuniziert über ein einfaches Protokoll mit ihm. Wenn Claude entscheidet, dass es dein Tool braucht, ruft es dieses auf, bekommt ein Ergebnis und macht weiter.
Das ist das gesamte mentale Modell. Halte es fest.
Was du brauchst, bevor du deinen ersten MCP-Server startest
Node 18 oder neuer. Ein Terminal. Claude Code installiert und funktionsfähig. Das ist die Liste. Du brauchst kein Docker, kein Cloud-Konto und musst das Wire-Format des Protokolls nicht verstehen — das SDK erledigt alles davon.
Wir werden einen kleinen Server bauen, der ein einziges Tool bereitstellt: das aktuelle Wetter für eine Stadt abrufen. Gefälschte Daten, weil es um die Infrastruktur geht, nicht ums Wetter. Sobald die Infrastruktur funktioniert, ist der Wechsel zu einer echten API eine Fünf-Minuten-Änderung.
Schritt 1: Projekt scaffolden
mkdir weather-mcp && cd weather-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
Das zod-Paket ist kein optionales Beiwerk. MCP-Tools brauchen ein Schema, damit Claude weiß, welche Argumente übergeben werden sollen, und zod ist der sauberste Weg, eines zu schreiben. Du wirst dir später selbst danken, wenn Claude jedes Mal exakt die richtige Form übergibt.
Schritt 2: Den Server schreiben
Erstelle index.js:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "weather", version: "1.0.0" });
server.tool(
"get_weather",
"Get the current weather for a city",
{ city: z.string().describe("City name, e.g. Lisbon") },
async ({ city }) => ({
content: [{ type: "text", text: `It's 22°C and sunny in ${city}.` }],
})
);
const transport = new StdioServerTransport();
await server.connect(transport);
Sieh, wie wenig das ist. Ein Tool, ein Schema, eine gefälschte Antwort. Der StdioServerTransport-Teil ist der, der mich beim ersten Mal eine Stunde lang verwirrt hat — er bedeutet, dass der Server mit Claude über Standardeingabe und -ausgabe kommuniziert, nicht über einen Netzwerk-Port. Dein Server hat also kein console.log-Debugging, weil alles, was du auf stdout ausgibst, den Protokoll-Stream korrumpiert. Drucke stattdessen auf console.error. Brenne das in dein Gedächtnis.
Schritt 3: Bei Claude Code registrieren
Claude Code liest MCP-Server aus einer Konfigurationsdatei. Der einfachste Weg ist die CLI:
claude mcp add weather -- node /full/path/to/weather-mcp/index.js
Verwende den absoluten Pfad. Relative Pfade sehen gut aus und scheitern dann mysteriöserweise, wenn Claude den Server aus einem anderen Arbeitsverzeichnis startet. Ich habe diesen Fehler dreimal gemacht. Absoluter Pfad. Jedes Mal.
Dann prüfen, ob er registriert wurde:
claude mcp list
Du solltest weather in der Ausgabe sehen. Wenn nicht, ist der Add-Befehl lautlos fehlgeschlagen — führe ihn erneut aus und lies die Fehlermeldung.
Schritt 4: Tatsächlich benutzen
Starte eine Claude Code-Sitzung in einem beliebigen Projekt und frage:
Wie ist das Wetter in Lisbon?
Claude sollte erkennen, dass es ein get_weather-Tool hat, es aufrufen und mit deiner gefälschten Antwort antworten. Wenn das zum ersten Mal funktioniert, fühlt es sich ein bisschen wie Magie an — du hast eine Funktion in einer separaten Datei geschrieben, und jetzt kann dein KI-Assistent sie eigenständig aufrufen.
Wenn Claude das Tool nicht aufruft, ist die Beschreibung in neun von zehn Fällen zu vage. "Das aktuelle Wetter für eine Stadt abrufen" sagt Claude genau, wann es das Tool verwenden soll. "Wetter-Tool" nicht. Tool-Beschreibungen sind Prompts. Schreibe sie so, als würdest du einem neuen Teammitglied das Tool erklären, das entscheiden soll, wann es einzusetzen ist.
Die drei Dinge, die dich stolpern lassen werden
Stdout-Verschmutzung. Bereits erwähnt, sage ich nochmal, weil es der häufigste Bug beim ersten Server ist. Kein console.log. Niemals. Das Protokoll lebt auf stdout.
Veralteter Prozess. Wenn du index.js bearbeitest, lädt Claude es nicht neu. Starte deine Claude Code-Sitzung neu, damit der Server neu gestartet wird. Ich habe einmal zwanzig Minuten damit verbracht, überzeugt zu sein, dass meine Codeänderung nicht funktioniert, während ich in Wirklichkeit die alte Version ausführte.
Schema-Abweichungen. Wenn dein zod-Schema sagt, dass city erforderlich ist, und Claude nichts übergibt, bekommst du einen verwirrenden Fehler. Mache optionale Dinge tatsächlich optional mit .optional(), und gib jedem Feld ein .describe(), damit Claude weiß, was dort hingehört.
Vom Spielzeug zur echten Anwendung
Jetzt der lustige Teil. Dieser gefälschte Wetter-String? Ersetze den Funktionskörper durch ein echtes fetch zu einer tatsächlichen Wetter-API. Das Schema, die Registrierung, die Art, wie Claude es aufruft — nichts davon ändert sich. Du hast den schwierigen Teil bereits gebaut.
Das ist das Ding, das einem beim Thema MCP niemand sagt: Der erste Server ist 90% des Lernens. Jeder weitere Server danach sind dieselben fünf Schritte mit einer anderen Funktion in der Mitte. Willst du, dass Claude deine Datenbank abfragt? Gleiches Muster. Die interne API deines Unternehmens aufrufen? Gleiches Muster. Dein Notion lesen? Du verstehst es.
Baue den Wetter-Server heute Abend. Es wird vierzig Minuten dauern, wenn du den vierstündigen Umweg überspringst, den ich genommen habe. Und morgen baust du dann den, den du wirklich brauchst.
