Claude Platform Docs
MessagesTunnels MCP

Déployer des tunnels MCP avec Docker Compose

Installez la pile de tunnel MCP sur une VM à l'aide de Docker Compose.

Ce guide déploie la pile de tunnel sous forme de conteneurs durcis sur un seul hôte. La même configuration peut être répliquée sur plusieurs hôtes pour la disponibilité.

Avant de commencer

Vous avez besoin de :

  • Un tunnel. Avec l'accès programmatique, le composant de configuration (setup component) en crée un pour vous lorsque vous ne fournissez pas d'ID de tunnel ; pour vous rattacher à un tunnel existant à la place, créez-le dans la Console et notez l'ID du tunnel (tnl_...). Le provisionnement manuel part toujours d'un tunnel créé dans la Console.
  • Un moyen pour l'hôte de s'authentifier auprès de l'API Tunnels.
    • Accès programmatique (recommandé). Activez Set up programmatic access lors de la création du tunnel (ou créez la règle de fédération directement sous Settings > Workload identity si vous laissez le composant de configuration créer le tunnel) afin que le composant de configuration puisse s'authentifier via Workload Identity Federation. Notez l'ID de la règle de fédération (fdrl_...) et l'ID de votre organisation.
    • Manuel. Ignorez l'accès programmatique. Vous récupérerez le jeton du tunnel depuis la Console, générerez vous-même une CA et un certificat serveur, puis enregistrerez la CA dans la Console.
  • Un hôte avec Docker et Docker Compose installés. Le flux manuel nécessite également openssl (1.1.1 ou ultérieur).
  • Une connectivité réseau sortante depuis l'hôte vers api.anthropic.com (443 TCP) et la périphérie du tunnel (tunnel edge) (7844 TCP et UDP). Consultez l'ensemble des exigences réseau.
  • Un ou plusieurs serveurs MCP en cours d'exécution et joignables depuis l'hôte aux adresses que vous configurerez sous routes. Si vous n'en avez pas encore, utilisez le serveur d'exemple.

Facultatif : utiliser un serveur MCP d'exemple

Si vous ne disposez pas d'un serveur MCP pour les tests, utilisez ce serveur minimal :

mkdir -p mcp-tunnel
cat > mcp-tunnel/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

Les étapes d'installation suivantes font un cd dans mcp-tunnel/ et indiquent où ajouter le service et la route correspondants.

Installation

Ce guide fournit une approche de référence utilisant Docker Compose. Il vous incombe de l'adapter pour répondre aux exigences de sécurité de votre organisation.

Ce parcours nécessite que l'hôte dispose d'un fournisseur d'identité OIDC (tel qu'un serveur de métadonnées de VM cloud ou SPIFFE). Si ce n'est pas le cas, utilisez plutôt l'onglet Sans accès programmatique.

Le composant de configuration utilise Workload Identity Federation pour récupérer le jeton du tunnel, générer une CA et un certificat serveur, et enregistrer la CA auprès d'Anthropic.

  1. Préparer le répertoire de déploiement

    mkdir -p mcp-tunnel/{config,data}
    cd mcp-tunnel
    sudo chown 65532:65532 data

    Les conteneurs s'exécutent sous l'UID non root 65532 et ont besoin d'un accès en écriture à data/.

  2. Écrire docker-compose.yaml

    Le fichier compose épingle les images par empreinte SHA-256, exécute chaque conteneur en tant que non root avec un système de fichiers en lecture seule, supprime toutes les capacités Linux et désactive l'élévation de privilèges.

    cat > docker-compose.yaml <<'EOF'
    services:
      setup:
        image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:efb27b299d627e4134815663cb8896641eeaee025d734c0f695582b4df38f013
        entrypoint: ["/setup"]
        command:
          - init
          - --api-url=https://api.anthropic.com
          - --output=dir:/data
          - --token-version=1
        environment:
          - TUNNEL_ID
          - ANTHROPIC_FEDERATION_RULE_ID
          - ANTHROPIC_ORGANIZATION_ID
          - ANTHROPIC_WORKSPACE_ID
          - ANTHROPIC_IDENTITY_TOKEN
        volumes:
          - ./data:/data
        user: "65532:65532"
        read_only: true
        security_opt:
          - no-new-privileges:true
        cap_drop:
          - ALL
        profiles: ["setup"]
    
      cloudflared:
        image: cloudflare/cloudflared@sha256:6b599ca3e974349ead3286d178da61d291961182ec3fe9c505e1dd02c8ac31b0
        command: tunnel --no-autoupdate run --url http://localhost:8080
        environment:
          - TUNNEL_TOKEN
        # Partage le netns du proxy pour que localhost:8080 l'atteigne.
        network_mode: "service:mcp-proxy"
        restart: unless-stopped
        user: "65532:65532"
        read_only: true
        security_opt:
          - no-new-privileges:true
        cap_drop:
          - ALL
        stop_grace_period: 30s
        logging:
          options:
            max-size: "10m"
            max-file: "3"
    
      mcp-proxy:
        image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:efb27b299d627e4134815663cb8896641eeaee025d734c0f695582b4df38f013
        volumes:
          - ./config/mcp-proxy.yaml:/etc/mcp-gateway/config.yaml:ro
          - ./data:/data:ro
        restart: unless-stopped
        user: "65532:65532"
        read_only: true
        security_opt:
          - no-new-privileges:true
        cap_drop:
          - ALL
        stop_grace_period: 30s
        logging:
          options:
            max-size: "10m"
            max-file: "3"
    EOF

    Si vous utilisez le serveur MCP d'exemple, ajoutez-le en tant que service :

    cat >> docker-compose.yaml <<'EOF'
    
      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
  3. Provisionner le tunnel

    Définissez les identifiants. Laissez TUNNEL_ID non défini pour que le composant de configuration crée un tunnel ; définissez-le pour vous rattacher à un tunnel existant depuis la Console :

    # export TUNNEL_ID=tnl_...   # à définir pour se rattacher à un tunnel existant
    export ANTHROPIC_FEDERATION_RULE_ID=fdrl_...
    export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000

    Si votre règle de fédération est limitée à un espace de travail autre que celui par défaut de votre organisation, définissez également ANTHROPIC_WORKSPACE_ID=wrkspc_... ; sinon, le composant de configuration utilise l'espace de travail par défaut. Un tunnel créé automatiquement est créé dans cet espace de travail.

    Définissez ANTHROPIC_IDENTITY_TOKEN sur un JWT OIDC provenant du fournisseur d'identité de cet hôte. Suivez le guide WIF de votre fournisseur pour enregistrer l'émetteur, définir le sujet de la règle et émettre le jeton ; l'audience de la règle doit correspondre à l'audience que vous demandez lors de l'émission.

    Exécutez le composant de configuration :

    docker compose run --rm setup

    setup init est idempotent sur data/ : le réexécuter réutilise l'ID de tunnel et la CA déjà stockés à cet endroit et ne crée jamais de second tunnel. Une nouvelle CA n'est générée et enregistrée que lorsque data/ est vide ou que TUNNEL_ID a changé ; dans ce cas, la limite de deux certificats actifs s'applique, donc révoquez-en d'abord un dans la Console si les deux emplacements sont occupés.

    Consultez Échecs d'authentification du composant de configuration en cas d'erreur.

    Récupérez le domaine de votre tunnel et exportez-le pour les étapes suivantes :

    export TUNNEL_DOMAIN=$(sudo cat data/tunnel-domain)
    echo "$TUNNEL_DOMAIN"
  4. Écrire la configuration du proxy

    tunnel_domain est obligatoire : le proxy l'utilise pour retirer le suffixe de domaine des noms d'hôte entrants avant de rechercher le sous-domaine dans routes. routes est une table plate associant un sous-domaine à une URL amont, et non une liste.

    cat > config/mcp-proxy.yaml <<EOF
    listen_addr: ":8080"
    log_level: info
    shutdown_timeout: 30s
    tunnel_domain: ${TUNNEL_DOMAIN}
    tls:
      cert_file: /data/tls.crt
      key_file: /data/tls.key
    routes:
      echo: http://hello-mcp:9000
    EOF

    La route echo: cible le serveur MCP d'exemple ; remplacez-la par vos propres routes (ou ajoutez-les). Consultez la référence de configuration du proxy pour tous les champs disponibles.

  5. Démarrer le déploiement

    export TUNNEL_TOKEN=$(sudo cat data/tunnel-token)
    docker compose up -d

Le fichier compose lit TUNNEL_TOKEN depuis l'environnement de l'hôte sans valeur par défaut, de sorte que l'export doit être répété dans chaque nouveau shell et après un redémarrage.

Pour un déploiement multi-VM, copiez le répertoire mcp-tunnel/ sur chaque hôte, définissez TUNNEL_TOKEN et exécutez docker compose up -d. Dans le flux programmatique, TUNNEL_TOKEN vaut $(sudo cat data/tunnel-token) ; dans le flux manuel, il s'agit de la valeur que vous avez copiée depuis la Console. Le même jeton de tunnel et les mêmes certificats fonctionnent sur toutes les répliques.

Vérifier le déploiement

Vérifiez de bout en bout en appelant un serveur MCP amont (upstream MCP server) depuis le côté d'Anthropic : consultez Utiliser les serveurs MCP tunnelisés. Avec le serveur MCP d'exemple, l'URL routée est https://echo.<your-tunnel-domain>/mcp. Si la vérification échoue, consultez Dépannage.

Mises à niveau

Exécutez les commandes de cette section depuis le répertoire de déploiement mcp-tunnel/.

Effectuer la rotation du jeton du tunnel

Avec l'accès programmatique, incrémentez --token-version dans la commande du service setup, définissez les identifiants Workload Identity Federation, émettez un nouveau JWT OIDC et réexécutez le composant de configuration :

# Modifiez docker-compose.yaml : incrémentez l'entier dans l'argument
# --token-version du service setup (par exemple, de --token-version=1 à
# --token-version=2). Le binaire setup refuse la rotation lorsque la valeur
# n'a pas changé.

# export TUNNEL_ID=tnl_...   # à définir uniquement si vous l'avez défini lors de l'installation
export ANTHROPIC_FEDERATION_RULE_ID=fdrl_...
export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000
# export ANTHROPIC_WORKSPACE_ID=wrkspc_...   # si votre règle est limitée à un espace de travail
# Régénérez ANTHROPIC_IDENTITY_TOKEN selon le guide du fournisseur WIF pour votre
# environnement (il aura expiré depuis l'installation).
export ANTHROPIC_IDENTITY_TOKEN=...

docker compose run --rm setup

export TUNNEL_TOKEN=$(sudo cat data/tunnel-token)
docker compose up -d cloudflared

L'argument --token-version est modifié dans docker-compose.yaml plutôt que passé en ligne de commande afin que la nouvelle valeur persiste pour les exécutions futures du composant de configuration. Le composant de configuration s'authentifie avec Workload Identity Federation ; il n'y a pas de jeton API à révoquer.

Sans accès programmatique, cliquez sur Rotate token sur la page de détail du tunnel dans la Console, puis mettez à jour la variable d'environnement TUNNEL_TOKEN sur chaque hôte et redémarrez cloudflared (docker compose up -d cloudflared).

Renouvellement des certificats

Il vous incombe de surveiller l'expiration et de renouveler le certificat serveur avant qu'il n'expire.

Avec l'accès programmatique :

docker compose run --rm setup renew-cert --output=dir:/data

Les arguments CLI remplacent la command du service setup (les arguments init) mais conservent son entrypoint, de sorte que cela exécute /setup renew-cert --output=dir:/data.

Sans accès programmatique, signez un nouveau certificat serveur avec votre CA existante (la CA enregistrée dans la Console ne change pas) et remplacez data/tls.crt. Définissez d'abord TUNNEL_DOMAIN si vous exécutez ceci depuis un nouveau shell.

export TUNNEL_DOMAIN=YOUR_TUNNEL_DOMAIN_HERE
openssl req -new -key 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

Dans les deux flux, le proxy interroge tls.cert_file et le recharge automatiquement, de sorte qu'aucun redémarrage n'est nécessaire.

Étapes suivantes

Rattachez un serveur MCP amont à un Managed Agent ou à l'API Messages.

Conseils de durcissement, rotation des identifiants et réponse aux violations.

Diagnostiquez les problèmes de connectivité, de TLS et de routage.

Was this page helpful?