MCP-Server auf VPS für KI-Coding-Agenten betreiben
Betreiben Sie MCP-Server auf dem eigenen VPS: stdio und HTTP, systemd, Nginx mit TLS, Authentifizierung sowie typische JSON-RPC- und Netzwerkfehler.
Was Sie aufbauen
Zwei funktionierende MCP-Setups auf einem VPS. Zuerst einen stdio-Server, also ein Datei- oder Datenbank-Tool, das Claude Code als untergeordneten Prozess startet und über eine Pipe mit ihm kommuniziert. Anschließend einen remote HTTP-Server, der als dauerhaft laufender Netzwerkdienst hinter systemd und einem Nginx-Reverse-Proxy mit TLS ausgeführt wird. Er ist für jeden MCP-Client erreichbar, den Sie darauf konfigurieren. Die Installation ist in beiden Fällen kurz. Der größte Teil dieses Leitfadens behandelt die zwei Punkte, die in der Praxis Probleme verursachen: Der JSON-RPC-Datenstrom muss sauber bleiben, und ein nicht authentifizierter Tool-Endpunkt darf niemals öffentlich im Internet erreichbar sein.
Was MCP tatsächlich ist
Das Model Context Protocol ist ein Standard, über den ein KI-Client wie Claude Code, Claude Desktop, die Gemini CLI auf einem VPS oder Ihr eigenes Skript externe Tools aufrufen und externe Ressourcen lesen kann. Das Modell selbst führt nichts aus. Es stellt eine Anfrage an den Client. Der Client spricht über JSON-RPC 2.0 mit einem MCP-Server. Der Server führt das Tool aus und gibt das Ergebnis zurück. Dieser Client ist mit dem Begriff Agent-Harness gemeint: die Schleife um das Modell, die die Tool-Liste, die Berechtigungsprüfungen und den Sitzungsstatus verwaltet. MCP erweitert dabei lediglich den Tool-Teil. Ein Protokoll genügt. Ein von Ihnen einmal geschriebener Server funktioniert dadurch mit jedem Client, der MCP unterstützt. Wenn diese Trennung für Sie neu ist und Sie insbesondere wissen möchten, wie ein Modell überhaupt entscheidet, ein Tool aufzurufen, lohnt sich ein schrittweiser Einstieg in die Grundlagen von Agenten eine Stunde, bevor Sie einem dieser Server echte Zugangsdaten geben.
Es gibt zwei Transportarten. Der restliche Teil dieses Leitfadens ist entsprechend aufgeteilt:
- stdio. Der Client startet den Server als untergeordneten Prozess und tauscht zeilengetrennte JSON-RPC-Nachrichten über dessen Standardeingabe und Standardausgabe aus. Es gibt kein Netzwerk, keinen Port und keine Authentifizierung. Die Vertrauensgrenze ist der Prozess selbst. Fast jedes lokale Tool wird auf diese Weise ausgeliefert.
- Streamable HTTP (und der ältere Verwandte HTTP+SSE). Der Server ist ein dauerhaft laufender Webdienst. Der Client verbindet sich über HTTP. Der Server kann Antworten als Server-Sent Events zurückstreamen. So können Sie einen Server mit mehreren Clients gemeinsam verwenden oder ein Tool betreiben, das dauerhaft auf dem System laufen muss.
Verwenden Sie stdio, wenn das Tool zu einem einzelnen System und einem einzelnen Benutzer gehört. Verwenden Sie HTTP, wenn es sich um einen gemeinsam genutzten Dienst handelt.
Voraussetzungen und die tatsächlichen Stolpersteine
Gehen Sie von einem frischen Ubuntu-24.04-KVM-VPS mit root- oder sudo-Zugriff aus. Darüber hinaus benötigen Sie:
- Eine Laufzeitumgebung, in der der Server geschrieben ist. Die meisten Referenzserver verwenden Node oder Python. Ubuntu 24.04 enthält Node 18, mehrere aktuelle MCP-Pakete erfordern jedoch Node 20 oder neuer. Installieren Sie daher eine aktuelle LTS-Version über NodeSource oder nvm, statt
aptzu vertrauen. Python 3.12 ist bereits vorhanden. - Eine Domain und einen DNS-A-Record, aber nur für den Remote-HTTP-Server. Für TLS muss ein Name auf diesen VPS aufgelöst werden. Das stdio-Beispiel benötigt überhaupt kein DNS.
- 512 MB RAM reichen aus. MCP-Server sind schlanke JSON-RPC-Prozesse. Der Speicherbedarf entsteht durch das, worauf Ihr Tool zugreift, beispielsweise durch einen Datenbanktreiber oder einen Dateicache, nicht durch das Protokoll.
- Die Spezifikation ist noch jung und wird weiterentwickelt. Die Revision vom 2025-03-26 ersetzte HTTP+SSE durch Streamable HTTP und kennzeichnete SSE als veraltet. SSE funktioniert weiterhin, und viele Server unterstützen es nach wie vor. Betrachten Sie daher jede festgelegte Transportart als etwas, das Sie anhand der Release Notes des Servers erneut prüfen müssen, nicht als unveränderliche Vorgabe.
Schritt 1: Einen stdio-Server in Claude Code einbinden
Beginnen Sie mit dem Filesystem-Server. Er ist offiziell, wird aktiv gepflegt und benötigt nur Node. Der folgende Befehl registriert ihn bei Claude Code und beschränkt ihn auf das aktuelle Projekt, sodass der Eintrag in einer versionierbaren Datei landet:
cd /home/matt/projects/api
claude mcp add --scope project --transport stdio filesystem \
-- npx -y @modelcontextprotocol/server-filesystem /home/matt/projects/apiDer Trenner -- ist wichtig: Alles danach ist der Befehl, den Claude Code ausführt, und kein Flag für Claude Code. Dadurch wird eine .mcp.json im Projektstamm erstellt:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/home/matt/projects/api"
]
}
}
}Es läuft noch nichts. Wenn Sie Claude Code das nächste Mal in diesem Verzeichnis starten, liest der Agent .mcp.json ein, startet npx -y @modelcontextprotocol/server-filesystem ... als Kindprozess und führt den MCP-Handshake über stdin/stdout dieses Prozesses aus. Prüfen Sie, ob die Einrichtung erfolgreich war:
claude mcp listEin funktionsfähiger Server zeigt seinen Befehl und ein grünes Häkchen, filesystem: npx -y @modelcontextprotocol/server-filesystem ... - ✔ Connected. Innerhalb der Sitzung listet der Slash-Befehl /mcp die Tools auf, die der Server bereitstellt (read_text_file, write_file, list_directory). Der Agent kann sie nun für die freigegebenen Pfade aufrufen. Ein Datenbank-Tool wird auf dieselbe Weise eingerichtet. Tauschen Sie das Paket aus und übergeben Sie am Ende einen Verbindungsstring. Prüfen Sie jedoch im Repository des Servers den aktuellen Paketnamen, da der Referenzserver für Postgres mehr als einmal den Besitzer gewechselt hat.
Das ist der eigentliche Vorteil, wenn der Agent direkt auf dem Server läuft: Die Claude-Code-Sitzung läuft auf dem VPS innerhalb von tmux, und die stdio-Server laufen direkt daneben. Sie haben unmittelbaren Zugriff auf die Projektdateien und lokalen Dienste, ohne Netzwerk-Roundtrip. Sobald der Agent sowohl write_file als auch read_text_file besitzt, sollten Sie diese Reichweite mit einem Skill kombinieren, der ihn auf die kleinstmögliche funktionierende Änderung ausrichtet, weil ein Filesystem-Tool eine weitreichende Neufassung genauso einfach macht wie eine Korrektur in zwei Zeilen. Dieselbe Einbindung geht über lokale Dateien hinaus: Wenn Sie bereits eine Suchmaschine auf dem VPS betreiben, können Sie dem Agenten Ihre eigene SearXNG-Instanz als Such-Tool übergeben. Dadurch bleiben die Suchanfragen auf Ihrem Server, während nicht vertrauenswürdiger Seitentext direkt in den Kontext gelangt, auf dessen Grundlage der Agent anschließend handelt.
Schritt 2: Einen entfernten HTTP-Server erstellen
Ein stdio-Server wird zusammen mit seinem übergeordneten Prozess beendet und pro Client einmal gestartet. Wenn Sie daher zwei Claude-Code-Sitzungen auf dem Server ausführen, die Arbeit aneinander übergeben, erhält jede Sitzung eine eigene private Kopie des Tools. Wenn ein Tool für alle Clients dauerhaft laufen soll, etwa ein gemeinsames Administrationswerkzeug oder ein Datenbank-Gateway, das sowohl Ihr Laptop als auch Ihre CI aufrufen, benötigen Sie den HTTP-Transport und einen echten Dienst. Hier ist ein minimaler Python-Server mit dem offiziellen SDK, der ein Tool bereitstellt:
# /opt/mcp-ops/server.py
from mcp.server.mcpserver import MCPServer
import subprocess
mcp = MCPServer("ops-tools")
@mcp.tool()
def disk_free() -> str:
"""Return `df -h` for the server."""
out = subprocess.run(["df", "-h"], capture_output=True, text=True)
return out.stdout
if __name__ == "__main__":
# Serves Streamable HTTP at /mcp on 127.0.0.1:8000
mcp.run(transport="streamable-http", host="127.0.0.1", port=8000)Hinweis host="127.0.0.1". Der Server bindet nur an localhost. Nichts außerhalb des Servers kann ihn direkt erreichen. Das ist genau das gewünschte Verhalten, solange noch keine Authentifizierung vorhanden ist. Dies ist das 2.x-SDK, das pip install "mcp[cli]" derzeit abruft (2.3.0 am 2026-10-20). Es hat FastMCP in MCPServer umbenannt und host sowie port vom Konstruktor nach run() verschoben. Der alte Import mcp.server.fastmcp schlägt nun mit ModuleNotFoundError fehl. Installieren Sie das SDK in einer eigenen virtuellen Umgebung, damit systemd einen stabilen Interpreter-Pfad verwendet:
sudo useradd --system --home /opt/mcp-ops --shell /usr/sbin/nologin mcp
sudo install -d -o mcp -g mcp /opt/mcp-ops
sudo -H -u mcp python3 -m venv /opt/mcp-ops/.venv
sudo -H -u mcp /opt/mcp-ops/.venv/bin/pip install "mcp[cli]"Schritt 3: Mit systemd dauerhaft ausführen
Ein Tool, das nicht verfügbar ist, wenn der Agent es aufruft, ist schlechter als gar kein Tool. Das ist besonders wichtig, wenn der Client selbst ein langlebiger Prozess ist: Ein dauerhaft laufender Agent, der seinen Speicher und seine Zeitpläne über Reboots hinweg beibehält ruft diese Tools nach einem Zeitplan auf, ohne dass jemand den Vorgang überwacht. Deshalb muss der Server ebenfalls selbstständig wieder starten. Schreiben Sie /etc/systemd/system/mcp-ops.service:
[Unit]
Description=MCP ops-tools server
After=network.target
[Service]
Type=simple
User=mcp
WorkingDirectory=/opt/mcp-ops
ExecStart=/opt/mcp-ops/.venv/bin/python /opt/mcp-ops/server.py
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
[Install]
WantedBy=multi-user.targetDer absolute Pfad zum venv-Python in ExecStart ist erforderlich. Zeigen Sie ihn auf /usr/bin/python3, und starten Sie den Prozess mit ModuleNotFoundError: No module named 'mcp', weil der Systeminterpreter Ihr pip install nicht kennt. Aktivieren und prüfen Sie den Dienst:
sudo systemctl daemon-reload
sudo systemctl enable --now mcp-ops
sudo systemctl status mcp-ops
curl -si -H 'Accept: application/json, text/event-stream' \
-H 'Content-Type: application/json' \
-X POST http://127.0.0.1:8000/mcpstatus sollte active (running) anzeigen. curl gibt HTTP/1.1 400 Bad Request mit einem JSON-RPC-Fehler im Antworttext zurück. Die Anfrage enthielt keine Sitzung und keine gültigen JSON-Nutzdaten. Genau das ist hier erwünscht: Es beweist, dass der Port antwortet und das Protokoll spricht. Connection refused oder eine leere Antwort bedeutet, dass der Prozess nicht an die erwartete Adresse gebunden ist. Lesen Sie journalctl -u mcp-ops -n 50.
Schritt 4: TLS und einen Reverse Proxy vorschalten
Der Server lauscht auf localhost. Damit Sie ihn von überall erreichen, terminieren Sie TLS in nginx und leiten die Anfragen intern per Proxy weiter. Installieren Sie nginx, beziehen Sie ein Zertifikat mit Certbot und Let’s Encrypt mit nginx und schreiben Sie anschließend den location-Block. Entscheidend ist, das Buffering zu deaktivieren. Das Standardverhalten von nginx hält eine Antwort zurück, bis sie vollständig ist. Dadurch bleibt ein SSE-Stream dauerhaft hängen:
server {
listen 443 ssl;
server_name mcp.example.com;
# ssl_certificate lines managed by Certbot
location /mcp {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
# The four lines that make SSE work through nginx:
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
chunked_transfer_encoding off;
}
}Laden Sie die Konfiguration mit sudo nginx -t && sudo systemctl reload nginx neu. Wenn Sie bereits eine größere Anzahl von Containern betreiben, übernimmt ein Traefik-Reverse-Proxy mit automatischem TLS dieselbe Aufgabe. Er stellt das Zertifikat aus und leitet Anfragen anhand des Hostnamens weiter. Sie müssen dann nur Labels zum MCP-Container hinzufügen. In beiden Fällen ist der Reverse Proxy jetzt das einzige System an einem öffentlichen Port. Er leitet auf einen Dienst weiter, den Sie noch nicht abgesichert haben. Beheben Sie das, bevor Sie die URL irgendwo registrieren.
Schritt 5: Die Sicherheitsregel, die dieses Thema bestimmt
Veröffentlichen Sie niemals einen nicht authentifizierten MCP-Endpunkt. Ein MCP-Server ist keine schreibgeschützte API. Er gewährt Zugriff auf Tools, Ihre Dateien, Ihre Datenbank und manchmal eine Shell. Ein offener /mcp im öffentlichen Internet ermöglicht Fremden denselben Zugriff wie Ihrem AI-Agenten: Sie listen Ihre Tools auf und rufen sie anschließend auf. Behandeln Sie ihn genau wie einen nicht authentifizierten Admin-Socket, denn genau das ist er. Welche Möglichkeiten ein gestohlenes Token eröffnet, hängt außerdem vom dahinterliegenden Server ab: der schreibgeschützte MCP-Server, der mit dem openGym-Workout-Tracker ausgeliefert wird kann ausschließlich Trainingsdaten zurückgeben, während ein Datei- oder Shell-Tool Zugriff auf das System gewährt.
Drei Schutzmaßnahmen in absteigender Priorität:
- Veröffentlichen Sie ihn nicht. Lassen Sie den Server auf
127.0.0.1laufen und greifen Sie von Ihrem Laptop über einen SSH-Tunnel darauf zu:ssh -L 8000:127.0.0.1:8000 matt@vps. Richten Sie den Client anschließend aufhttp://127.0.0.1:8000/mcp. Dadurch wird nichts veröffentlicht. - Betreiben Sie ihn in einem privaten Netzwerk. Binden Sie die Tunneladresse eines selbst gehosteten WireGuard-VPNs und erlauben Sie nur VPN-Peers den Zugriff. Für das öffentliche Internet bleibt der Port geschlossen.
- Falls der Endpunkt öffentlich erreichbar sein muss, verlangen Sie ein Token. Die geeignete Lösung ist der MCP-OAuth-Flow, den der HTTP-Transport nativ unterstützt. Das pragmatische Minimum ist ein gemeinsames Bearer-Token, das am Proxy geprüft wird. Es ist einfach umzusetzen und verhindert unbefugte Zugriffsversuche vollständig:
location /mcp {
if ($http_authorization != "Bearer REPLACE_WITH_LONG_RANDOM") {
return 401;
}
proxy_pass http://127.0.0.1:8000;
# ...buffering-off block from above...
}Erzeugen Sie das Token mit openssl rand -hex 32. Binden Sie den Server selbst niemals ohne eine dieser Schutzmaßnahmen davor an 0.0.0.0. Der Client sendet das Token anschließend als Header. In Claude Code:
claude mcp add --scope project --transport http ops-tools https://mcp.example.com/mcp \
--header 'Authorization: Bearer ${MCP_TOKEN}'Setzen Sie MCP_TOKEN in Ihrer Shell, damit das Geheimnis nicht als Klartext in .mcp.json landet. Claude Code ersetzt ${MCP_TOKEN} beim Lesen aus der Umgebung. Wenn die Variable nicht gesetzt ist, ersetzt Claude Code sie nicht durch eine leere Zeichenfolge. Stattdessen meldet es die fehlende Variable in claude mcp list und verwendet den literalen Text ${MCP_TOKEN}. Wählen Sie außerdem einen eigenen Namen. In den Headern eines Remote-Servers liest Claude Code seine eigenen Credential-Variablen und die Ihres Cloud-Anbieters, beispielsweise ANTHROPIC_API_KEY, absichtlich als leer aus. Das gilt auch für andere Zugangsdaten, die Ihre Umgebung enthält, beispielsweise NPM_TOKEN.
Alle oben genannten Schutzmaßnahmen sichern den Endpunkt, nicht den Agenten, der das Token bereits besitzt. Das ist die andere Hälfte des Problems: Wenn Ihr Client der DeepSeek Harness ist, übernehmen Plugins, die festlegen, welche Tools ein Agent aufrufen darf, und die Toolausgabe auf eingeschleuste Anweisungen prüfen diese Aufgabe.
Schritt 6: Mit dem MCP Inspector debuggen
Wenn sich ein Server fehlerhaft verhält, sollten Sie nicht innerhalb des Agents raten. Steuern Sie ihn direkt mit dem Inspector, dem offiziellen webbasierten Test-Client. Bei einem stdio-Server übergeben Sie ihm denselben Befehl, den der Agent ausführt:
npx @modelcontextprotocol/inspector \
npx -y @modelcontextprotocol/server-filesystem /tmpDer Inspector stellt seine Benutzeroberfläche über einen Webserver auf http://localhost:6274 bereit und gibt eine URL mit einer MCP_INSPECTOR_API_TOKEN-Query-Zeichenfolge aus. Öffnen Sie diesen Link, anstatt die Adresse aus dem Gedächtnis einzugeben. Seit v2 (2.11.0 ist am 2026-10-20 aktuell) fügt das Backend das Token bei jedem Ladevorgang auch in die bereitgestellte Seite ein. Dadurch funktioniert ein Neuladen weiterhin. Das Token schützt die /api/*-Routen, über die Prozesse gestartet werden können. Der separate v1-Proxy auf 6277 ist entfallen. Der Webserver ist jedoch nicht der einzige Listener: v2 startet zusätzlich eine Sandbox für MCP Apps auf MCP_SANDBOX_PORT (standardmäßig 6275) und einen dedizierten App-Origin-Server auf MCP_APP_ORIGIN_PORT (standardmäßig 6278). Dieser stellt jede MCP App bereit, deren UI-Ressource _meta.ui.domain deklariert. Wenn Sie den Inspector über einen SSH-Tunnel erreichen oder ihn in einem Container ausführen und den Tab Apps benötigen, leiten Sie 6275 und 6278 zusammen mit 6274 weiter. Stellen Sie die Verbindung her, öffnen Sie den Tab Tools, wählen Sie ein Tool aus, tragen Sie echte Argumente ein und rufen Sie es auf. Funktioniert es im Inspector, aber nicht im Agent, liegt der Fehler in Ihrer Client-Konfiguration und nicht im Server. Für den entfernten HTTP-Server starten Sie den Inspector ohne Befehl. Fügen Sie einen Server mit dem Transport Streamable HTTP und https://mcp.example.com/mcp hinzu. Tragen Sie den Header Authorization in dessen Einstellungen ein und stellen Sie die Verbindung her. So lässt sich am schnellsten bestätigen, dass Authentifizierung und Proxy korrekt funktionieren, bevor ein Agent beteiligt ist. Der Inspector speichert Header in seinem Serverkatalog genau wie eingegeben. Dieses Token befindet sich daher nun ebenfalls in ~/.mcp-inspector/mcp.json.
Server aktuell halten
MCP entwickelt sich schnell weiter. Installieren Sie daher regelmäßig Patches. Node-Server, die mit einem nicht versionierten npx -y gestartet werden, verwenden die Version, die npx auflöst: die Version aus dem lokalen Projekt, falls dort eine vorhanden ist, andernfalls eine Kopie, die npx im npm-Cache installiert. -y überspringt nur die Installationsaufforderung. Es erzwingt kein Update. Sie verfolgen damit weder zuverlässig die neueste Version noch wissen Sie sicher, welche Version tatsächlich ausgeführt wird. Fixieren Sie die exakt getestete Version. Lesen Sie sie aus npm view @modelcontextprotocol/server-filesystem version aus und hängen Sie sie in .mcp.json an den Paketnamen an (@modelcontextprotocol/server-filesystem@<version>), sobald der Server relevant ist. Aktualisieren Sie die Version anschließend bewusst. Python-Server unter systemd aktualisieren Sie mit sudo -H -u mcp /opt/mcp-ops/.venv/bin/pip install -U "mcp[cli]", gefolgt von sudo systemctl restart mcp-ops. Lesen Sie vor einem Major-Update die Release Notes. Der Wechsel vom Python-SDK 1.x zum 2.x führt dazu, dass 1.x-Code beim Import fehlschlägt. Der Migrationsleitfaden des SDK empfiehlt, bis zur abgeschlossenen Migration eine obere Versionsgrenze mit <2 festzulegen, beispielsweise "mcp[cli]<2". Prüfen Sie beim Upgrade, auf welche Spec-Version Ihr SDK abzielt. Ein Wechsel über die Grenze zwischen SSE und Streamable HTTP kann das Transportprotokoll ändern, das Ihre Clients anfordern müssen.
Fehlerbilder und die dabei angezeigten Meldungen
Der Agent meldet, dass der Server fehlgeschlagen ist. claude mcp list gibt ✘ Failed to connect aus. In aktuellen Versionen wird die Fehlerdetails an diese Zeile angehängt. Führen Sie claude --debug aus. Dort sehen Sie normalerweise Error: spawn npx ENOENT. Der Befehl befindet sich nicht im PATH des Agents. Die Laufzeitumgebung fehlt oder liegt nicht an der Stelle, an der der Agent danach sucht: Node ist nicht installiert, npx fehlt oder eine Python-Umgebung wird über einen unqualifizierten Namen referenziert. Korrigieren Sie den Befehl so, dass er einen absoluten Pfad verwendet, oder installieren Sie die Laufzeitumgebung. Stellen Sie anschließend die Verbindung erneut her.
Ein stdio-Server verbindet sich und bricht die Verbindung sofort wieder ab. Der Client protokolliert einen JSON-Parsing-Fehler, etwa Unexpected token 'S', "Server sta"... is not valid JSON oder Failed to parse message. Die Ursache ist immer gleich: Der Server hat eine Logzeile nach stdout geschrieben. Bei stdio ist stdout der JSON-RPC-Kanal. Jeder zusätzliche Text beschädigt daher den Datenstrom, und der Handshake schlägt fehl. In Node schreibt console.log nach stdout. Verwenden Sie console.error. In Python schreibt ein unqualifiziertes print() nach stdout. Schreiben Sie Logs mit logging, das auf sys.stderr konfiguriert ist, oder übergeben Sie file=sys.stderr. Die Regel ist eindeutig: Bei stdio darf stdout nur JSON-RPC enthalten. Alles für Menschen bestimmte wird nach stderr geschrieben.
Ein entfernter Server läuft beim Handshake in ein Timeout oder beendet die Verbindung. Der Client schlägt mit MCP error -32000: Connection closed fehl. Alternativ bleibt der Inspector bei Connect hängen und listet keine Tools auf. Hinter nginx ist die Ursache das Buffering: Der Proxy hält den SSE-Datenstrom zurück, statt ihn weiterzuleiten. Daher wartet der Client auf eine Antwort, die nie eintrifft. Fügen Sie proxy_buffering off; und den restlichen Block aus Schritt 4 zu location hinzu. Prüfen Sie dies mit curl -N gegen die öffentliche URL. Die Eventdaten sollten schrittweise eintreffen und nicht erst am Ende vollständig ausgegeben werden.
Die Authentifizierung wird abgewiesen. Der Client meldet Error POSTing to endpoint (HTTP 401) oder ausdrücklich 401 Unauthorized. Entweder fehlt der Header, das Token ist falsch oder die Variable wurde nicht expandiert. Letzteres ist ein häufiger Fehler. Wenn MCP_TOKEN beim Einlesen der Konfiguration durch den Client nicht gesetzt ist, warnt Claude Code in claude mcp list vor der fehlenden Variable und sendet den Literaltext. nginx sieht dann Bearer ${MCP_TOKEN}. Eine Variable, deren Name einem anderen Zugangsschlüssel von Claude Code, Ihrem Cloudanbieter oder Ihrer Umgebung entspricht, wird stattdessen als leer gelesen. nginx sieht dann Bearer ohne Wert. Geben Sie die Variable aus, fügen Sie den Header erneut hinzu und prüfen Sie, ob die exakten Bytes mit dem Token in der nginx-Konfiguration if übereinstimmen.
Der Dienst startet unter systemd nicht. journalctl -u mcp-ops zeigt ModuleNotFoundError: No module named 'mcp'. ExecStart verweist auf das System-Python statt auf den Interpreter der virtuellen Umgebung. Oder Address already in use: Ein anderer Prozess verwendet Port 8000. Ermitteln Sie ihn mit sudo ss -ltnp | grep 8000.
FAQ
Was ist genau ein MCP-Server?
Es handelt sich um ein Programm, das einem KI-Client über das Model Context Protocol Tools und Ressourcen per JSON-RPC 2.0 zur Verfügung stellt. Das KI-Modell führt das Tool nie selbst aus. Es sendet eine Anfrage an seinen Client, der Client ruft den MCP-Server auf, und der Server führt den Vorgang aus und gibt ein Ergebnis zurück. Da das Protokoll standardisiert ist, funktioniert ein Server mit jedem kompatiblen Client, unabhängig davon, ob es sich um Claude Code, Claude Desktop oder die Gemini CLI handelt.
Was ist der Unterschied zwischen stdio- und HTTP-Transport?
Ein stdio-Server wird vom Client als untergeordneter Prozess gestartet und kommuniziert über stdin/stdout. Er ist daher an einen Client auf einem Rechner gebunden und wird zusammen mit diesem beendet. Netzwerkzugriff und Authentifizierung sind nicht erforderlich. Ein HTTP-Server ist ein dauerhaft laufender Netzwerkdienst, den mehrere Clients gleichzeitig erreichen können. Deshalb benötigt er TLS und Authentifizierung. Verwenden Sie stdio für lokale Tools mit einem einzelnen Benutzer. Verwenden Sie HTTP (Streamable HTTP bei aktuellen Servern) für gemeinsam genutzte oder dauerhaft laufende Dienste.
Wie sichere ich einen entfernten MCP-Server ab?
Gehen Sie davon aus, dass der Server Zugriff auf Ihre Dateien, Datenbank oder Shell gewährt. Machen Sie ihn niemals ohne Authentifizierung erreichbar. Binden Sie ihn möglichst nur an localhost und greifen Sie über einen SSH-Tunnel oder ein privates VPN darauf zu. Wenn der Server öffentlich erreichbar sein muss, schalten Sie einen Reverse Proxy davor, der ein Bearer-Token oder den MCP-OAuth-Ablauf erzwingt. Erzeugen Sie das Token mit openssl rand -hex 32. Binden Sie den Server niemals ohne eine dieser Schutzmaßnahmen davor an 0.0.0.0.
Wie debugge ich einen Server, der nicht startet?
Prüfen Sie zuerst claude mcp list. ✘ Failed to connect mit spawn ... ENOENT bedeutet, dass der Befehl oder die Laufzeitumgebung fehlt. Korrigieren Sie den Pfad oder installieren Sie die fehlende Komponente. Wenn die Verbindung zunächst hergestellt wird und anschließend mit einem JSON-Parsefehler abbricht, schreibt der Server Logs nach stdout und beschädigt dadurch den JSON-RPC-Datenstrom. Leiten Sie alle Logs nach stderr um. Führen Sie den exakten Befehl für alle anderen Fälle unter dem MCP Inspector aus. Dieser steuert den Server isoliert, sodass Sie einen Fehler im Server von einem Fehler in der Client-Konfiguration unterscheiden können.