Claude Platform Docs
MessagesMCPトンネル

Docker ComposeでMCPトンネルをデプロイする

Docker Composeを使用してVMにMCPトンネルスタックをインストールします。

このガイドでは、トンネルスタックを単一ホスト上に堅牢化されたコンテナとしてデプロイします。可用性のために、同じ構成を複数のホストに複製することもできます。

始める前に

以下が必要です。

  • トンネル。 プログラムによるアクセスを使用する場合、トンネルIDを指定しなければセットアップコンポーネントがトンネルを作成します。既存のトンネルにアタッチする場合は、Consoleでトンネルを作成し、トンネルID(tnl_...)を記録してください。手動プロビジョニングは常にConsoleで作成したトンネルから始まります。
  • ホストがTunnels APIに対して認証する手段。
    • プログラムによるアクセス(推奨)。 トンネル作成時に Set up programmatic access をオンにして(またはセットアップコンポーネントにトンネルを作成させる場合は Settings > Workload identity でフェデレーションルールを直接作成して)、セットアップコンポーネントがWorkload Identity Federationを通じて認証できるようにします。フェデレーションルールID(fdrl_...)と組織IDを記録してください。
    • 手動。 プログラムによるアクセスをスキップします。Consoleからトンネルトークンを取得し、CAとサーバー証明書を自分で生成して、ConsoleにCAを登録します。
  • DockerとDocker Composeがインストールされたホスト。 手動フローでは openssl(1.1.1以降)も必要です。
  • ホストから api.anthropic.com(443 TCP)およびトンネルエッジ(7844 TCPおよびUDP)へのアウトバウンドネットワーク接続。完全なネットワーク要件を参照してください。
  • routes で設定するアドレスでホストから到達可能な、稼働中の1つ以上のMCPサーバー。まだない場合は、サンプルサーバーを使用してください。

オプション:サンプルMCPサーバーを使用する

テスト用のMCPサーバーがない場合は、この最小限のサーバーを使用してください。

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

以下のインストール手順では mcp-tunnel/cd し、対応するサービスとルートを追加する場所を示します。

インストール

このガイドでは、Docker Composeを使用した1つの参考アプローチを提供します。組織のセキュリティ要件を満たすように適応させる責任はお客様にあります。

このパスでは、ホストにOIDCアイデンティティプロバイダー(クラウドVMメタデータサーバーやSPIFFEなど)が必要です。ない場合は、代わりに プログラムによるアクセスなし タブを使用してください。

セットアップコンポーネントはWorkload Identity Federationを使用してトンネルトークンを取得し、CAとサーバー証明書を生成して、CAをAnthropicに登録します。

  1. デプロイディレクトリを準備する

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

    コンテナは非rootのUID 65532 として実行され、data/ への書き込みアクセスが必要です。

  2. docker-compose.yamlを作成する

    このcomposeファイルは、イメージをSHA-256ダイジェストで固定し、すべてのコンテナを読み取り専用ファイルシステムで非rootとして実行し、すべてのLinuxケーパビリティを削除し、権限昇格を無効にします。

    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
        # プロキシのnetnsを共有し、localhost:8080で到達できるようにします。
        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

    サンプルMCPサーバーを使用している場合は、サービスとして追加してください。

    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. トンネルをプロビジョニングする

    識別子を設定します。セットアップコンポーネントにトンネルを作成させる場合は TUNNEL_ID を未設定のままにし、Consoleの既存のトンネルにアタッチする場合は設定してください。

    # export TUNNEL_ID=tnl_...   # 既存のトンネルに接続する場合に設定
    export ANTHROPIC_FEDERATION_RULE_ID=fdrl_...
    export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000

    フェデレーションルールが組織のデフォルト以外のワークスペースにスコープされている場合は、ANTHROPIC_WORKSPACE_ID=wrkspc_... も設定してください。設定しない場合、セットアップコンポーネントはデフォルトのワークスペースを使用します。自動作成されるトンネルはそのワークスペースに作成されます。

    ANTHROPIC_IDENTITY_TOKEN に、このホストのアイデンティティプロバイダーから取得したOIDC JWTを設定します。プロバイダー向けのWIFガイドに従って、発行者を登録し、ルールのサブジェクトを設定し、トークンを発行してください。ルールのオーディエンスは、発行時にリクエストするオーディエンスと一致する必要があります。

    セットアップコンポーネントを実行します。

    docker compose run --rm setup

    setup initdata/ に対して冪等です。再実行すると、すでにそこに保存されているトンネルIDとCAを再利用し、2つ目のトンネルを作成することはありません。新しいCAが生成・登録されるのは、data/ が空の場合または TUNNEL_ID が変更された場合のみです。その場合、アクティブな証明書は2つまでという上限が適用されるため、両方のスロットが埋まっている場合は先にConsoleで1つを失効させてください。

    エラーが発生した場合は、セットアップコンポーネントの認証失敗を参照してください。

    トンネルドメインを取得し、後の手順のためにエクスポートします。

    export TUNNEL_DOMAIN=$(sudo cat data/tunnel-domain)
    echo "$TUNNEL_DOMAIN"
  4. プロキシ設定を作成する

    tunnel_domain必須です。プロキシはこれを使用して、routes でサブドメインを検索する前に、受信ホスト名からドメインサフィックスを取り除きます。routes はサブドメインからアップストリームURLへのフラットなマップであり、リストではありません。

    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

    echo: ルートはサンプルMCPサーバーを対象としています。独自のルートに置き換える(または追加する)ようにしてください。利用可能なすべてのフィールドについては、プロキシ設定リファレンスを参照してください。

  5. デプロイを開始する

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

composeファイルはデフォルト値なしでホスト環境から TUNNEL_TOKEN を読み取るため、新しいシェルを開くたび、および再起動後にエクスポートを繰り返す必要があります。

複数VMへのデプロイでは、mcp-tunnel/ ディレクトリを各ホストにコピーし、TUNNEL_TOKEN を設定して、docker compose up -d を実行します。プログラムによるフローでは TUNNEL_TOKEN$(sudo cat data/tunnel-token) であり、手動フローではConsoleからコピーした値です。同じトンネルトークンと証明書がすべてのレプリカで機能します。

デプロイを検証する

Anthropic側からアップストリームMCPサーバーを呼び出して、エンドツーエンドで検証します。トンネル経由のMCPサーバーを使用するを参照してください。サンプルMCPサーバーを使用している場合、ルーティングされるURLは https://echo.<your-tunnel-domain>/mcp です。検証に失敗した場合は、トラブルシューティングを参照してください。

アップグレード

このセクションのコマンドは、mcp-tunnel/ デプロイディレクトリ内から実行してください。

トンネルトークンをローテーションする

プログラムによるアクセスを使用している場合は、setup サービスのコマンドで --token-version をインクリメントし、Workload Identity Federationの識別子を設定し、新しいOIDC JWTを発行して、セットアップコンポーネントを再実行します。

# docker-compose.yamlを編集: setupサービスの
# --token-version引数の整数をインクリメントします(例: --token-version=1 から
# --token-version=2 へ)。setupバイナリは値が変更されていない場合、
# ローテーションを拒否します。

# export TUNNEL_ID=tnl_...   # インストール時に設定した場合のみ設定
export ANTHROPIC_FEDERATION_RULE_ID=fdrl_...
export ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000
# export ANTHROPIC_WORKSPACE_ID=wrkspc_...   # ルールがワークスペーススコープの場合
# お使いの環境向けのWIFプロバイダーガイドに従ってANTHROPIC_IDENTITY_TOKENを再発行します
# (インストール以降に有効期限が切れているはずです)。
export ANTHROPIC_IDENTITY_TOKEN=...

docker compose run --rm setup

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

--token-version 引数は、セットアップコンポーネントの今後の実行でも新しい値が保持されるように、コマンドラインで渡すのではなく docker-compose.yaml 内で編集します。セットアップコンポーネントはWorkload Identity Federationで認証するため、失効させるAPIトークンはありません。

プログラムによるアクセスを使用していない場合は、Consoleのトンネル詳細ページで Rotate token をクリックし、各ホストで TUNNEL_TOKEN 環境変数を更新してcloudflaredを再起動します(docker compose up -d cloudflared)。

証明書の更新

有効期限を監視し、期限切れになる前にサーバー証明書を更新する責任はお客様にあります。

プログラムによるアクセスを使用している場合:

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

CLI引数は setup サービスの commandinit 引数)を置き換えますが、entrypoint は保持するため、これは /setup renew-cert --output=dir:/data を実行します。

プログラムによるアクセスを使用していない場合は、既存のCAで新しいサーバー証明書に署名し(Consoleに登録されたCAは変更されません)、data/tls.crt を置き換えます。新しいシェルから実行する場合は、先に TUNNEL_DOMAIN を設定してください。

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

どちらのフローでも、プロキシは tls.cert_file をポーリングして自動的に再読み込みするため、再起動は不要です。

次のステップ

アップストリームMCPサーバーをManaged AgentまたはMessages APIにアタッチします。

堅牢化のガイダンス、認証情報のローテーション、侵害への対応。

接続、TLS、ルーティングの問題を診断します。

Was this page helpful?