Démarrage rapide des tunnels MCP
Connectez Claude à un serveur MCP privé à l'aide d'un déploiement Docker Compose local.
Ce guide de démarrage rapide vous accompagne de la création d'un tunnel jusqu'à l'appel par Claude d'un serveur MCP privé à travers celui-ci. Il utilise Docker Compose avec un approvisionnement manuel des identifiants, ce qui constitue le chemin le plus court pour les tests locaux. Pour les déploiements en production, consultez Déployer avec Helm ou Déployer avec Docker Compose.
Ce que vous allez construire
Une pile de tunnel à deux conteneurs (le proxy et cloudflared) ainsi qu'un serveur MCP d'exemple s'exécutant à côté. Lorsque tout fonctionne, le serveur d'exemple est accessible depuis Claude à l'adresse https://echo.<your-tunnel-domain>/mcp, même si rien n'écoute sur un port public.
Ce dont vous avez besoin
- Docker et Docker Compose sur une machine disposant d'un accès Internet sortant.
- Un rôle dans la Claude Console permettant de gérer les tunnels MCP. Consultez les prérequis du guide de la Console.
- OpenSSL 1.1.1 ou version ultérieure. Préinstallé sur macOS et la plupart des distributions Linux. Sous Windows, installez-le séparément (le binaire
openssldoit se trouver dans votrePATH).
Créer un tunnel
Dans la Claude Console, accédez à la page MCP tunnels (
platform.claude.com/settings/workspaces/default/mcp-tunnels). Chaque tunnel appartient à un espace de travail. Sélectionnez l'espace de travail souhaité dans le sélecteur d'espace de travail de la barre latérale. Cliquez sur New tunnel et donnez-lui un nom. Laissez Set up programmatic access désactivé ; ce guide de démarrage rapide utilise le provisionnement manuel des identifiants.Une fois le tunnel créé, ouvrez-le. Copiez deux valeurs depuis la section Connection :
- Domain (ressemble à
abcd1234.tunnel.anthropic.com) - Token (cliquez sur l'icône en forme d'œil, puis copiez)
- Domain (ressemble à
Configurer le répertoire de déploiement
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 1Générer une CA et un certificat serveur
Le proxy termine le TLS interne à l'aide d'un certificat signé par une CA que vous contrôlez. Générez les deux :
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.extDe retour dans la Console, sur la page de détails du tunnel, cliquez sur Add certificate et téléversez
data/ca.crt(ou collez son contenu). Le badge Needs certificate à côté du nom du tunnel disparaît.Écrire le serveur MCP d'exemple
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.pyÉcrire la configuration du proxy et le fichier compose
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.yamlLe démarrer
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"Vous devriez voir une ligne
route configuredpourechoet quatre lignesRegistered tunnel connection. Les conteneurs mettent quelques secondes à démarrer ; relancez les commandes de journalisation si elles ne renvoient rien.L'appeler depuis Claude
Dans la Console, accédez à la page Sessions (
platform.claude.com/sessions) et créez une session. Dans le sélecteur d'agent, sélectionnez Create new agent, donnez un nom à l'agent et conservez le modèle prérempli. Cliquez sur + MCP Server, sélectionnez votre tunnel, puis définissez Subdomain surechoet Path surmcp. Demandez ensuite :Use the hello tool to greet tunnel.
Vous devriez voir un appel d'outil suivi de son résultat.
Étapes suivantes
Le tunnel est vérifié de bout en bout. Pour utiliser votre propre serveur MCP à la place, ajoutez-le à docker-compose.yaml (ou exécutez-le sur le même réseau Docker), ajoutez une route pour celui-ci dans config/mcp-proxy.yaml, puis redémarrez le proxy (docker compose restart mcp-proxy).
Pour les déploiements en production :
Déploiement renforcé sur un seul hôte, avec ou sans accès programmatique.
Déploiement Kubernetes avec gestion automatique des identifiants.
Was this page helpful?