MCP tunnelsのアーキテクチャ — トンネルスタックの構成要素
MCP tunnelsを構成するProxy・cloudflared・Setup componentの役割と、資格情報の受け渡し方、接続の向きが逆転する仕組みを解説します。
MCP tunnelsとは何か
MCP tunnelsは、Host・Client・Serverの三層構造を持つMCPのうち、プライベートネットワーク内で動くMCPサーバーへ、インバウンドのポートを一切開けずにClaudeを接続する機能です。トラフィックはアウトバウンド専用の接続を通ります。ファイアウォールの受信ポート開放も、Anthropicのアクセス元IPレンジの許可リスト登録も要りません。
接続先の実行環境としては、Managed Agentsのセッションと、Messages APIのMCP接続の両方から使えます。Consoleで作ったトンネルはClaude.aiのコネクタには出てきません。
MCP tunnelsはResearch Previewの段階で、利用には申請が必要です。稼働率・サポート・継続性のいずれにも約束は無く、トランスポートはCloudflareという第三者プロバイダーに依存し、Anthropicはいつでも仕様を変えたり提供を終えたりできる条件です。
トンネルスタックを構成する5つの用語
構成要素には複数の呼び名が飛び交います。正式名称と別名の対応を先に押さえておくと、設定ファイルやログを読み違えません。
| 用語 | 役割 | 設定ファイルやイメージでの別名 |
|---|---|---|
| Proxy | 役割Anthropicが実装するルーティング担当。内部TLSを終端し、宛先IPが許可レンジ内かを検証し、ホスト名でアップストリームへ振り分ける | 設定ファイルやイメージでの別名イメージ名mcp-proxy、設定パス/etc/mcp-gateway/config.yaml |
| cloudflared | 役割Cloudflareが提供するオープンソースのトンネルコネクタ。アウトバウンド接続の起点になる | 設定ファイルやイメージでの別名「outbound connector」「tunnel connector」とも呼ばれる |
| Setup component | 役割mcp-proxyイメージに同梱されるsetupバイナリ。プログラム的アクセス時にWIFで認証し、トンネルトークンの取得とCA証明書の発行・登録まで自動化する。証明書の更新用にrenew-certも持つ | 設定ファイルやイメージでの別名Helmのpre-installフックJob、Composeのsetupサービス |
| Tunnel edge | 役割cloudflaredが接続するCloudflareのエッジサーバー群(198.41.192.0/19、2606:4700:a0::/44、ポート7844) | 設定ファイルやイメージでの別名「the edge」 |
| Upstream MCPサーバー | 役割Proxyがルーティングする、プライベートネットワーク内の実際のMCPサーバー。1台が、トンネルドメイン配下のサブドメイン1つに対応する | 設定ファイルやイメージでの別名「upstream」「routed MCP server」 |
Proxyとcloudflaredの2コンテナが「トンネルスタック」の実体で、1スタックが1トンネルに対応します。可用性を上げたければ、同じスタックを複数ホストに複製できます。cloudflaredという名前からManaged Agentの一部に見えますが、Managed Agentとは無関係のコネクタです。
資格情報の受け渡し方 — 2つのモード
トンネルスタックが起動時に必要とする資格情報は2つです。cloudflaredのアウトバウンド接続を認証するトンネルトークンと、Proxyが内部TLSのハンドシェイクで提示するサーバー証明書(トンネルに登録済みのCAで署名されたもの)。受け渡し方は次の2モードで、Helmチャートでは設定値のsetup.enabledがそのまま切り替えスイッチです。
資格情報の受け渡し2モード
プログラム的アクセス
Setup componentがWorkload Identity Federation(WIF)でTunnels APIへ認証します。トンネルトークンの取得、CAとサーバー証明書の生成、CAの登録までを自動で進めるので、長期のシークレットを手でコピーする工程がありません。workspace:manage_tunnelsスコープを持つ連合ルールが前提です。
手動
Consoleからトンネルトークンをコピーし、opensslなどでCAとサーバー証明書を自分で作ってConsoleにCAを登録します。トークンと証明書はシークレットとしてスタックに渡し、Setup componentは動きません。
プログラム的アクセスにはKubernetesやクラウドIAMなど、OIDCトークンを出せるIdPが要ります。IdPを持たない環境や動作確認では手動モードが現実的な入口です。WIFのトークン交換に失敗したときは、Tunnels API側の403の意味が切り分けの手がかりになります。交換自体は成功しているのに403が返るなら、連合ルールのスコープにworkspace:manage_tunnelsが無いか、ルールのサービスアカウントがトンネルのワークスペースに入っていません。
接続の向きとリクエストの向きが逆転する仕組み
トンネルには2つの「向き」があり、互いに逆を向いています。接続の向きはcloudflaredからトンネルエッジへのアウトバウンドで、ファイアウォールが目にするのはポート7844の外向き通信だけです。リクエストの向きは、接続が確立したあとにAnthropic側からプライベートネットワーク側へ流れるMCPリクエストです。「アウトバウンド専用」は接続の向きを指しており、リクエストまでアウトバウンドという意味ではありません。
1本のMCPリクエストが通る経路
- 1
cloudflaredが外向きに接続を張る
プライベートネットワーク内のcloudflaredが、ポート7844でトンネルエッジへ接続します。この接続は開いたままで、受信ポートは開きません。
- 2
Anthropicのバックエンドがリクエストを送る
MCPリクエストはエッジに届き、開いたままの接続に載ってcloudflaredへ運ばれます。この区間は外側のmTLSで守られます。
- 3
cloudflaredがProxyへ渡す
cloudflaredはリクエストを
localhost:8080のProxyへ渡します。Proxyで内部TLSが終わり、ここで初めてMCPの中身が読めます。 - 4
Proxyがホスト名で振り分ける
Proxyはホスト名から上流のMCPサーバーを選んで転送します。レスポンスは同じ経路を逆にたどってAnthropicへ戻ります。
内部TLSはAnthropicのバックエンドとProxyの間だけで完結します。途中のcloudflaredとトンネルエッジには暗号化されたバイト列しか見えません。
この構造は、Proxyのポートへ手でアクセスすると表に出ます。curl https://<proxy>:8080はwrong version numberで失敗します。8080番の待ち受けはTLSではなく平文のWebSocketで、TLSはそのストリームの内側で張られるためです。この失敗は異常ではありません。疎通はManaged AgentかMessages API経由で試します。
cloudflaredの接続先がProxyに向いていないと、呼び出し側にはHTTP 500が返り、cloudflaredのログにNo ingress rules were definedが出ます。Composeでは、cloudflaredのサービスに--url http://localhost:8080とnetwork_mode: "service:mcp-proxy"を足す対処です。
Proxyの経路制御とIP検証という設計
Proxyの設定ファイル(Composeなら/etc/mcp-gateway/config.yaml、Helmならレンダリング済みConfigMap)は、routesにサブドメインとアップストリームURLのマップを持ちます。ここには実装上の落とし穴が2つあります。
1つ目は、routesがマップ型でなければならない点です。リスト形式で書くと、起動時にcannot unmarshal !!seq into map[string]stringで落ちます。
# 正しい: マップ
routes:
echo: http://hello-mcp:9000
# 誤り: リスト形式は起動時にエラー
routes:
- echo: http://hello-mcp:90002つ目は、アップストリームの値がscheme://host:portの形で、ポートが必須な点です。パスを付けると設定の読み込み時にinvalid upstream (must be scheme://host:port)で弾かれます。パスはルート側ではなく、呼び出し側のURLに書きます。ホスト名が一致するかだけで行き先が決まり、リクエストのパスとクエリは上流へそのまま転送されます。
ホスト名の照合は、完全一致を先に試し、次にtunnel_domainの末尾を除いたサブドメインで照合する順です。tunnel_domainを設定しておけば、routesのキーはwikiのような短いサブドメインで書けます。空のままなら、キーは完全なホスト名にします。
https://のアップストリームには、upstream.tls.ca_fileかupstream.tls.include_system_casのどちらかが要ります。どちらも無いと、Proxyは上流の証明書を検証する足場を持てません。
もう1つの安全設計が、アップストリームIPの検証です。ProxyはSSRF対策として、既定ではRFC1918のプライベートアドレス空間(10.0.0.0/8・172.16.0.0/12・192.168.0.0/16)にしか接続しません。IPv4のみの対応です。社内システムがこの範囲外のアドレスを使うなら、upstream.allowed_ipsで広げます。
upstream:
allowed_ips:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
- 10.96.0.0/12 # 例: 追加したい範囲(値は環境ごとに異なる)ここで見落としやすいのが、allowed_ipsが既定の範囲を置き換える点です。足したい範囲だけを書くと、他の上流が使っているプライベートレンジまで拒否されます。Kubernetesではマネージド環境のService CIDRがRFC1918の外にあることがあり、その場合はIP validation failed: <ip> is not a private addressが出ます。
IP検証を丸ごと切るupstream.disable_ip_validationは、allowed_ipsとは同時に使えません。allowed_ipsに0.0.0.0/0を入れてもSSRF対策は無効になり、Proxyが届く範囲はIPv4アドレス全体に広がります。ローカルでの試験を除き、避ける設定です。
ネットワーク要件と証明書のライフサイクル
構成要素ごとに、外向きの通信先が固定されています。Setup componentはapi.anthropic.comのポート443へ、cloudflaredはトンネルエッジのポート7844(TCPとUDP)へ、Proxyは設定した各アップストリームMCPサーバーへ接続します。ファイアウォールのルールを事前に用意するなら、この3行がそのままチェックリストです。
# Setup componentが必要とする経路の疎通確認(ポート443)
curl -sS -o /dev/null -w "%{http_code}\n" https://api.anthropic.comcloudflaredが「Tunnel won't connect」の状態になる原因は、TUNNEL_TOKENの欠落・期限切れ・コピーミスか、7844番の外向き通信の遮断が中心です。UDPの受信バッファに関する警告は、QUICの調整ヒントでエラーではありません。
証明書には2種類あり、ライフサイクルが違います。CAは1トンネルに最大2枚まで有効にでき、この上限がダウンタイムなしのローテーションを可能にします。サーバー証明書は登録済みのCAから直接署名され、中間CAは挟めません。SANは*.<tunnel-domain>に一致する必要があります。
Setup componentが自動生成する証明書の既定値
CA
ECDSA P-256
有効期間5年
サーバー証明書
RSA 4096
有効期間90日・ワイルドカードSAN
登録するCA
PEM形式
1枚8kBまで
自前のPKIで発行するときのCAは、RSA 2048ビット以上かECDSA P-256以上で、BasicConstraintsにCA:TRUEが必須です。90日のサーバー証明書は、更新を定期ジョブにしておかないと期限切れで内部TLSが落ちます。自動生成を使う構成なら、setup renew-certがAPI呼び出しなしで保存済みのCAから新しい証明書を発行します。--renew-before=720hを付けると、残り30日を超えていれば何もしないため、固定スケジュールで回しても安全です。
Tunnels REST APIは/v1/tunnelsにあり、トンネルの作成・一覧・アーカイブ、CA証明書の登録、トンネルトークンの開示・ローテーションを担います。すべてのエンドポイントはworkspace:manage_tunnelsスコープを持つWIF発行のBearerトークンを要求し、Admin APIキーでは呼べません。
以前のAdmin API面(/v1/organizations/tunnels、betaヘッダーmcp-tunnels-2026-05-19)は、移行期間中は動きますが非推奨です。新しい面ではパスが/v1/tunnels、betaヘッダーがmcp-tunnels-2026-06-22、WIFのスコープがworkspace:manage_tunnelsに変わります。認証ヘッダーの具体的な指定方法やconfig.yamlの各項目、setupコマンドのフラグはMCP tunnelsリファレンスにまとめています。
3層防御と、障害を切り分ける順序
MCP tunnelsは3層の独立した防御を積み重ねています。トンネルエッジへの到達を検証する外部mTLSとIP検証、Cloudflareのネットワークを越えてもペイロードを読ませない内部TLS、認証済みトンネル経由でも各MCPサーバーが要求するOAuthです。トンネルを通れることは、MCPツールの利用許可を意味しません。トンネルが運ぶのは暗号化されたトラフィックで、上流のMCPサーバーへの認証まではしないからです。
障害の切り分けも、この層構造に沿います。接続、内部TLS、ルーティングと上流IPの順に調べると、ログの文言から原因の層を当てられます。
| 層 | 見るログ | 文言と原因 |
|---|---|---|
| 接続(cloudflared) | 見るログcloudflaredのログ | 文言と原因No ingress rules were definedは接続先の未設定。7844番の遮断やトークン不備では接続自体が張れない |
| 内部TLS | 見るログProxyのログ | 文言と原因tls handshake failedは、サーバー証明書の期限切れ、SANと*.<tunnel-domain>の不一致、署名CAの未登録のいずれか |
| ルーティング | 見るログProxyのログ | 文言と原因no route for hostはtunnel_domainの不一致か、設定を編集したあとの再起動漏れ。IP validation failedは上流が許可範囲の外 |
Proxyがopen /data/tls.key: permission deniedで終了するときは、秘密鍵のパーミッションが0600で、非rootのProxyコンテナが読めていません。公式の手順はchmod 644ですが、鍵を他のユーザーにも読ませる変更になるため、置き場所のアクセス制限と合わせて決める必要があります。
また、Consoleで作ったトンネルがManaged Agentsの「+ MCP Server」の選択肢に出ないときは、有効なCA証明書が無いか、セッションのワークスペースがトンネルのものと違います。
責任分界は明確です。Anthropicはトンネルへのアクセス制御とCA証明書の検証、自社組織が所有するトンネルにしかリクエストを送らないことを保証します。トンネルを通る内容、Cloudflareの利用規約の遵守、トークンとTLS秘密鍵の保管、証明書の更新、各MCPサーバーのOAuth設定、ProxyとMCPサーバーのネットワーク制限は、利用組織の担当です。
トンネルトークンとTLS秘密鍵の両方を奪われると、Proxyになりすましてペイロードを読める状態になります。この2つは高価値のシークレットとして扱います。侵害を疑ったときの確認手順とトンネルの廃止手順はMCP tunnelsのセキュリティにまとめています。
なぜCloudflareを挟んでも中身が読まれないのか
トランスポートに第三者を使いながら中身を読ませない設計は、責任の置き場所をずらした結果です。Cloudflareが担うのは、暗号化された接続の運搬だけです。cloudflaredとエッジが目にするのは、cloudflaredを動かすホストの外向きIP・ホストのフィンガープリント・接続のタイミングとバイト量・割り当てられたサブドメインに限られます。ペイロードの復号鍵はProxyの秘密鍵の中にしか無く、Cloudflareには渡りません。
もう1つの仕掛けが、接続の順序です。AnthropicはCA証明書が登録されるまでトンネルに接続しません。このため、平文のペイロードがCloudflareのネットワークを通る瞬間は作られません。Cloudflareはこの研究プレビューではサブプロセッサーの位置づけで、メタデータの利用はAnthropicとの契約で制限されています。
これは「信頼できるトランスポート事業者を選ぶ」代わりに、「事業者を信頼しなくてよい構造にする」という選択です。接続の確立(cloudflaredの認証)・内部TLSの検証(証明書の一致)・各MCPサーバーのOAuthを、別々の関門として置いています。関門が増えるぶん運用の手間は増えます。この3つの関門が成り立つ前提は、トークンと秘密鍵を同時に奪われないことです。
まとめ
ポート開放も許可リスト登録も避けたいが、ペイロードはProxyまで暗号化したまま届けたい。MCP tunnelsはその要件に合わせた構成です。一方で稼働保証が無いResearch Previewなので、可用性が要る経路へ載せるかどうかは、保証条件が示されてからの判断になります。
手を動かして最短経路で1本のトンネルを立てる手順は、MCP tunnelsのクイックスタートにまとめています。