Eigenen MCP-Server auf einem VPS bauen und selbst hosten
Bauen Sie einen TypeScript MCP-Server von Grund auf, stellen Sie ihn auf einem VPS mit systemd bereit und betreiben Sie ihn hinter Nginx mit TLS. Verbinden Sie Claude Desktop, Claude Code und Cursor mit Ihrem selbst gehosteten Server.
Jedes MCP-Server-Tutorial hört bei "lokal mit stdio ausführen" auf. Dieses hier deckt den gesamten Weg ab: einen TypeScript MCP-Server bauen, auf einem VPS hinter Nginx mit TLS bereitstellen, mit Authentifizierung und Firewall-Regeln absichern und MCP-Clients über das Internet verbinden.
Was werden Sie bauen?
MCP-Clients senden JSON-RPC-Anfragen über HTTPS. Nginx terminiert TLS und leitet Anfragen an Ihren MCP-Server-Prozess weiter, der auf einem lokalen Port läuft. Der MCP-Server validiert ein Bearer-Token, verarbeitet die Anfrage und gibt Ergebnisse zurück.
MCP Client (Claude, Cursor, ...)
|
| HTTPS (port 443)
v
Nginx (TLS termination + reverse proxy)
|
| HTTP (port 3000, localhost only)
v
MCP Server (Node.js + Express)
|
v
SQLite database
Das Arbeitsbeispiel ist ein Notizen-Server. Er stellt zwei Tools (Notizen suchen, Notiz erstellen) und eine Resource (alle Notizen auflisten) bereit. Einfach genug zum Nachvollziehen, nuetzlich genug zum Erweitern.
Welchen Transport sollten Sie für einen Remote-MCP-Server verwenden?
Streamable HTTP ist der aktuelle MCP-Spezifikationsstandard für Remote-Deployments. Er hat den veralteten SSE-Transport ersetzt und funktioniert über normale HTTP-POST-Anfragen. Stdio bleibt der Transport für rein lokale Server, bei denen der Client den Server als Subprozess startet.
| Transport | Anwendungsfall | Remote-fähig | Client-Unterstützung |
|---|---|---|---|
| stdio | Lokale Tools, CLI-Integrationen | Nein | Alle Clients |
| SSE (veraltet) | Ältere Remote-Server | Ja | Die meisten Clients (wird ausgemustert) |
| Streamable HTTP | Remote-Server, Produktion | Ja | Claude Desktop, Claude Code, Cursor |
Streamable HTTP sendet jede Client-Nachricht als HTTP POST an einen einzelnen Endpunkt (z.B. /mcp). Der Server antwortet mit application/json für einfache Antworten oder text/event-stream, wenn er mehrere Nachrichten zurückstreamen muss. Das funktioniert mit Standard-HTTP-Infrastruktur, einschließlich Reverse Proxies und Load Balancern.
Voraussetzungen
- Ein VPS mit Debian 12 oder Ubuntu 24.04 (diese Anleitung verwendet Debian 12)
- Ein Domainname mit DNS, der auf Ihren VPS zeigt (z.B.
mcp.example.com) - Node.js 20+ auf dem VPS installiert
- Grundkenntnisse in TypeScript und Linux
KI-Agenten auf einem VPS selbst hosten
Wie richten Sie ein TypeScript-MCP-Server-Projekt ein?
Beginnen Sie auf Ihrem lokalen Rechner oder direkt auf dem VPS. Initialisieren Sie das Projekt, installieren Sie das MCP SDK und richten Sie TypeScript ein.
mkdir mcp-notes-server && cd mcp-notes-server
npm init -y
npm install @modelcontextprotocol/sdk zod express better-sqlite3
npm install -D typescript @types/node @types/express @types/better-sqlite3
Erstellen Sie die TypeScript-Konfiguration:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
Aktualisieren Sie package.json, um die Build- und Start-Skripte hinzuzufügen und den Modultyp festzulegen:
{
"type": "module",
"scripts": {
"build": "tsc",
"start": "node build/index.js"
}
}
Erstellen Sie das Quellverzeichnis:
mkdir src
Wie implementieren Sie MCP-Tools mit Eingabevalidierung?
Ein MCP-Server stellt Tools, Resources und Prompts für KI-Clients bereit. Tools sind Funktionen, die die KI aufrufen kann. Resources sind schreibgeschützte Daten, auf die die KI zugreifen kann. Wir implementieren beides.
Erstellen Sie src/index.ts mit dem Datenbank-Setup und einer Factory-Funktion, die für jede Anfrage einen neuen MCP-Server erstellt. Zustandsloses Streamable HTTP erfordert eine neue McpServer-Instanz pro Anfrage, da das SDK es nicht erlaubt, denselben Server mit einem anderen Transport erneut zu verbinden.
import express from "express";
import { randomUUID } from "crypto";
import Database from "better-sqlite3";
import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
// --- Database setup ---
const db = new Database("notes.db");
db.pragma("journal_mode = WAL");
db.exec(`
CREATE TABLE IF NOT EXISTS notes (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
)
`);
// --- MCP Server factory ---
// Each stateless request needs its own McpServer + transport pair.
// The SDK binds a server to a single transport on connect() and
// throws if you try to reuse it. A factory function keeps it clean.
function createServer(): McpServer {
const server = new McpServer({
name: "notes-server",
version: "1.0.0",
});
Registrieren Sie nun die Tools innerhalb der Factory. Jedes Tool verwendet Zod für die Eingabevalidierung. Das SDK validiert Eingaben automatisch, bevor Ihr Handler ausgeführt wird.
// --- Tools ---
server.tool(
"search_notes",
"Search notes by keyword in title or content",
{
query: z.string().min(1).describe("Search keyword"),
},
async ({ query }) => {
const stmt = db.prepare(
"SELECT id, title, content, created_at FROM notes WHERE title LIKE ? OR content LIKE ? ORDER BY created_at DESC LIMIT 20"
);
const rows = stmt.all(`%${query}%`, `%${query}%`);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(rows, null, 2),
},
],
};
}
);
server.tool(
"create_note",
"Create a new note with a title and content",
{
title: z.string().min(1).max(200).describe("Note title"),
content: z.string().min(1).describe("Note content"),
},
async ({ title, content }) => {
const id = randomUUID();
const stmt = db.prepare(
"INSERT INTO notes (id, title, content) VALUES (?, ?, ?)"
);
stmt.run(id, title, content);
return {
content: [
{
type: "text" as const,
text: `Note created with id: ${id}`,
},
],
};
}
);
Wie fügen Sie Resources zu einem MCP-Server hinzu?
Resources geben KI-Clients schreibgeschützten Zugriff auf Daten. Sie werden über URI referenziert. Fügen Sie eine Resource hinzu, die alle Notizen auflistet, weiterhin innerhalb der createServer-Factory:
// --- Resources ---
server.resource(
"all-notes",
"notes://all",
{
description: "List all notes in the database",
mimeType: "application/json",
},
async (uri) => {
const rows = db.prepare(
"SELECT id, title, created_at FROM notes ORDER BY created_at DESC LIMIT 100"
).all();
return {
contents: [
{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(rows, null, 2),
},
],
};
}
);
return server;
}
MCP-Clients können diese Resource entdecken und lesen, ohne ein Tool aufzurufen. Claude Desktop zeigt Resources im Anhänge-Menue an. Claude Code stellt sie über @-Erwähnungen bereit.
Wie sichern Sie einen MCP-Server mit Token-Authentifizierung ab?
Ein produktiver MCP-Server braucht Authentifizierung. Ohne sie kann jeder, der Ihren Endpunkt entdeckt, Ihre Tools aufrufen. Verwenden Sie ein Bearer-Token, das in einer Express-Middleware geprüft wird, bevor Anfragen den MCP-Transport erreichen.
Generieren Sie ein starkes Token:
openssl rand -base64 32
Speichern Sie die Ausgabe. Sie benötigen sie sowohl für die Server- als auch für die Client-Konfiguration.
Fügen Sie die Authentifizierungs-Middleware und Express-Routen zu src/index.ts hinzu:
// --- Auth middleware ---
const AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
if (!AUTH_TOKEN) {
console.error("MCP_AUTH_TOKEN environment variable is required");
process.exit(1);
}
function authenticateRequest(
req: express.Request,
res: express.Response,
next: express.NextFunction
): void {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith("Bearer ")) {
res.status(401).json({
jsonrpc: "2.0",
error: { code: -32001, message: "Missing or invalid authorization" },
id: null,
});
return;
}
const token = authHeader.slice(7);
if (token !== AUTH_TOKEN) {
res.status(403).json({
jsonrpc: "2.0",
error: { code: -32001, message: "Invalid token" },
id: null,
});
return;
}
next();
}
// --- Express app ---
const app = express();
app.use(express.json());
app.use("/mcp", authenticateRequest);
Die Middleware wird vor jeder Anfrage an /mcp ausgeführt. Sie prüft auf ein Bearer-Token im Authorization-Header und lehnt unautorisierte Anfragen mit einer JSON-RPC-Fehlerantwort ab.
Wie richten Sie den Streamable-HTTP-Transport ein?
Fügen Sie das Transport-Setup und die Route-Handler hinzu. Jede Anfrage erstellt einen neuen McpServer aus der Factory und eine neue Transport-Instanz:
// --- Streamable HTTP transport ---
app.post("/mcp", async (req, res) => {
const server = createServer();
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
await server.connect(transport);
try {
await transport.handleRequest(req, res, req.body);
} catch (error) {
console.error("MCP request error:", error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: "2.0",
error: { code: -32603, message: "Internal server error" },
id: null,
});
}
}
});
app.get("/mcp", (_req, res) => {
res.status(405).json({
jsonrpc: "2.0",
error: { code: -32000, message: "Method not allowed. Use POST." },
id: null,
});
});
app.delete("/mcp", (_req, res) => {
res.status(405).json({
jsonrpc: "2.0",
error: { code: -32000, message: "Method not allowed." },
id: null,
});
});
// --- Health check ---
app.get("/health", (_req, res) => {
res.json({ status: "ok" });
});
// --- Start ---
const PORT = parseInt(process.env.PORT || "3000", 10);
app.listen(PORT, "127.0.0.1", () => {
console.log(`MCP server listening on http://127.0.0.1:${PORT}/mcp`);
});
sessionIdGenerator: undefined erstellt einen zustandslosen Server. Jede Anfrage ist unabhängig, mit eigenem McpServer und Transport-Paar. Das ist einfacher zu deployen und funktioniert gut hinter einem Reverse Proxy ohne Sticky Sessions. Die Datenbankverbindung (db) lebt auf Modulebene und wird anfageübergreifend geteilt, sodass Daten zwischen Aufrufen bestehen bleiben.
Der Server bindet an 127.0.0.1, nicht an 0.0.0.0. Er akzeptiert nur Verbindungen von localhost. Nginx ist der einzige Weg, ihn von aussen zu erreichen.
Bauen und lokal testen:
npm run build
Prüfen Sie, ob der Build ohne Fehler durchläuft.
Wie testen Sie einen MCP-Server lokal?
Der MCP Inspector ist das offizielle Test-Tool. Er verbindet sich mit Ihrem Server und lässt Sie Tools interaktiv aufrufen.
Starten Sie Ihren Server in einem Terminal:
MCP_AUTH_TOKEN=test-token-local npm start
In einem anderen Terminal mit curl testen:
curl -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer test-token-local" \
-d '{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "test-client", "version": "1.0.0" }
},
"id": 1
}'
Sie sollten eine SSE-Antwort sehen (event: message gefolgt von einer data:-Zeile), die die Fähigkeiten des Servers enthält, einschließlich der tools- und resources-Objekte. Das bestätigt, dass der Server Verbindungen annimmt und auf den MCP-Initialisierungs-Handshake antwortet.
Testen Sie das create_note-Tool:
curl -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer test-token-local" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "create_note",
"arguments": { "title": "Test Note", "content": "Hello from curl" }
},
"id": 2
}'
Die Antwort sollte "Note created with id: ..." enthalten. Testen Sie nun das Such-Tool:
curl -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer test-token-local" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "search_notes",
"arguments": { "query": "Test" }
},
"id": 3
}'
Sie sollten die gerade erstellte Notiz in den Ergebnissen sehen. Prüfen Sie, ob eine Anfrage ohne Authorization-Header einen 401-Fehler zurückgibt:
curl -s -o /dev/null -w "%{http_code}" -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
Das sollte 401 ausgeben. Wenn ja, funktioniert Ihre Auth-Middleware.
Sie können auch den MCP Inspector für interaktives Testen mit Web-UI verwenden:
npx @modelcontextprotocol/inspector
Der Inspector öffnet eine Browser-Oberfläche, in der Sie sich mit Ihrem Server verbinden, Tools und Resources durchsuchen und Aufrufe testen können.
Wie stellen Sie einen MCP-Server auf einem VPS bereit?
Übertragen Sie Ihr Projekt mit rsync, scp oder pushen Sie es in ein Git-Repository und klonen Sie es auf dem Server. Die folgenden Schritte setzen voraus, dass Sie auf dem VPS eingeloggt sind.
Dedizierten Benutzer erstellen
Führen Sie Anwendungsprozesse nie als root aus. Erstellen Sie einen Dienstbenutzer:
sudo useradd -r -m -s /usr/sbin/nologin mcpserver
Node.js installieren
Falls Node.js 20+ noch nicht installiert ist:
curl -fsSL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt-get install -y nodejs
node --version
npm --version
Der erste Befehl lädt das Setup-Skript in eine Datei herunter, damit Sie es vor der Ausführung prüfen können. Die Ausgabe sollte v20.x.x oder höher für Node.js und 10.x.x für npm anzeigen. Das MCP SDK benötigt Node.js 18+, aber 20 LTS wird für den Produktionseinsatz empfohlen.
Projektverzeichnis einrichten
sudo mkdir -p /opt/mcp-notes-server
sudo cp -r /path/to/your/project/* /opt/mcp-notes-server/
cd /opt/mcp-notes-server
sudo npm ci --omit=dev
sudo npm run build
sudo chown -R mcpserver:mcpserver /opt/mcp-notes-server
Eigentuemer prüfen:
ls -la /opt/mcp-notes-server/
Alle Dateien sollten mcpserver:mcpserver gehören.
Umgebungsdatei erstellen
Speichern Sie das Auth-Token in einer geschützten Umgebungsdatei:
sudo mkdir -p /etc/mcp-notes-server
echo "MCP_AUTH_TOKEN=$(openssl rand -base64 32)" | sudo tee /etc/mcp-notes-server/env > /dev/null
sudo chmod 600 /etc/mcp-notes-server/env
sudo chown mcpserver:mcpserver /etc/mcp-notes-server/env
Lesen Sie das generierte Token aus und speichern Sie es sicher. Sie benötigen es für die Client-Konfiguration:
sudo cat /etc/mcp-notes-server/env
systemd-Service erstellen
sudo tee /etc/systemd/system/mcp-notes-server.service > /dev/null << 'EOF'
[Unit]
Description=MCP Notes Server
After=network.target
[Service]
Type=simple
User=mcpserver
Group=mcpserver
WorkingDirectory=/opt/mcp-notes-server
EnvironmentFile=/etc/mcp-notes-server/env
ExecStart=/usr/bin/node build/index.js
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/mcp-notes-server
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
EnvironmentFile lädt MCP_AUTH_TOKEN aus der geschützten Datei. Der Hardening-Abschnitt begrenzt, was der Prozess tun kann. NoNewPrivileges verhindert Rechteeskalation. ProtectSystem=strict macht das Dateisystem schreibgeschützt, ausser für Pfade in ReadWritePaths. ProtectHome blockiert den Zugriff auf Home-Verzeichnisse.
Aktivieren und starten Sie den Service:
sudo systemctl enable --now mcp-notes-server
enable sorgt dafür, dass der Service beim Booten startet. --now startet ihn sofort.
Status prüfen:
sudo systemctl status mcp-notes-server
Sie sollten active (running) sehen. Falls der Service fehlgeschlagen ist, prüfen Sie die Logs:
journalctl -u mcp-notes-server -n 50 --no-pager
Prüfen Sie, ob der Server lokal antwortet:
TOKEN=$(sudo grep MCP_AUTH_TOKEN /etc/mcp-notes-server/env | cut -d= -f2)
curl -s http://127.0.0.1:3000/health
Das sollte {"status":"ok"} zurückgeben.
Wie betreiben Sie einen MCP-Server hinter Nginx mit TLS?
Nginx terminiert TLS und leitet Anfragen an den MCP-Server weiter. Der MCP-Server behandelt TLS nie direkt. Das ist das Standardmuster für produktive Node.js-Deployments.
Nginx als Reverse Proxy konfigurieren
Nginx und Certbot installieren
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx
Nginx-Serverblock konfigurieren
sudo tee /etc/nginx/sites-available/mcp.example.com.conf > /dev/null << 'NGINX'
server {
listen 80;
listen [::]:80;
server_name mcp.example.com;
# Certbot will add the redirect to HTTPS
location / {
return 444;
}
}
NGINX
Ersetzen Sie mcp.example.com durch Ihre tatsächliche Domain.
Aktivieren Sie die Seite und holen Sie ein TLS-Zertifikat:
sudo ln -s /etc/nginx/sites-available/mcp.example.com.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d mcp.example.com
Certbot ändert die Konfiguration, um TLS-Einstellungen und eine HTTP-zu-HTTPS-Weiterleitung hinzuzufügen. Aktualisieren Sie nun die Konfiguration für den Reverse Proxy zum MCP-Endpunkt:
sudo tee /etc/nginx/sites-available/mcp.example.com.conf > /dev/null << 'NGINX'
server {
listen 80;
listen [::]:80;
server_name mcp.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mcp.example.com;
ssl_certificate /etc/letsencrypt/live/mcp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Hide Nginx version
server_tokens off;
# MCP endpoint
location /mcp {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Required for Streamable HTTP / SSE responses
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding off;
# Keep connection open for streaming responses
proxy_set_header Connection "";
# Extended timeouts for long-running tool calls
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# Forward client info
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Pass through Authorization header
proxy_set_header Authorization $http_authorization;
}
# Health check (no auth required)
location /health {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
# Block everything else
location / {
return 444;
}
}
NGINX
Die wichtigen Direktiven für MCP-Kompatibilität:
proxy_buffering offverhindert, dass Nginx SSE-Antworten puffert. Ohne diese Einstellung hängen Streaming-Antworten, bis die Verbindung geschlossen wird.proxy_cache offstellt sicher, dass dynamische Antworten nicht gecacht werden.chunked_transfer_encoding offvermeidet Chunking-Probleme bei SSE-Event-Streams.Connection ""hält die Verbindung offen, ohne WebSocket-Upgrade-Verhalten auszulösen.proxy_read_timeout 300serlaubt Tool-Aufrufe, die bis zu 5 Minuten dauern. Die Standard-60s sind für aufwendige Operationen zu kurz.
Let's Encrypt SSL/TLS für Nginx einrichten auf Debian 12 und Ubuntu 24.04
Testen und neu laden:
sudo nginx -t
sudo systemctl reload nginx
Von Ihrem lokalen Rechner (nicht dem Server) prüfen:
curl -s https://mcp.example.com/health
Das sollte {"status":"ok"} zurückgeben. Wenn ja, leitet Nginx korrekt an Ihren MCP-Server über TLS weiter.
Firewall-Regeln
Blockieren Sie direkten Zugriff auf Port 3000 von aussen. Nur Nginx (auf localhost) sollte den MCP-Server erreichen:
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Prüfen Sie, ob Port 3000 von aussen nicht erreichbar ist:
# Von Ihrem lokalen Rechner, das sollte einen Timeout ergeben oder abgelehnt werden:
curl -s --connect-timeout 5 http://YOUR_VPS_IP:3000/health
Die Verbindung sollte fehlschlagen. Ihr MCP-Server ist nur über Nginx auf Port 443 erreichbar.
KI-Agent-Server absichern: Sandboxing, Firewall und Monitoring
Wie verbinden Sie MCP-Clients mit einem Remote-Server?
Nachdem der Server hinter Nginx mit TLS läuft, konfigurieren Sie Ihre MCP-Clients für die Verbindung.
Claude Code
Fügen Sie den Remote-Server über die CLI hinzu:
claude mcp add --transport http \
--header "Authorization: Bearer YOUR_TOKEN_HERE" \
notes-server https://mcp.example.com/mcp
Ersetzen Sie YOUR_TOKEN_HERE durch das Token aus /etc/mcp-notes-server/env.
Verbindung prüfen:
claude mcp list
In Claude Code tippen Sie /mcp, um den Serverstatus zu prüfen. Der notes-server sollte als verbunden angezeigt werden, mit den Tools search_notes und create_note.
Claude Code auf einem VPS betreiben: Installation, Absicherung und persistente Sitzungen
Claude Desktop
Claude Desktop verbindet sich über die Einstellungs-UI mit Remote-MCP-Servern. Gehen Sie zu Settings > Connectors und fügen Sie einen neuen Remote-Server mit der URL https://mcp.example.com/mcp hinzu.
Wenn Sie das Bearer-Token übergeben müssen, können Sie es auch über eine lokale .mcp.json-Datei oder den oben gezeigten claude mcp add-CLI-Befehl konfigurieren und den Server in Claude Desktop importieren:
claude mcp add-from-claude-desktop
Cursor
Öffnen Sie die Cursor-Einstellungen und navigieren Sie zur MCP-Konfiguration. Fügen Sie einen neuen Server in der mcp.json-Datei hinzu (oder über die Cursor-Einstellungs-UI):
{
"mcpServers": {
"notes-server": {
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN_HERE"
}
}
}
}
Cursor versucht bei einer URL-Verbindung zuerst Streamable HTTP, daher ist keine zusätzliche Transport-Konfiguration nötig.
End-to-End-Verbindung prüfen
Bitten Sie die KI von jedem verbundenen Client aus:
- Eine Notiz erstellen: "Create a note titled 'Server Test' with content 'Connected successfully'"
- Danach suchen: "Search my notes for 'Server Test'"
Wenn beide Operationen Ergebnisse liefern, funktioniert die gesamte Kette: Client zu Nginx zu MCP-Server zu SQLite und zurück.
MCP-Primitives-Referenz
| Primitive | Zweck | Beispiel |
|---|---|---|
| Tools | Funktionen, die die KI mit strukturierten Eingaben aufrufen kann | search_notes, create_note |
| Resources | Schreibgeschützte Daten, auf die die KI zugreifen kann | notes://all Notizliste |
| Prompts | Vorgefertigte Templates für häufige Aufgaben | In diesem Tutorial nicht verwendet |
Tools sind das am häufigsten implementierte Primitive. Resources eignen sich, um Referenzdaten ohne Berechnung bereitzustellen. Prompts erstellen wiederverwendbare Templates, die die KI durch bestimmte Workflows führen.
KI-Agent-Protokolle erklärt: MCP, A2A und ANP
Etwas funktioniert nicht?
Server startet nicht: Prüfen Sie das Journal auf Fehler:
journalctl -u mcp-notes-server -n 50 --no-pager
Häufige Ursachen: fehlende Umgebungsvariable MCP_AUTH_TOKEN, falsche Dateiberechtigungen auf notes.db, zu alte Node.js-Version.
Nginx gibt 502 Bad Gateway zurück: Der MCP-Server läuft nicht oder hört nicht auf Port 3000. Prüfen Sie:
sudo systemctl status mcp-notes-server
curl -s http://127.0.0.1:3000/health
Client bekommt 401 Unauthorized: Das Token in der Client-Konfiguration stimmt nicht mit dem Token auf dem Server überein. Prüfen Sie:
sudo cat /etc/mcp-notes-server/env
Streaming-Antworten laufen in einen Timeout: Erhöhen Sie proxy_read_timeout in der Nginx-Konfiguration. Die Standard-300s reichen für die meisten Fälle, aber lang laufende Tools brauchen möglicherweise mehr.
Zertifikatsfehler: Prüfen Sie, ob das Zertifikat gültig ist und Ihre Domain abdeckt:
sudo certbot certificates
Falls das Zertifikat abgelaufen ist, erneuern Sie es:
sudo certbot renew
Database-locked-Fehler: SQLite im WAL-Modus verarbeitet gleichzeitige Lesezugriffe gut, aber gleichzeitige Schreibzugriffe können kollidieren. Für Server mit hohem Verkehrsaufkommen sollten Sie PostgreSQL in Betracht ziehen.
Permission denied bei notes.db: Der Benutzer mcpserver braucht Schreibzugriff auf das Arbeitsverzeichnis für SQLite. Prüfen Sie:
ls -la /opt/mcp-notes-server/notes.db
Die Datei sollte mcpserver:mcpserver gehören. Falls sie beim Testen von root erstellt wurde, korrigieren Sie das:
sudo chown mcpserver:mcpserver /opt/mcp-notes-server/notes.db
sudo chmod 640 /opt/mcp-notes-server/notes.db
Client zeigt "connection refused" oder "timeout": Prüfen Sie, ob Ihr DNS-A-Record auf die VPS-IP zeigt und die Ports 80 und 443 in der Firewall geöffnet sind:
sudo ufw status
dig +short mcp.example.com
Die dig-Ausgabe sollte Ihre VPS-IP-Adresse anzeigen. Falls nicht, aktualisieren Sie Ihre DNS-Einträge und warten Sie auf die Propagierung.
Nächste Schritte
Ihr MCP-Server ist live und abgesichert. Mögliche Erweiterungen:
- Weitere Tools hinzufügen, die sich mit Ihren Datenbanken, APIs oder Dateisystemen verbinden
- OAuth 2.1 statt Bearer-Tokens für Mehrbenutzerzugriff implementieren
- Rate Limiting in Express oder Nginx zum Schutz vor Missbrauch einrichten
- Monitoring mit
journalctl -u mcp-notes-server -fund Alerting aufsetzen - Mehrere MCP-Server hinter derselben Nginx-Instanz auf verschiedenen Pfaden bereitstellen
Die offizielle MCP-SDK-Dokumentation behandelt fortgeschrittene Muster wie zustandsbehaftete Sitzungen, Fortschrittsberichte und strukturierte Ausgabe-Schemas.
Bereit, es selbst auszuprobieren?
KI-Tools auf Ihrem eigenen VPS erstellen und bereitstellen. →