使用 Helm 部署 MCP 隧道
使用 Anthropic Helm chart 在 Kubernetes 集群上安装隧道栈。
Anthropic Helm chart 将 tunnel stack(隧道栈) 作为单个 Deployment 安装,并将其附加到您的隧道:可以是 chart 的 setup hook 为您创建的隧道,也可以是您在 Console 中创建的现有隧道。
开始之前
您需要:
- 一个隧道。 使用程序化访问时,如果您未提供隧道 ID,chart 的 setup hook 会为您创建一个;若要改为附加到现有隧道,请在 Console 中创建它并记录隧道 ID(
tnl_...)。手动配置始终从 Console 创建的隧道开始;您还需要它的隧道令牌和隧道域名。 - 一种让 chart 向 Tunnels API 进行身份验证的方式。
- 程序化访问(推荐)。 setup 组件通过 Workload Identity Federation(工作负载身份联合)进行身份验证,获取隧道令牌,生成 CA,将其注册到 Anthropic,并将所有内容存储在一个 Secret 中。您需要一条作用域为
workspace:manage_tunnels的联合规则。 - 手动。 跳过程序化访问。您将从 Console 获取隧道令牌,自行生成 CA 和服务器证书,在 Console 中注册 CA,并以 Secret 的形式将凭据提供给集群。
- 程序化访问(推荐)。 setup 组件通过 Workload Identity Federation(工作负载身份联合)进行身份验证,获取隧道令牌,生成 CA,将其注册到 Anthropic,并将所有内容存储在一个 Secret 中。您需要一条作用域为
- 一个 Kubernetes 集群,您可以使用
helm和kubectl向其部署。不使用程序化访问选项卡还会用到openssl(1.1.1 或更高版本)。 - 出站网络连接,从集群到
api.anthropic.com(443 TCP)以及 tunnel edge(隧道边缘)(7844 TCP 和 UDP)。请参阅完整的网络要求。 - 一个或多个 MCP 服务器,正在运行且可从集群通过您将在
gateway.config.routes下配置的地址访问。如果您还没有,请使用示例服务器。
可选:使用示例 MCP 服务器
如果您没有可用于测试的 MCP 服务器,请使用这个最小化的服务器:
kubectl create namespace mcp-tunnel --dry-run=client -o yaml | kubectl apply -f -
kubectl -n mcp-tunnel apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: hello-mcp-src
data:
hello_server.py: |
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")
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-mcp
spec:
replicas: 1
selector:
matchLabels: { app: hello-mcp }
template:
metadata:
labels: { app: hello-mcp }
spec:
containers:
- name: hello-mcp
image: python:3.13-slim
command: ["sh", "-c", "pip install --quiet mcp && python /app/hello_server.py"]
volumeMounts:
- { name: src, mountPath: /app }
ports:
- { containerPort: 9000 }
volumes:
- name: src
configMap: { name: hello-mcp-src }
---
apiVersion: v1
kind: Service
metadata:
name: hello-mcp
spec:
selector: { app: hello-mcp }
ports:
- { port: 9000, targetPort: 9000 }
EOF接下来的安装步骤会注明在何处添加相应的路由。
安装
setup 组件通过您的联合规则交换集群的投射 ServiceAccount 令牌,获取隧道令牌,生成 CA 和服务器证书,并将 CA 注册到 Anthropic。每日运行的 CronJob 会按需续期服务器证书,因此您无需手动处理任何密钥。
为集群设置 Workload Identity Federation
按照在 Kubernetes 中使用 WIF 注册集群的 OIDC 颁发者并创建联合规则。setup 组件在发布命名空间中以其自己的 ServiceAccount 运行;确切名称遵循 Helm 的
fullname约定,因此对于mcp-tunnel以外的任何发布名称,请在创建规则之前运行helm template <release> ... | grep -A2 'kind: ServiceAccount'进行确认。本指南其余部分假定发布名称为mcp-tunnel、命名空间为mcp-tunnel,此时 ServiceAccount 为mcp-tunnel-setup。字段 值 Subject system:serviceaccount:mcp-tunnel:mcp-tunnel-setupAudience api.anthropic.com(chart 的默认值;不含协议前缀)Scope workspace:manage_tunnels如果隧道位于组织默认工作区以外的工作区中,还需将规则的服务账户添加到该工作区(Tunnels API 根据服务账户的工作区成员资格进行授权)。
记下规则的 ID(
fdrl_...);您将把它设置为api.wif.federationRuleId。获取默认值
helm show values \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.0.2 > values.yaml配置隧道附加和路由
编辑
values.yaml,使用联合规则 ID 和组织 ID 设置api.wif.*键,并为每个上游 MCP 服务器添加一个routes条目:values.yamlapi: wif: federationRuleId: "fdrl_..." organizationId: "00000000-0000-0000-0000-000000000000" # Set when the tunnel is in a non-default workspace and the # rule's service account is a member of that workspace. # workspaceId: "wrkspc_..." tunnel: # Leave empty to have the setup hook create a tunnel during install. # Set to attach to an existing tunnel from the Console. id: "" # Increment to rotate the tunnel token on the next upgrade. # See the "Rotate the tunnel token" section. tokenVersion: "1" gateway: config: routes: docs: http://docs-mcp.internal:8080 search: http://search-mcp.internal:8080使用这些路由,Claude 可通过
docs.<your-tunnel-domain>和search.<your-tunnel-domain>访问这些服务器。某些托管 Kubernetes 发行版会在标准私有地址范围之外分配 Service CIDR;如果您的路由指向集群内 Service,请按照上游 IP 验证在此处添加gateway.config.upstream.allowed_ips。审查渲染后的清单
渲染 chart 并根据您组织的审查规范检查输出:
helm template mcp-tunnel \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.0.2 \ -n mcp-tunnel \ -f values.yaml > rendered.yaml安装
helm install mcp-tunnel \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.0.2 \ --namespace mcp-tunnel --create-namespace \ -f values.yamlsetup 组件作为 Helm pre-install hook Job 运行,因此
helm install会阻塞直到其完成。成功后 Helm 会自动删除该 Job。如果helm install因 hook 错误而失败,请参阅 setup 组件身份验证失败。当
tunnel.id为空时,setup 组件会在您的联合规则所指向的工作区(除非您设置了api.wif.workspaceId,否则为组织的默认工作区)中创建隧道,并将其 ID 和域名存储在mcp-tunnelSecret 中。您可以在隧道的详情页面上找到验证所需的域名,该页面可从 Console 中的 MCP tunnels 页面(platform.claude.com/settings/workspaces/default/mcp-tunnels)打开。在侧边栏的工作区选择器中,选择包含该隧道的工作区。您也可以从 Secret 中读取域名:kubectl -n mcp-tunnel get secret mcp-tunnel \ -o jsonpath='{.data.tunnel-domain}' | base64 -d重新运行 setup 组件(在升级或令牌轮换期间)会复用存储在此 Secret 中的隧道 ID;它绝不会创建第二个隧道。
在此模式下(setup.enabled: false),chart 不进行任何 API 调用;setup 组件不会运行,也没有 cert-renew CronJob。如果您不想设置 Workload Identity Federation,请使用此路径。
获取隧道令牌和域名
生成 CA 和服务器证书
代理监听明文 WebSocket,内层 TLS 使用您在此处生成的证书在该流内部承载。根据证书要求,服务器证书的 SAN 必须包含
*.<tunnel-domain>。export TUNNEL_DOMAIN=YOUR_TUNNEL_DOMAIN_HERE mkdir -p mcp-tunnel/data cd mcp-tunnel # 自签名 CA。显式指定扩展,使其满足证书 # 要求,而不依赖发行版 openssl.cnf 的默认值。 openssl req -x509 -newkey rsa:2048 -nodes \ -keyout data/ca.key -out data/ca.crt \ -days 3650 -subj "/CN=mcp-tunnel-ca" \ -addext "basicConstraints=critical,CA:TRUE" \ -addext "keyUsage=critical,keyCertSign,cRLSign" \ -addext "subjectKeyIdentifier=hash" # 服务器证书的扩展文件。使用 -extfile(而非 # 仅 OpenSSL 3.0+ 支持的 -copy_extensions)可确保其在 # OpenSSL 1.1.x 上仍可正常工作。 cat > data/tls.ext <<EOF subjectAltName = DNS:${TUNNEL_DOMAIN},DNS:*.${TUNNEL_DOMAIN} authorityKeyIdentifier = keyid,issuer extendedKeyUsage = serverAuth EOF # 由该 CA 签发的服务器证书 openssl req -newkey rsa:2048 -nodes \ -keyout 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在 Console 中注册
data/ca.crt。请将data/ca.key保存在持久且安全的位置;续期时您需要用它签发新的服务器证书。创建两个 Secret
chart 读取特定的键;Secret 名称可配置,但键不可配置。如果命名空间已存在(例如来自示例 MCP 服务器步骤),以下命名空间创建命令不会产生任何效果。
kubectl create namespace mcp-tunnel --dry-run=client -o yaml | kubectl apply -f - kubectl -n mcp-tunnel create secret generic mcp-tunnel-token \ --from-literal=tunnel-token='eyJ...' kubectl -n mcp-tunnel create secret generic mcp-tunnel-cert \ --from-file=tls.crt=data/tls.crt \ --from-file=tls.key=data/tls.key获取默认值
helm show values \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.0.2 > values.yaml为手动配置设置值
编辑
values.yaml并设置以下键:values.yamlsetup: enabled: false external: tunnelTokenSecretName: mcp-tunnel-token # must contain key: tunnel-token serverCertSecretName: mcp-tunnel-cert # must contain keys: tls.crt, tls.key gateway: config: # Required when setup.enabled is false. Replace the placeholder with # the $TUNNEL_DOMAIN value you exported earlier. When setup.enabled # is true the chart injects this from the Secret as a -tunnel-domain # flag instead. tunnel_domain: YOUR_TUNNEL_DOMAIN_HERE routes: docs: http://docs-mcp.internal:8080 search: http://search-mcp.internal:8080某些托管 Kubernetes 发行版会在标准私有地址范围之外分配 Service CIDR;如果您的路由指向集群内 Service,请按照上游 IP 验证在此处添加
gateway.config.upstream.allowed_ips。审查渲染后的清单
helm template mcp-tunnel \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.0.2 \ -n mcp-tunnel \ -f values.yaml > rendered.yaml安装
helm install mcp-tunnel \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.0.2 \ --namespace mcp-tunnel --create-namespace \ -f values.yaml
验证部署
从 Anthropic 一侧进行端到端验证:在 Managed Agent 会话或 Messages API 请求中使用 https://<route>.<your-tunnel-domain>/<path>,其中 <route> 是 gateway.config.routes 中的一个键,<path> 是上游 MCP 服务器提供服务的路径。使用示例 MCP 服务器时,即为 https://echo.<your-tunnel-domain>/mcp。有关请求格式,请参阅使用隧道化的 MCP 服务器。
如果失败,请检查 pod 日志(kubectl -n mcp-tunnel logs deploy/mcp-tunnel -c mcp-proxy 和 -c cloudflared)并查阅故障排除。
可选配置
使用 NetworkPolicy 限制出站流量
默认情况下拒绝进入代理 pod 的入站流量(networkPolicy.ingress.enabled: true)。若要进一步限制 pod 出站流量,请设置 networkPolicy.egress.enabled: true,并在 networkPolicy.egress.mcpServers 中填入覆盖您上游 MCP 服务器的 pod 标签选择器或 CIDR 范围。从 cloudflared 到隧道边缘的出站流量通过 networkPolicy.egress.cloudflaredEgressCIDRs 单独放行。
调优代理
gateway.config.* 下的字段会透传到代理配置文件。常见调整包括 upstream.allowed_ips、log_level 和 upstream.tls。完整字段列表请参阅代理配置参考。chart 始终会设置 listen_addr、tls.cert_file 和 tls.key_file;在 gateway.config 中设置它们不会生效。
提供您自己的 OIDC 令牌
默认情况下,chart 会为 setup 组件投射一个 Kubernetes ServiceAccount 令牌。若要使用来自其他身份提供商(例如 SPIFFE、Vault 或云 SDK sidecar)的令牌,请使用 setup.extraVolumes 和 setup.extraVolumeMounts 挂载它。然后将 api.wif.tokenFile 指向挂载路径。chart 会将 ANTHROPIC_IDENTITY_TOKEN_FILE 设置为该路径,setup 组件从那里读取令牌。
升级
始终向 helm upgrade 传递 --version,以免意外拉取更新的 chart。
从 chart 1.x 升级
Chart 2.0.0 将隧道 ID 从 api.wif.tunnelId 移至 tunnel.id。升级前,请编辑您的 values.yaml:将 tnl_... 值移至 tunnel.id 并删除 api.wif.tunnelId。不设置 tunnel.id 是安全的(setup 组件重新运行时会复用已存储在 mcp-tunnel Secret 中的隧道 ID),但显式迁移可使您的 values.yaml 保持准确。另外,请在 Console 中将联合规则的作用域从 org:manage_tunnels 更新为 workspace:manage_tunnels。
更改配置
对于路由、副本数或 NetworkPolicy 等常规更改:
helm upgrade mcp-tunnel \
oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \
--version 2.0.2 \
-n mcp-tunnel \
-f values.yaml轮换隧道令牌
使用程序化访问时,在 values.yaml 中递增 tunnel.tokenVersion,并使用 --set setup.force=true 进行升级。setup 组件仅在被强制时才会在升级过程中重新运行:
helm upgrade mcp-tunnel \
oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \
--version 2.0.2 \
-n mcp-tunnel \
-f values.yaml \
--set setup.force=truesetup 组件使用 Workload Identity Federation 进行身份验证;没有需要撤销的 API 令牌。
不使用程序化访问时,在 Console 的隧道详情页面点击 Rotate token,然后更新 mcp-tunnel-token Secret:
kubectl -n mcp-tunnel create secret generic mcp-tunnel-token \
--from-literal=tunnel-token='eyJ...' --dry-run=client -o yaml | kubectl apply -f -
kubectl -n mcp-tunnel rollout restart deploy/mcp-tunnel证书续期
chart 提供了自动化,但您仍需负责监控到期时间并确认续期完成。
使用程序化访问时,证书续期是自动的。chart 会部署一个 CronJob(以 Helm fullname 命名,后缀为 -cert-renew),每天运行 setup renew-cert(按 serverCert.cronSchedule,默认为 UTC 0 0 * * *)。除非证书距到期时间在 serverCert.renewBefore(默认 30 天)以内,否则该作业不执行任何操作。续期在本地进行:作业使用已存储在 Secret 中的 CA 签发新证书,不进行任何 API 调用,只需要 chart 授予的 Kubernetes RBAC。代理会从 Secret 挂载热重载证书,因此无需重启 Deployment。
不使用程序化访问时没有 CronJob。在安装后保留的 mcp-tunnel/ 目录中,使用现有 CA 签发新的服务器证书(不要重新生成 CA):
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
kubectl -n mcp-tunnel create secret generic mcp-tunnel-cert \
--from-file=tls.crt=data/tls.crt --from-file=tls.key=data/tls.key \
--dry-run=client -o yaml | kubectl apply -f -代理会从 Secret 挂载热重载证书。
后续步骤
Was this page helpful?