MCP-Tunnels Schnellstart
Verbinde Claude mit einem privaten MCP-Server über eine lokale Docker-Compose-Bereitstellung.
Dieser Schnellstart führt dich vom Erstellen eines Tunnels bis dahin, dass Claude über diesen einen privaten MCP-Server aufruft. Er verwendet Docker Compose mit manueller Bereitstellung der Anmeldedaten, was der kürzeste Weg für lokale Tests ist. Für Produktionsbereitstellungen siehe Mit Helm bereitstellen oder Mit Docker Compose bereitstellen.
Was du erstellst
Einen Tunnel-Stack aus zwei Containern (dem Proxy und cloudflared) sowie einen Beispiel-MCP-Server, der daneben läuft. Wenn alles läuft, ist der Beispielserver von Claude aus unter https://echo.<your-tunnel-domain>/mcp erreichbar, obwohl nichts auf einem öffentlichen Port lauscht.
Was du brauchst
- Docker und Docker Compose auf einem Rechner mit ausgehendem Internetzugang.
- Eine Rolle in der Claude Console, die MCP-Tunnels verwalten kann. Siehe die Voraussetzungen im Console-Leitfaden.
- OpenSSL 1.1.1 oder neuer. Unter macOS und den meisten Linux-Distributionen vorinstalliert. Unter Windows installierst du es separat (die
openssl-Binärdatei muss in deinemPATHliegen).
Einen Tunnel erstellen
Gehe in der Claude Console zur Seite MCP-Tunnels (
platform.claude.com/settings/workspaces/default/mcp-tunnels). Jeder Tunnel gehört zu einem Workspace. Wähle den gewünschten Workspace in der Workspace-Auswahl in der Seitenleiste aus. Klicke auf New tunnel und gib ihm einen Namen. Lass Set up programmatic access deaktiviert; dieser Schnellstart verwendet die manuelle Bereitstellung von Anmeldedaten.Öffne den Tunnel, nachdem er erstellt wurde. Kopiere zwei Werte aus dem Abschnitt Connection:
- Domain (sieht aus wie
abcd1234.tunnel.anthropic.com) - Token (klicke auf das Augensymbol und kopiere dann)
- Domain (sieht aus wie
Das Bereitstellungsverzeichnis einrichten
mkdir -p mcp-tunnel/{config,data} cd mcp-tunnel export TUNNEL_DOMAIN=YOUR_TUNNEL_DOMAIN_HERE # from step 1 export TUNNEL_TOKEN='eyJ...' # from step 1New-Item -ItemType Directory -Force -Path mcp-tunnel/config, mcp-tunnel/data | Out-Null Set-Location mcp-tunnel $env:TUNNEL_DOMAIN = "YOUR_TUNNEL_DOMAIN_HERE" # from step 1 $env:TUNNEL_TOKEN = "eyJ..." # from step 1Eine CA und ein Serverzertifikat generieren
Der Proxy terminiert inneres TLS mit einem Zertifikat, das von einer CA signiert ist, die du kontrollierst. Generiere beides:
openssl req -x509 -newkey rsa:2048 -nodes \ -keyout data/ca.key -out data/ca.crt \ -days 3650 -subj "/CN=mcp-tunnel-ca" \ -addext "basicConstraints=critical,CA:TRUE" \ -addext "keyUsage=critical,keyCertSign,cRLSign" \ -addext "subjectKeyIdentifier=hash" cat > data/tls.ext <<EOF subjectAltName = DNS:${TUNNEL_DOMAIN},DNS:*.${TUNNEL_DOMAIN} authorityKeyIdentifier = keyid,issuer extendedKeyUsage = serverAuth EOF openssl req -newkey rsa:2048 -nodes \ -keyout data/tls.key -out /tmp/server.csr \ -subj "/CN=${TUNNEL_DOMAIN}" openssl x509 -req -in /tmp/server.csr \ -CA data/ca.crt -CAkey data/ca.key -CAcreateserial \ -out data/tls.crt -days 90 -extfile data/tls.ext chmod 644 data/tls.keyopenssl req -x509 -newkey rsa:2048 -nodes ` -keyout data/ca.key -out data/ca.crt ` -days 3650 -subj "/CN=mcp-tunnel-ca" ` -addext "basicConstraints=critical,CA:TRUE" ` -addext "keyUsage=critical,keyCertSign,cRLSign" ` -addext "subjectKeyIdentifier=hash" @" subjectAltName = DNS:$env:TUNNEL_DOMAIN,DNS:*.$env:TUNNEL_DOMAIN authorityKeyIdentifier = keyid,issuer extendedKeyUsage = serverAuth "@ | Set-Content -NoNewline -Encoding ascii -Path data/tls.ext openssl req -newkey rsa:2048 -nodes ` -keyout data/tls.key -out data/server.csr ` -subj "/CN=$env:TUNNEL_DOMAIN" openssl x509 -req -in data/server.csr ` -CA data/ca.crt -CAkey data/ca.key -CAcreateserial ` -out data/tls.crt -days 90 -extfile data/tls.extKlicke zurück in der Console auf der Detailseite des Tunnels auf Add certificate und lade
data/ca.crthoch (oder füge den Inhalt ein). Das Badge Needs certificate neben dem Namen des Tunnels verschwindet.Den Beispiel-MCP-Server schreiben
cat > hello_server.py <<'EOF' from mcp.server.fastmcp import FastMCP mcp = FastMCP("hello-server", host="0.0.0.0", port=9000) @mcp.tool() def hello(name: str = "world") -> str: """Say hello to someone.""" return f"Hello, {name}!" if __name__ == "__main__": mcp.run(transport="streamable-http") EOF@' from mcp.server.fastmcp import FastMCP mcp = FastMCP("hello-server", host="0.0.0.0", port=9000) @mcp.tool() def hello(name: str = "world") -> str: """Say hello to someone.""" return f"Hello, {name}!" if __name__ == "__main__": mcp.run(transport="streamable-http") '@ | Set-Content -NoNewline -Encoding ascii -Path hello_server.pyDie Proxy-Konfiguration und die Compose-Datei schreiben
cat > config/mcp-proxy.yaml <<EOF listen_addr: ":8080" tunnel_domain: ${TUNNEL_DOMAIN} tls: cert_file: /data/tls.crt key_file: /data/tls.key routes: echo: http://hello-mcp:9000 EOF cat > docker-compose.yaml <<'EOF' services: mcp-proxy: image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:d243d30642d39857a0579e465cb3b9bf3ae7c1141e83143bb6856777a31467a5 volumes: - ./config/mcp-proxy.yaml:/etc/mcp-gateway/config.yaml:ro - ./data:/data:ro restart: unless-stopped cloudflared: image: cloudflare/cloudflared@sha256:0e56c13c7058fcef9c4f0e7d83372f82330548dbf8f8b366f3d8b506526d93b2 command: tunnel --no-autoupdate run --url http://localhost:8080 environment: - TUNNEL_TOKEN network_mode: "service:mcp-proxy" restart: unless-stopped hello-mcp: image: python:3.13-slim working_dir: /app volumes: - ./hello_server.py:/app/hello_server.py:ro command: sh -c "pip install --quiet mcp && python hello_server.py" restart: unless-stopped EOF@" listen_addr: ":8080" tunnel_domain: $env:TUNNEL_DOMAIN tls: cert_file: /data/tls.crt key_file: /data/tls.key routes: echo: http://hello-mcp:9000 "@ | Set-Content -NoNewline -Encoding ascii -Path config/mcp-proxy.yaml @' services: mcp-proxy: image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:d243d30642d39857a0579e465cb3b9bf3ae7c1141e83143bb6856777a31467a5 volumes: - ./config/mcp-proxy.yaml:/etc/mcp-gateway/config.yaml:ro - ./data:/data:ro restart: unless-stopped cloudflared: image: cloudflare/cloudflared@sha256:0e56c13c7058fcef9c4f0e7d83372f82330548dbf8f8b366f3d8b506526d93b2 command: tunnel --no-autoupdate run --url http://localhost:8080 environment: - TUNNEL_TOKEN network_mode: "service:mcp-proxy" restart: unless-stopped hello-mcp: image: python:3.13-slim working_dir: /app volumes: - ./hello_server.py:/app/hello_server.py:ro command: sh -c "pip install --quiet mcp && python hello_server.py" restart: unless-stopped '@ | Set-Content -NoNewline -Encoding ascii -Path docker-compose.yamlStarten
docker compose up -d docker compose logs mcp-proxy | grep "route configured" docker compose logs cloudflared | grep "Registered tunnel connection"docker compose up -d docker compose logs mcp-proxy | Select-String "route configured" docker compose logs cloudflared | Select-String "Registered tunnel connection"Du solltest eine
route configured-Zeile fürechound vierRegistered tunnel connection-Zeilen sehen. Die Container brauchen einige Sekunden zum Starten; führe die Log-Befehle erneut aus, falls sie leer zurückkommen.Von Claude aus aufrufen
Gehe in der Console zur Seite Sessions (
platform.claude.com/sessions) und erstelle eine Session. Wähle in der Agent-Auswahl Create new agent, gib dem Agent einen Namen und behalte das vorausgefüllte Modell bei. Klicke auf + MCP Server, wähle deinen Tunnel aus und setze Subdomain aufechound Path aufmcp. Frage dann:Use the hello tool to greet tunnel.
Du solltest einen Tool-Aufruf gefolgt von seinem Ergebnis sehen.
Nächste Schritte
Der Tunnel ist durchgängig verifiziert. Um deinen eigenen MCP-Server einzusetzen, füge ihn zu docker-compose.yaml hinzu (oder führe ihn im selben Docker-Netzwerk aus), füge in config/mcp-proxy.yaml eine Route dafür hinzu und starte dann den Proxy neu (docker compose restart mcp-proxy).
Für Produktionsbereitstellungen:
Gehärtete Bereitstellung auf einem einzelnen Host, mit oder ohne programmatischen Zugriff.
Kubernetes-Bereitstellung mit automatischer Verwaltung von Anmeldedaten.
Was this page helpful?