Zielgruppe: Backend- und AI-Entwickler mit Python- oder TypeScript-Erfahrung, die Claude, Cursor oder VS Code an interne APIs, Datenbanken und Dateien anbinden wollen — ohne pro Modell einen eigenen Adapter zu schreiben. Ergebnis: Ein lauffaehiger MCP Server von der lokalen STDIO-Validierung bis HTTP+SSE-Produktion, inklusive Wissensdatenbank-Praxis. Aufbau: Protokoll-Kurzueberblick, sechs typische Fehlannahmen, drei Entscheidungstabellen, Code fuer Hello World / Tools / Resources / Prompts, Debugging, acht Rollout-Schritte, DSGVO-Checkliste und FAQ. Protokoll-Tiefe: MCP Deep Dive.
tools/list, JSON Schema und zustandsbehaftete Sitzungen.PATH in launchd/systemd anders ist als in der interaktiven Shell.Wenn mindestens zwei Punkte zutreffen, lohnt ein systematischer Aufbau statt «schnell npx -y». Dieser Leitfaden ersetzt nicht den Protokoll-Artikel, sondern liefert die Implementierungsschicht darunter.
Host (Cursor, Claude Desktop, VS Code) betreibt einen MCP Client. Der Client haelt eine 1:1-Sitzung mit jedem MCP Server und spricht JSON-RPC 2.0. Der Server exponiert drei Capability-Typen und kapselt externe Systeme.
| Capability | Rolle | Typische RPC-Methoden | Wenn/Dann |
|---|---|---|---|
| Tools | Aktionen mit Nebenwirkungen | tools/list, tools/call | Wenn SQL, Tickets oder Dateien geschrieben werden — dann idempotent designen und Schema dokumentieren |
| Resources | Lesbarer Kontext (URI) | resources/list, resources/read | Wenn das Modell Dokumente/Configs braucht — dann vor Tool-Call laden, Token-Budget beachten |
| Prompts | Wiederverwendbare Vorlagen | prompts/list, prompts/get | Wenn wiederkehrende Workflows (Onboarding, Code-Review) — dann Parameter im Schema fixieren |
| Transport | Latenz (lokal) | Skalierung | Empfehlung |
|---|---|---|---|
| STDIO | < 5 ms Cold Start (TS, gepinnt) | Ein Host-Prozess pro Server-Instanz | Entwicklung, Einzelplatz, CI-Smoke-Tests |
| HTTP + SSE | + RTT (typ. 20–80 ms EU) | Horizontal mit Session Affinity | Team-Sharing, Remote, getrennte Auth-Zone |
Voraussetzungen: Node.js 20 LTS oder Python 3.11+, Git, ein MCP-faehiger Host (Cursor 0.4x+ oder Claude Desktop). Auf macOS empfehlen wir dieselbe Minor-Version lokal und auf dem Ziel-Host — Environment-Drift ist die haeufigste Ursache fuer «Tool nicht registriert».
mkdir mcp-hello && cd mcp-hello npm init -y npm install @modelcontextprotocol/sdk zod # Alternativ Python: # python3 -m venv .venv && source .venv/bin/activate # pip install mcp
| SDK | Paket | Startbefehl | Stärke |
|---|---|---|---|
| TypeScript | @modelcontextprotocol/sdk | node dist/index.js | Cursor/Claude-Integration, schnelles STDIO |
| Python | mcp | python server.py | Daten-APIs, interne ML-Pipelines |
Der kleinste Server antwortet auf initialize und registriert ein Echo-Tool. Erwartetes Ergebnis: Host zeigt genau ein Tool «echo» in der Tool-Liste.
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: "hello-mcp", version: "1.0.0" });
server.tool(
"echo",
{ message: z.string().describe("Text zur Ausgabe") },
async ({ message }) => ({ content: [{ type: "text", text: message }] })
);
const transport = new StdioServerTransport();
await server.connect(transport);
// ~/.cursor/mcp.json (Beispiel)
{
"mcpServers": {
"hello-mcp": {
"command": "node",
"args": ["/abs/path/mcp-hello/dist/index.js"],
"env": {}
}
}
}
Validierung: Absoluter Pfad fuer command/args; relative Pfade brechen unter launchd. Nach Config-Aenderung Host neu starten und tools/list im Inspector pruefen.
Tools fuehren Nebenwirkungen aus. Jedes Tool braucht: eindeutigen Namen, Zod-/JSON-Schema, dokumentierte Seiteneffekte und Timeout-Budget. Beispiel: interne REST-API «Kundenstatus abfragen».
server.tool(
"get_customer_status",
{
customerId: z.string().uuid(),
includeOrders: z.boolean().default(false),
},
async ({ customerId, includeOrders }) => {
const res = await fetch(`${process.env.CRM_BASE}/customers/${customerId}`);
if (!res.ok) throw new Error(`CRM ${res.status}`);
const data = await res.json();
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
}
);
customerId in Logs landet, Verarbeitungsverzeichnis und Aufbewahrungsfrist definieren (DSGVO Art. 30).code und kurzer message — das Modell kann retry vs. escalate entscheiden.Resources liefern Lesedaten ohne garantierte Mutation. Nutzen Sie stabile URIs wie kb://article/{id} oder file:///policy/handbook.md.
server.resource(
"handbook",
"kb://policy/handbook",
async (uri) => ({
contents: [{
uri: uri.href,
mimeType: "text/markdown",
text: await fs.readFile("./data/handbook.md", "utf8"),
}],
})
);
Prompts sind parametrisierbare Vorlagen — nuetzlich fuer wiederkehrende Aufgaben (Incident-Triage, PR-Review). Sie reduzieren Token-Verschwendung gegenueber langen System-Prompts im Host.
server.prompt(
"incident_triage",
{
service: z.string(),
severity: z.enum(["P1", "P2", "P3"]),
},
({ service, severity }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Triage ${severity} fuer ${service}: Logs sammeln, Root Cause, naechste 3 Schritte.`,
},
}],
})
);
Wenn mehrere Entwickler denselben Server nutzen, wechseln Sie von STDIO auf HTTP+SSE. Planen Sie TLS, Reverse Proxy und Session Affinity — SSE ist zustandsbehaftet, nicht wie stateless REST.
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
const app = express();
app.get("/sse", async (req, res) => {
const transport = new SSEServerTransport("/message", res);
await server.connect(transport);
});
app.post("/message", express.json(), async (req, res) => {
await transport.handlePostMessage(req, res);
});
app.listen(8787, "0.0.0.0");
| HTTP-Checkpunkt | Parameter | Produktionswert |
|---|---|---|
| TLS | Terminierung | Am Reverse Proxy (nginx/Caddy), HSTS aktiv |
| Timeout | Erster Cold Call | 30–60 s; danach 10–15 s steady state |
| Auth | Bearer / OAuth 2.1 | Am Server-Entry, nicht im Client-JSON verstreut |
| Affinity | Load Balancer | Sticky Session oder ein Pod pro Client-Session |
Symptom-Matrix fuer strukturierte Triage:
| Symptom | Erste Evidenz | Wahrscheinliche Ursache | Massnahme |
|---|---|---|---|
| Leere Tool-Liste | Child-Exit-Code, stderr | Falscher cwd, fehlende Binary | Absoluter Pfad; gleicher OS-User wie Host |
| Erster Call langsam | npm/pip Fetch-Logs | npx -y JIT | Version pinnen; Image prewarmen |
| Schema rejected | JSON-RPC -32602 | Zod/JSON-Schema-Mismatch | tools/list-Output mit Client vergleichen |
| Steady Timeout | CPU, offene FDs | Blockierendes IO | Read-only Tool als A/B-Referenz |
# MCP Inspector (Community-Tool) npx @modelcontextprotocol/inspector node dist/index.js # Erwartung: initialize OK, tools/list >= 1 Eintrag, tools/call echo OK
Restart=on-failure und explizitem EnvironmentFile.mcp.json committen.tools/call mit correlation_id; Metriken: p95-Latenz, Fehlerrate, aktive SSE-Sessions.| Pruefpunkt | Artikel | MCP-Bezug |
|---|---|---|
| Verarbeitungsverzeichnis | Art. 30 | tools/call-Parameter, Logs, CRM-Responses |
| AV-Vertrag | Art. 28 | Getrennt: Cloud-Host (MACCOME) vs. LLM-API vs. eigener Server |
| TOMs | Art. 32 | TLS, OAuth zentral, Pseudonymisierung in Tool-Outputs |
| Speicherort | Datenresidenz | EU-Region dokumentieren — nicht US-Laptop als Prod-Host |
| Loeschung | Art. 17 | Session-Logs und Caches wipe-faehig bei Mandatsende |
Kombinieren Sie Resources (Markdown-Artikel) mit einem Tool «semantic_search» (Vektor-DB oder einfaches BM25). Ablauf: Modell liest Resource-Metadaten via resources/list, ruft semantic_search auf, zitiert URIs — reduziert Halluzinationen in Support- und Compliance-Workflows.
server.tool(
"semantic_search",
{ query: z.string().min(3), topK: z.number().int().min(1).max(10).default(5) },
async ({ query, topK }) => {
const hits = await index.search(query, topK);
return {
content: [{
type: "text",
text: hits.map(h => `${h.uri} (score ${h.score})\n${h.snippet}`).join("\n---\n"),
}],
};
}
);
tools/list im Inspector gruen.env-Datei.npx -y-Call ohne Pinning.Ein MCP Server auf dem Entwicklungs-Mac ist der richtige Start — aber drei Grenzen zeigen sich schnell: STDIO/SSE bricht beim Zuklappen, PATH und Secrets divergieren zwischen Team-Mitgliedern, und mehrschrittige Agent-Workflows brauchen stabile Uptime. Self-hosted VMs ohne dedizierte macOS-Umgebung kaempfen zudem mit Xcode-Toolchain-Luecken, wenn Ihr Server native Apple-APIs oder Simulator-Hooks braucht.
Fuer Teams, die MCP Server und Agent-Orchestrierung dauerhaft betreiben, ist ein dedizierter MACCOME Mac mini (M4 / M4 Pro) als 7×24-Knoten oft guenstiger als lokaler Sleep-Kampf — mit dokumentierter EU-Region fuer DSGVO-Anforderungen. Tarife: Mac-Mini-Mietpreise; Onboarding: Hilfe-Center.
Haeufige Fragen
Python oder TypeScript fuer den ersten MCP Server?
TypeScript mit @modelcontextprotocol/sdk fuer schnelle Cursor-Integration; Python mit mcp bei Daten-Pipelines. Entscheidung nach Team-Stack — beide sind produktionsfaehig.
Brauche ich HTTP+SSE oder reicht STDIO?
STDIO fuer Solo-Entwicklung. HTTP+SSE ab Team-Sharing oder Remote — dann TLS, Session Affinity und zentrale Auth planen.
Wie haengt MCP mit Agent Skills zusammen?
Skills sind Host-interne Prompt-Pakete; MCP ist das offene Tool-Protokoll. Details im Agent Skill Guide.
Welcher Host fuer Produktions-MCP?
Vermeiden Sie Laptop-Sleep fuer Long-Lived-Sessions. MACCOME bietet dedizierte M4/M4 Pro-Knoten mit 7×24-Betrieb. Mietpreise und Hilfe-Center.