Ihren ersten MCP-Server erstellen: Praxisleitfaden fuer Entwickler
Engineering Team
Was ist das Model Context Protocol (MCP)?
Das Model Context Protocol (MCP) ist ein offener Standard, der von Anthropic entwickelt wurde und definiert, wie AI-Anwendungen mit externen Datenquellen und Tools kommunizieren. Stellen Sie sich MCP als USB-C fuer die AI-Integration vor: So wie USB-C einen einzigen universellen Anschluss fuer Laden, Datenuebertragung und Bildschirmausgabe bietet, stellt MCP ein einziges universelles Protokoll bereit, um AI-Modelle mit Datenbanken, APIs, Dateisystemen und anderen Diensten zu verbinden. MCP eliminiert den Bedarf an individuellen Integrationen zwischen jeder AI-Anwendung und jedem Tool.
Im Jahr 2026 ist MCP zum dominierenden Standard fuer die AI-Tool-Kommunikation geworden. Gartner prognostiziert, dass 40 % der Unternehmensanwendungen bis Ende 2026 AI-Agenten enthalten werden, und MCP ist das Protokoll, das dies in grossem Massstab praktikabel macht. Vor MCP erforderte die Verbindung eines AI-Modells mit N Tools N individuelle Integrationen. Bei M AI-Anwendungen und N Tools benoetigte man M x N Integrationsadapter. MCP reduziert dies auf M + N: Jede AI-App implementiert einen MCP Client, jedes Tool implementiert einen MCP Server.
MCP-Architektur: Host, Client, Server und Transport
Das Verstaendnis der MCP-Architektur ist wesentlich, bevor Sie Code schreiben. Das Protokoll definiert vier Schluesselrollen:
| Komponente | Rolle | Beispiel |
|---|---|---|
| Host | Die AI-Anwendung, mit der Endbenutzer interagieren | Claude Desktop, Cursor, VS Code Copilot |
| Client | Der MCP-Protokollhandler innerhalb des Hosts | In die Host-Anwendung eingebaut |
| Server | Stellt Tools, Resources und Prompts ueber MCP bereit | Ihr benutzerdefinierter Server (den wir erstellen) |
| Transport | Die Kommunikationsschicht zwischen Client und Server | stdio, HTTP+SSE, Streamable HTTP |
Der Kommunikationsfluss funktioniert folgendermassen:
- Der Host startet und initialisiert einen MCP Client fuer jeden konfigurierten Server.
- Der Client verbindet sich mit dem Server ueber einen Transport (stdio fuer lokal, HTTP fuer remote).
- Der Client sendet eine
initialize-Anfrage und handelt Protokollversion und Faehigkeiten aus. - Der Server antwortet mit seinen verfuegbaren Tools, Resources und Prompts.
- Wenn das AI-Modell externe Daten oder Aktionen benoetigt, ruft der Client die entsprechende Server-Methode auf.
- Der Server fuehrt die Operation aus und gibt Ergebnisse ueber JSON-RPC 2.0-Nachrichten zurueck.
Tools vs Resources vs Prompts
MCP-Server koennen drei Arten von Faehigkeiten bereitstellen:
- Tools sind Funktionen, die das AI-Modell aufrufen kann. Sie akzeptieren strukturierte Eingaben und geben strukturierte Ausgaben zurueck. Beispiel:
query_database(sql: string)odersend_email(to: string, subject: string, body: string). - Resources sind Daten, die das AI-Modell lesen kann. Sie werden durch URIs identifiziert und geben Inhalte zurueck. Beispiel:
file:///path/to/document.mdoderpostgres://localhost/mydb/users. - Prompts sind wiederverwendbare Prompt-Vorlagen, die der Server bereitstellt. Sie helfen bei der Standardisierung der Interaktion der AI mit der Domaene des Servers. Beispiel: eine
summarize_ticket-Vorlage fuer einen Jira MCP Server.
Schritt fuer Schritt: MCP-Server in TypeScript erstellen
Lassen Sie uns einen praktischen MCP-Server erstellen, der ein Tool zum Abfragen einer SQLite-Datenbank bereitstellt. Dies ist ein haeufiger Anwendungsfall: einem AI-Modell sicheren, schreibgeschuetzten Zugriff auf Ihre Anwendungsdaten zu geben.
Schritt 1: Projekt initialisieren
mkdir mcp-sqlite-server && cd mcp-sqlite-server
npm init -y
npm install @modelcontextprotocol/sdk better-sqlite3
npm install -D typescript @types/node @types/better-sqlite3
npx tsc --init
tsconfig.json konfigurieren:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"declaration": true
},
"include": ["src/**/*"]
}
Schritt 2: Server implementieren
src/index.ts erstellen:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import Database from "better-sqlite3";
import { z } from "zod";
const db = new Database(process.env.DB_PATH || "./data.db", {
readonly: true,
});
const server = new McpServer({
name: "sqlite-query",
version: "1.0.0",
});
server.tool(
"query",
"Fuehrt eine schreibgeschuetzte SQL-Abfrage auf der SQLite-Datenbank aus",
{
sql: z.string().describe("Die auszufuehrende SQL SELECT-Abfrage"),
},
async ({ sql }) => {
const normalized = sql.trim().toUpperCase();
if (!normalized.startsWith("SELECT")) {
return {
content: [{ type: "text", text: "Fehler: Nur SELECT-Abfragen sind erlaubt." }],
isError: true,
};
}
try {
const rows = db.prepare(sql).all();
return {
content: [{ type: "text", text: JSON.stringify(rows, null, 2) }],
};
} catch (error) {
return {
content: [{ type: "text", text: `Abfragefehler: ${(error as Error).message}` }],
isError: true,
};
}
}
);
server.tool(
"list_tables",
"Listet alle Tabellen in der Datenbank mit ihren Schemas auf",
{},
async () => {
const tables = db
.prepare(
`SELECT name, sql FROM sqlite_master
WHERE type='table' AND name NOT LIKE 'sqlite_%'
ORDER BY name`
)
.all();
return {
content: [{ type: "text", text: JSON.stringify(tables, null, 2) }],
};
}
);
Schritt 3: Kompilieren und lokal testen
npx tsc
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | node dist/index.js
Sie sollten eine JSON-RPC-Antwort mit den Faehigkeiten des Servers sehen.
Schritt 4: Denselben Server in Python erstellen
Fuer Python-Entwickler zeigen wir hier die aequivalente Implementierung mit dem offiziellen MCP Python SDK:
import sqlite3
import json
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("sqlite-query")
DB_PATH = "data.db"
@mcp.tool()
def query(sql: str) -> str:
"""Fuehrt eine schreibgeschuetzte SQL-Abfrage auf der SQLite-Datenbank aus."""
normalized = sql.strip().upper()
if not normalized.startswith("SELECT"):
raise ValueError("Nur SELECT-Abfragen sind erlaubt.")
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
try:
cursor = conn.execute(sql)
rows = [dict(row) for row in cursor.fetchall()]
return json.dumps(rows, indent=2, default=str)
finally:
conn.close()
@mcp.tool()
def list_tables() -> str:
"""Listet alle Tabellen in der Datenbank mit ihren Schemas auf."""
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
try:
cursor = conn.execute(
"SELECT name, sql FROM sqlite_master "
"WHERE type='table' AND name NOT LIKE 'sqlite_%'"
)
tables = [dict(row) for row in cursor.fetchall()]
return json.dumps(tables, indent=2)
finally:
conn.close()
if __name__ == "__main__":
mcp.run(transport="stdio")
Verbindung mit Claude Desktop
Claude Desktop unterstuetzt MCP-Server nativ. Um Ihren Server zu verbinden, bearbeiten Sie die Claude Desktop-Konfigurationsdatei:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"sqlite-query": {
"command": "node",
"args": ["/absolute/path/to/dist/index.js"],
"env": {
"DB_PATH": "/absolute/path/to/your/data.db"
}
}
}
}
Starten Sie Claude Desktop neu. Sie sehen ein Hammer-Symbol in der Chat-Oberflaeche, das verfuegbare MCP-Tools anzeigt. Jetzt koennen Sie Claude Fragen stellen wie „Welche Tabellen gibt es in der Datenbank?“ oder „Zeige mir die 10 neuesten Benutzer nach Registrierungsdatum“ und Claude wird Ihren MCP-Server verwenden, um die Datenbank direkt abzufragen.
Verbindung mit Cursor
Cursor unterstuetzt ebenfalls MCP-Server. Fuegen Sie die Konfiguration in .cursor/mcp.json im Stammverzeichnis Ihres Projekts hinzu:
{
"mcpServers": {
"sqlite-query": {
"command": "node",
"args": ["./dist/index.js"],
"env": {
"DB_PATH": "./data.db"
}
}
}
}
Nach dem Speichern starten Sie Cursor neu. Die MCP-Tools erscheinen im AI-Assistenten-Panel und koennen waehrend der Codegenerierung und Debugging-Sitzungen aufgerufen werden.
Testen und Debuggen Ihres MCP-Servers
Verwendung des MCP Inspector
Der MCP Inspector ist das offizielle Debugging-Tool. Er bietet eine Web-Oberflaeche zur Interaktion mit Ihrem Server:
npx @modelcontextprotocol/inspector node dist/index.js
Dies oeffnet eine Browser-Oberflaeche unter http://localhost:5173, wo Sie:
- Alle registrierten Tools, Resources und Prompts anzeigen koennen
- Tools mit benutzerdefinierten Eingaben aufrufen und Antworten ueberpruefen koennen
- Den JSON-RPC-Nachrichtenstrom in Echtzeit ueberwachen koennen
- Die Fehlerbehandlung durch Senden fehlerhafter Anfragen testen koennen
Haeufige Debugging-Probleme
| Problem | Ursache | Loesung |
|---|---|---|
| Server erscheint nicht in Claude Desktop | Konfigurationspfad oder JSON-Syntaxfehler | JSON validieren, absolute Pfade ueberpruefen |
| Fehler „Tool not found“ | Tools nicht vor der Verbindung registriert | Tools vor dem Aufruf von server.connect() registrieren |
| Timeout bei Tool-Aufrufen | Langandauernde Operation ohne Fortschritt | Fortschrittsbenachrichtigungen ueber server.sendProgress() hinzufuegen |
| stderr-Ausgabe beschaedigt das Protokoll | console.log schreibt auf stdout (stdio-Transport) | console.error() fuer Logging bei stdio verwenden |
| Verbindungsabbruch nach Inaktivitaet | Transport-Timeout | Heartbeat implementieren oder HTTP-Transport verwenden |
Best Practices fuer die Produktion
-
Eingabevalidierung: Validieren und bereinigen Sie immer Tool-Eingaben. Verwenden Sie Zod-Schemas (TypeScript) oder Pydantic-Modelle (Python) fuer strenge Typueberpruefung.
-
Standardmaessig schreibgeschuetzt: Beginnen Sie mit schreibgeschuetztem Zugriff. Fuegen Sie Schreibfaehigkeiten nur hinzu, wenn sie wirklich benoetigt werden, und fordern Sie immer eine Bestaetigung fuer destruktive Operationen an.
-
Fehlerbehandlung: Geben Sie strukturierte Fehlermeldungen mit
isError: truezurueck. Legen Sie niemals interne Stack-Traces oder Datenbank-Verbindungsstrings offen. -
Protokollierung: Protokollieren Sie alle Tool-Aufrufe mit Zeitstempel, Eingaben und Ausfuehrungsdauer. Verwenden Sie stderr fuer die Protokollierung (nicht stdout) bei stdio-Transport.
-
Ratenbegrenzung: Implementieren Sie Tool-spezifische Ratenbegrenzungen, um zu verhindern, dass unkontrollierte AI-Schleifen Ihre Backend-Dienste ueberlasten.
-
Timeout: Setzen Sie Ausfuehrungs-Timeouts fuer alle Tool-Handler. AI-Modelle koennen Tools aufrufen, die teure Abfragen ausloesen — schuetzen Sie Ihre Infrastruktur.
-
Umgebungstrennung: Verwenden Sie Umgebungsvariablen fuer alle Konfigurationen. Codieren Sie niemals Datenbank-URLs, API-Schluessel oder Dateipfade fest ein.
-
Versionierung: Verwenden Sie semantische Versionierung fuer Ihren MCP-Server. Der
initialize-Handshake umfasst eine Versionsverhandlung — inkompatible Aenderungen erfordern einen Major-Versionsbump.
FAQ
F: Was ist der Unterschied zwischen MCP und Function Calling? A: Function Calling (verwendet von OpenAI, Anthropic und anderen) definiert Tools inline in jeder API-Anfrage. MCP externalisiert Tool-Definitionen auf eigenstaendige Server, die von MCP-kompatiblen Hosts entdeckt und genutzt werden. Function Calling ist pro Anfrage; MCP ist ein persistentes Protokoll mit Stateful Sessions.
F: Kann ich MCP mit anderen Modellen als Claude verwenden? A: Ja. MCP ist ein offenes Protokoll. OpenAI, Google DeepMind und Microsoft haben seit Anfang 2026 MCP-Unterstuetzung in ihre Plattformen integriert. Jede AI-Anwendung, die einen MCP Client implementiert, kann sich mit jedem MCP Server verbinden.
F: Ist MCP nur fuer lokale Tools? A: Nein. Obwohl der stdio-Transport fuer lokale Server konzipiert ist, unterstuetzen die HTTP+SSE- und Streamable-HTTP-Transporte entfernte MCP-Server. Sie koennen einen MCP-Server als netzwerkzugaenglichen Cloud-Dienst bereitstellen.
F: Wie handhabt MCP die Authentifizierung? A: Das Protokoll unterstuetzt OAuth 2.0 fuer entfernte Server. Lokale stdio-Server erben den Sicherheitskontext des Host-Prozesses. Fuer Enterprise-Deployments kann ein MCP-Gateway die Authentifizierung und Autorisierung zentralisieren.
F: Welche Sprachen koennen zum Erstellen eines MCP-Servers verwendet werden? A: Offizielle SDKs sind fuer TypeScript, Python, Java, Kotlin, C# und Swift verfuegbar. Community-SDKs umfassen Rust, Go, Ruby und PHP. Das Protokoll ist sprachunabhaengig — jede Sprache, die JSON-RPC ueber stdio oder HTTP lesen/schreiben kann, kann einen MCP-Server implementieren.
F: Wie aktualisiert man einen MCP-Server ohne den Host neu zu starten?
A: MCP unterstuetzt Faehigkeitsaenderungs-Benachrichtigungen. Wenn sich die Tools Ihres Servers aendern, kann der Server eine notifications/tools/list_changed-Nachricht senden, die den Client auffordert, die Tool-Liste erneut abzurufen. Bei stdio-Servern muss der Host normalerweise neu gestartet werden. HTTP-Server koennen ohne Host-Neustart aktualisiert werden.