Claude Platform Docs
MensajesTúneles MCP

Implementa túneles MCP con Docker Compose

Instala la pila de túneles MCP en una VM usando Docker Compose.

Esta guía implementa la pila de túneles como contenedores reforzados en un solo host. La misma configuración se puede replicar en varios hosts para lograr disponibilidad.

Antes de empezar

Necesitas:

  • Un túnel. Con acceso programático, el componente de configuración crea uno por ti cuando no proporcionas un ID de túnel; para conectarte a un túnel existente en su lugar, créalo en la Claude Console y anota el ID del túnel (tnl_...). El aprovisionamiento manual siempre parte de un túnel creado en la Console.
  • Una forma de que el host se autentique ante la Tunnels API.
    • Acceso programático (recomendado). Activa Set up programmatic access al crear el túnel para que el componente de configuración pueda autenticarse mediante Workload Identity Federation. Si dejas que el componente de configuración cree el túnel, crea en su lugar la regla de federación directamente en la página Workload identity (platform.claude.com/settings/workload-identity-federation) de la Claude Console. Anota el ID de la regla de federación (fdrl_...) y el ID de tu organización.
    • Manual. Omite el acceso programático. Obtendrás el token del túnel desde la Console, generarás tú mismo una CA y un certificado de servidor, y registrarás la CA en la Console.
  • Un host con Docker y Docker Compose instalados. El flujo manual también requiere openssl (1.1.1 o posterior).
  • Conectividad de red saliente desde el host hacia api.anthropic.com (443 TCP) y el borde del túnel (7844 TCP y UDP). Consulta los requisitos de red completos.
  • Uno o más servidores MCP en ejecución y accesibles desde el host en las direcciones que configurarás en routes. Si aún no tienes uno, usa el servidor de ejemplo.

Opcional: Usa un servidor MCP de ejemplo

Si no tienes un servidor MCP disponible para pruebas, usa este servidor mínimo:

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

Los siguientes pasos de instalación hacen cd a mcp-tunnel/ e indican dónde agregar el servicio y la ruta correspondientes.

Instalación

Esta guía ofrece un enfoque de referencia usando Docker Compose. Eres responsable de adaptarlo para cumplir con los requisitos de seguridad de tu organización.

Esta ruta requiere que el host tenga un proveedor de identidad OIDC (como un servidor de metadatos de VM en la nube o SPIFFE). Si no lo tiene, usa en su lugar la pestaña Sin acceso programático.

El componente de configuración usa Workload Identity Federation para obtener el token del túnel, generar una CA y un certificado de servidor, y registrar la CA con Anthropic.

  1. Prepara el directorio de implementación

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

    Los contenedores se ejecutan con el UID no root 65532 y necesitan acceso de escritura a data/.

  2. Escribe docker-compose.yaml

    El archivo compose fija las imágenes por digest SHA-256, ejecuta cada contenedor como no root con un sistema de archivos de solo lectura, elimina todas las capacidades de Linux y deshabilita la escalada de privilegios.

    cat > docker-compose.yaml <<'EOF'
    services:
      setup:
        image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:d243d30642d39857a0579e465cb3b9bf3ae7c1141e83143bb6856777a31467a5
        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:0e56c13c7058fcef9c4f0e7d83372f82330548dbf8f8b366f3d8b506526d93b2
        command: tunnel --no-autoupdate run --url http://localhost:8080
        environment:
          - TUNNEL_TOKEN
        # Comparte el netns del proxy para que localhost:8080 llegue a él.
        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:d243d30642d39857a0579e465cb3b9bf3ae7c1141e83143bb6856777a31467a5
        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 usas el servidor MCP de ejemplo, agrégalo como servicio:

    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. Aprovisiona el túnel

    Establece los identificadores. Deja TUNNEL_ID sin definir para que el componente de configuración cree un túnel; defínelo para conectarte a un túnel existente de la Console:

    # export TUNNEL_ID=tnl_...   # configúralo para conectarte a un túnel existente
    export ANTHROPIC_FEDERATION_RULE_ID=fdrl_...
    export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000

    Si tu regla de federación está limitada a un espacio de trabajo distinto del predeterminado de tu organización, establece también ANTHROPIC_WORKSPACE_ID=wrkspc_...; de lo contrario, el componente de configuración usa el espacio de trabajo predeterminado. Un túnel creado automáticamente se crea en ese espacio de trabajo.

    Establece ANTHROPIC_IDENTITY_TOKEN con un JWT OIDC del proveedor de identidad de este host. Sigue la guía de WIF para tu proveedor para registrar el emisor, establecer el sujeto de la regla y emitir el token; la audiencia de la regla debe coincidir con la audiencia que solicitas al emitirlo.

    Ejecuta el componente de configuración:

    docker compose run --rm setup

    setup init es idempotente sobre data/: volver a ejecutarlo reutiliza el ID del túnel y la CA ya almacenados allí y nunca crea un segundo túnel. Solo se genera y registra una nueva CA cuando data/ está vacío o TUNNEL_ID ha cambiado; en ese caso se aplica el límite de dos certificados activos, así que revoca uno en la Console primero si ambos espacios están ocupados.

    Consulta Fallos de autenticación del componente de configuración si se produce un error.

    Obtén el dominio de tu túnel y expórtalo para los pasos posteriores:

    export TUNNEL_DOMAIN=$(sudo cat data/tunnel-domain)
    echo "$TUNNEL_DOMAIN"
  4. Escribe la configuración del proxy

    tunnel_domain es obligatorio: el proxy lo usa para quitar el sufijo de dominio de los nombres de host entrantes antes de buscar el subdominio en routes. routes es un mapa plano de subdominio a URL upstream, no una lista.

    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 ruta echo: apunta al servidor MCP de ejemplo; reemplázala por tus propias rutas (o agrégalas). Consulta la referencia de configuración del proxy para ver todos los campos disponibles.

  5. Inicia la implementación

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

El archivo compose lee TUNNEL_TOKEN del entorno del host sin valor predeterminado, por lo que debes repetir la exportación en cada shell nueva y después de un reinicio.

Para una implementación en varias VM, copia el directorio mcp-tunnel/ a cada host, establece TUNNEL_TOKEN y ejecuta docker compose up -d. En el flujo programático, TUNNEL_TOKEN es $(sudo cat data/tunnel-token); en el flujo manual, es el valor que copiaste de la Console. El mismo token de túnel y los mismos certificados funcionan en todas las réplicas.

Verifica la implementación

Verifica de extremo a extremo llamando a un servidor MCP upstream desde el lado de Anthropic: consulta Usar los servidores MCP tunelizados. Con el servidor MCP de ejemplo, la URL enrutada es https://echo.<your-tunnel-domain>/mcp. Si la verificación falla, consulta Solución de problemas.

Actualizaciones

Ejecuta los comandos de esta sección desde dentro del directorio de implementación mcp-tunnel/.

Rota el token del túnel

Con acceso programático, incrementa --token-version en el comando del servicio setup, establece los identificadores de Workload Identity Federation, emite un JWT OIDC nuevo y vuelve a ejecutar el componente de configuración:

# Edita docker-compose.yaml: incrementa el entero en el argumento
# --token-version del servicio setup (por ejemplo, de --token-version=1 a
# --token-version=2). El binario setup se niega a rotar si el valor
# no ha cambiado.

# export TUNNEL_ID=tnl_...   # configúralo solo si lo configuraste durante la instalación
export ANTHROPIC_FEDERATION_RULE_ID=fdrl_...
export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000
# export ANTHROPIC_WORKSPACE_ID=wrkspc_...   # si tu regla está limitada al espacio de trabajo
# Vuelve a generar ANTHROPIC_IDENTITY_TOKEN según la guía del proveedor WIF para tu
# entorno (habrá expirado desde la instalación).
export ANTHROPIC_IDENTITY_TOKEN=...

docker compose run --rm setup

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

El argumento --token-version se edita en docker-compose.yaml en lugar de pasarse en la línea de comandos para que el nuevo valor persista en futuras ejecuciones del componente de configuración. El componente de configuración se autentica con Workload Identity Federation; no hay ningún token de API que revocar.

Sin acceso programático, haz clic en Rotate token en la página de detalles del túnel en la Console, luego actualiza la variable de entorno TUNNEL_TOKEN en cada host y reinicia cloudflared (docker compose up -d cloudflared).

Renovación de certificados

Eres responsable de supervisar la caducidad y renovar el certificado de servidor antes de que caduque.

Con acceso programático:

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

Los argumentos de la CLI reemplazan el command del servicio setup (los argumentos de init) pero conservan su entrypoint, por lo que esto ejecuta /setup renew-cert --output=dir:/data.

Sin acceso programático, firma un nuevo certificado de servidor con tu CA existente (la CA registrada en la Console no cambia) y reemplaza data/tls.crt. Establece primero TUNNEL_DOMAIN si ejecutas esto desde una shell nueva.

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

En cualquiera de los dos flujos, el proxy consulta periódicamente tls.cert_file y lo recarga automáticamente, por lo que no se requiere reiniciar.

Próximos pasos

Was this page helpful?