注意

MCP 隧道处于研究预览阶段。

MCP 隧道处于研究预览阶段。它们按“原样”提供,不附带任何正常运行时间、支持或连续性承诺,并依赖于第三方网络提供商(Cloudflare),该提供商不对底层传输作任何可用性承诺。Anthropic 可随时修改或停止 MCP 隧道。

MCP 隧道(MCP tunnels)让您可以将 Claude 连接到运行在您私有网络内部的 “Model Context Protocol”,即 MCP 服务器。流量通过仅出站的连接传输,因此您无需开放入站防火墙端口、将服务暴露到公共互联网,或在您的源站上将 Anthropic 的 IP 范围加入允许列表。

工作原理

隧道栈(tunnel stack)由运行在您网络内部的两个组件组成:

  • cloudflared: Cloudflare 的开源隧道连接器。它发起到隧道边缘(tunnel edge)的仅出站连接,并将来自 Anthropic 的加密流量传送到您的代理。
  • 代理(Proxy): Anthropic 的路由组件。它终止内层 TLS(inner TLS),验证上游 IP 是否位于允许的范围内,并根据主机名将每个请求路由到正确的上游 MCP 服务器。

您暴露的每个 MCP 服务器都会在您的隧道域名下获得一个主机名(例如 docs.<your-tunnel-domain>)。您可以在 Claude Console 中将这些主机名附加到智能体,或通过 MCP 连接器将它们传递给 Messages API。

前提条件

在部署之前,请确保您具备:

  • 一个部署目标:Kubernetes 集群,或安装了 Docker 和 Docker Compose 的虚拟机。

  • 一个隧道。在 Claude Console 中创建一个(请参阅创建隧道)或通过 API 创建;Helm chart 的设置钩子也可以在安装期间为您创建一个。

  • 一种让您的栈向 Tunnels API 进行身份验证的方式。选择其一:

    • 编程式访问(推荐)。 在创建隧道时设置 Workload Identity Federation(工作负载身份联合)。您的栈从您的身份提供商签发短期 API 令牌,获取隧道令牌,并自动生成和注册 CA 证书。需要管理联合规则的权限、一个已注册的 OIDC 颁发者,以及一条具有 workspace:manage_tunnels 作用域的联合规则。
    • 手动。 自行提供静态凭据:来自 Console 的隧道令牌,以及由您在其中注册的 CA 签名的服务器证书。请参阅获取连接详情和添加 CA 证书。
  • 一个或多个运行在您私有网络中的 MCP 服务器。示例请参阅远程 MCP 服务器。

  • 网络要求中列出的出站连接能力。

网络要求

组件 目标 端口 / 协议 使用阶段
设置组件 api.anthropic.com 443 TCP 配置和令牌轮换
cloudflared 隧道边缘(198.41.192.0/19、2606:4700:a0::/44) 7844 TCP 和 UDP 运行时
代理 您的上游 MCP 服务器 按配置 运行时

安全模型

安全层

三个独立的层保护每个请求:

层 防护对象
Anthropic 与传输提供商之间的外层 mTLS,带 IP 验证 未经授权的客户端访问隧道
从 Anthropic 后端到您的代理的内层 TLS 传输提供商或任何网络中间方对有效负载的检查
每个 MCP 服务器上的 OAuth 已通过身份验证的隧道流量对 MCP 工具的未授权使用

隧道传输运行在 Cloudflare 的网络上。由于代理使用只有您持有的证书终止内层 TLS,Cloudflare 无法读取请求或响应的有效负载。在注册 CA 证书之前,Anthropic 不会连接到隧道,因此有效负载在穿越 Cloudflare 网络时始终是加密的。Cloudflare 确实会接收连接元数据;请参阅传输提供商可以观察到的内容。

责任共担模型

Anthropic 负责 您的组织负责
隧道访问控制 通过您的隧道传输的所有内容和流量,以及遵守适用的第三方可接受使用政策(包括 Cloudflare 的)
在连接到您的代理之前验证您的 CA 证书 遵守这些页面上的部署指南
确保 Claude 仅向您的组织拥有的隧道发送请求 保护隧道令牌和 TLS 私钥
管理服务器证书并在其过期前续期
在每个 MCP 服务器上配置 OAuth
限制代理和 MCP 服务器的网络访问
如果您怀疑发生泄露,通知 Anthropic

警告

如果攻击者获得了您的隧道令牌以及您的某个 TLS 私钥,他们就可以冒充您的代理并读取 MCP 请求有效负载。请将两者都视为高价值机密。有关加固指南,请参阅 MCP 隧道安全。

传输提供商可以观察到的内容

Cloudflare 提供出站传输。它无法读取 MCP 请求或响应的有效负载,但确实会接收以下连接元数据:

  • 运行 cloudflared 的主机的出口 IP 地址
  • cloudflared 主机指纹
  • 连接时序和字节量
  • 分配给您隧道的 *.tunnel.anthropic.com 子域名

Anthropic 与 Cloudflare 的协议限制了 Cloudflare 对这些遥测数据的使用。Cloudflare 在本研究预览中充当子处理方。

部署隧道

如果您是 MCP 隧道的新用户,请先从快速入门开始,在本地获得一个可用的隧道,然后再配置生产部署。

如何在它们之间选择:

  • 部署目标

    • 部署到 Kubernetes 时使用 Helm
    • 单台主机或本地测试时使用 Docker Compose
  • 设置阶段的身份验证

    • 当您拥有 OIDC 身份提供商(例如 Kubernetes 集群、云 IAM 或 SPIFFE)时,使用程序化访问(通过 Workload Identity Federation)
    • 当您没有此类提供商或正在测试时,使用手动凭据

使用通过隧道连接的 MCP 服务器

一旦您的隧道处于活动状态(它拥有一个活动的 CA 证书并且您的隧道栈已连接),上游 MCP 服务器即可从 Claude Managed Agents 和 Messages API 访问。

注意

通过 Console 创建的 MCP 隧道不能作为 claude.ai 中的连接器使用。

在这两种情况下,隧道都会将加密流量传送到您的 MCP 服务器,但不会向其进行身份验证。如果上游 MCP 服务器需要自己的身份验证(OAuth、bearer 令牌),请按照您对任何其他 MCP 服务器的方式提供;它与隧道无关。

Managed Agents(Console)

  1. 在 Claude Console 的 Sessions 页面(platform.claude.com/sessions)上,创建一个会话并选择 Create new agent,以便编辑 MCP 服务器列表。
  2. 在 MCP servers 下,点击 MCP server 并打开下拉菜单。会话工作区中至少拥有一个有效证书的隧道会显示在列表顶部,位于公共连接器目录之上。
  3. 选择隧道,并提供您的代理路由到特定 MCP 服务器的 Subdomain(子域名),以及上游 MCP 服务器期望的 Path(路径)。Resolves to 行会显示确切的 URL。

有关完整步骤,请参阅在智能体中使用隧道。

Messages API

在 mcp_servers 数组中传入上游 MCP 服务器的 URL,方式与任何其他远程 MCP 服务器相同。请求体和 anthropic-beta 标头遵循标准的 MCP 连接器格式;只有 url 是隧道特有的。以下示例使用 MCP 连接器的 mcp-client beta 标头,它与 Tunnels API 使用的 mcp-tunnels beta 是分开的。请在创建隧道的工作区中发出请求:使用该工作区的 API 密钥,或者如果您的密钥不限定于某个工作区,则将 anthropic-workspace-id 标头设置为该工作区。

URL 的主机为 <subdomain>.<your-tunnel-domain>。路径取决于您的上游 MCP 服务器,而不是隧道:FastMCP 的 streamable-http 传输在 /mcp 提供服务,其他服务器可能使用 / 或自定义路径(请查看服务器的文档)。代理会原样转发路径。

cURL

curl https://api.anthropic.com/v1/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: mcp-client-2025-11-20" \
  -d '{
    "model": "claude-opus-5-5",
    "max_tokens": 1000,
    "messages": [{"role": "user", "content": "Use the hello tool to greet tunnel."}],
    "mcp_servers": [
      {
        "type": "url",
        "url": "https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp",
        "name": "echo"
      }
    ],
    "tools": [{"type": "mcp_toolset", "mcp_server_name": "echo"}]
  }'

CLI

ant beta:messages create --beta mcp-client-2025-11-20 <<'YAML'
model: claude-opus-5-5
max_tokens: 1000
messages:
  - role: user
    content: Use the hello tool to greet tunnel.
mcp_servers:
  - type: url
    url: https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp
    name: echo
tools:
  - type: mcp_toolset
    mcp_server_name: echo
YAML

Python

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=1000,
    messages=[{"role": "user", "content": "Use the hello tool to greet tunnel."}],
    mcp_servers=[
        {
            "type": "url",
            "url": "https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp",
            "name": "echo",
        }
    ],
    tools=[{"type": "mcp_toolset", "mcp_server_name": "echo"}],
    betas=["mcp-client-2025-11-20"],
)

print(response)

TypeScript

const anthropic = new Anthropic();

const response = await anthropic.beta.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 1000,
  messages: [
    {
      role: "user",
      content: "Use the hello tool to greet tunnel."
    }
  ],
  mcp_servers: [
    {
      type: "url",
      url: "https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp",
      name: "echo"
    }
  ],
  tools: [
    {
      type: "mcp_toolset",
      mcp_server_name: "echo"
    }
  ],
  betas: ["mcp-client-2025-11-20"]
});

console.log(response);

C#

AnthropicClient client = new();

var parameters = new MessageCreateParams
{
    Model = Messages::Model.ClaudeOpus5_5,
    MaxTokens = 1000,
    Messages = new List<BetaMessageParam>
    {
        new BetaUserMessageParam { Content = "Use the hello tool to greet tunnel." }
    },
    McpServers = new List<BetaRequestMcpServerUrlDefinition>
    {
        new()
        {
            Url = "https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp",
            Name = "echo"
        }
    },
    Tools = new List<BetaToolUnion>
    {
        new BetaMcpToolset("echo")
    },
    Betas = ["mcp-client-2025-11-20"]
};

var message = await client.Beta.Messages.Create(parameters);
Console.WriteLine(message);

Go

client := anthropic.NewClient()

response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
	Model:     anthropic.ModelClaudeOpus5_5,
	MaxTokens: 1000,
	Messages: []anthropic.BetaMessageParam{
		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Use the hello tool to greet tunnel.")),
	},
	MCPServers: []anthropic.BetaRequestMCPServerURLDefinitionParam{
		{
			URL:  "https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp",
			Name: "echo",
		},
	},
	Tools: []anthropic.BetaToolUnionParam{
		{OfMCPToolset: &anthropic.BetaMCPToolsetParam{
			MCPServerName: "echo",
		}},
	},
	Betas: []anthropic.AnthropicBeta{
		anthropic.AnthropicBetaMCPClient2025_11_20,
	},
})
if err != nil {
	log.Fatal(err)
}
fmt.Println(response)

Java

import com.anthropic.models.beta.messages.BetaMcpToolset;
// ...
import com.anthropic.models.beta.messages.BetaRequestMcpServerUrlDefinition;
// ...

void main() {
    AnthropicClient client = AnthropicOkHttpClient.fromEnv();

    MessageCreateParams params = MessageCreateParams.builder()
        .model(Model.CLAUDE_OPUS_5_5)
        .maxTokens(1000L)
        .addUserMessage("Use the hello tool to greet tunnel.")
        .addMcpServer(BetaRequestMcpServerUrlDefinition.builder()
            .url("https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp")
            .name("echo")
            .build())
        .addTool(BetaMcpToolset.builder()
            .mcpServerName("echo")
            .build())
        .addBeta("mcp-client-2025-11-20")
        .build();

    BetaMessage response = client.beta().messages().create(params);
    IO.println(response);
}

PHP

$client = new Client();

$message = $client->beta->messages->create(
    maxTokens: 1000,
    messages: [
        ['role' => 'user', 'content' => 'Use the hello tool to greet tunnel.']
    ],
    model: 'claude-opus-5-5',
    mcpServers: [
        [
            'type' => 'url',
            'url' => 'https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp',
            'name' => 'echo',
        ],
    ],
    tools: [
        [
            'type' => 'mcp_toolset',
            'mcpServerName' => 'echo',
        ],
    ],
    betas: ['mcp-client-2025-11-20'],
);

echo $message;

Ruby

client = Anthropic::Client.new

response = client.beta.messages.create(
  model: "claude-opus-5-5",
  max_tokens: 1000,
  messages: [
    { role: "user", content: "Use the hello tool to greet tunnel." }
  ],
  mcp_servers: [
    {
      type: "url",
      url: "https://echo.YOUR_TUNNEL_DOMAIN_HERE/mcp",
      name: "echo"
    }
  ],
  tools: [
    {
      type: "mcp_toolset",
      mcp_server_name: "echo"
    }
  ],
  betas: ["mcp-client-2025-11-20"]
)

puts response

有关向上游 MCP 服务器进行身份验证(authorization_token)以及其他 mcp_servers 选项,请参阅 MCP 连接器。

后续步骤

  • 安全:加固指南、凭据轮换和泄露响应。

  • 故障排除:诊断连接、TLS 和路由问题。

  • 参考:代理配置字段、Tunnels API、证书要求和设置组件。

  • MCP 连接器:从 Messages API 使用通过隧道连接的服务器。

可用性

MCP 隧道在所有模型上处于研究预览阶段。

API 支持

Messages API

  • 可用性:可用
状态 云平台
研究预览 Claude API

Managed Agents

  • 可用性:可用
状态 云平台
研究预览 Claude API

所需的 beta 请求头

Beta 请求头概览

Beta 请求头让您可以在实验性功能和新模型能力成为标准 API 的一部分之前访问它们。

请求头 API
mcp-client-2026-09-15或mcp-client-2025-11-20 Messages API

数据处理

数据处理概览

项目 零数据保留 HIPAA
状态 不具备资格 不具备资格
详细信息 研究预览。MCP 隧道安全页面介绍了数据流边界和子处理方详情。 了解更多 —

适用的端点:

  • /v1/tunnels