☰
Claude MCP Tunnels 实战:用 mcp-tunnels 插件与 Docker Compose 将私有网络 MCP 服务器安全接入 Claude
2026/10/1 2:54:43 网站建设 项目流程
  • AI 插件
  • 开发工具
  • 插件系统

【免费下载链接】claude-plugins-official

Official, Anthropic-managed directory of high quality Claude Code Plugins.

项目地址:https://gitcode.com/GitHub_Trending/cl/claude-plugins-official
点击查看免费下载

本文是 Claude Code 官方插件目录中mcp-tunnels插件的完整实战指南。它讲解如何借助 Anthropic MCP Tunnel 这一零入站端口方案,把运行在你自己私有网络内的 MCP 服务器暴露给 Claude:全程只建立出站连接,无需开放入站端口、无需公网暴露、无需在源站做 IP 白名单。读完本文,你将掌握/create-docker-mcp-tunnel命令的完整工作流(预检、建隧道、签发证书、注册 CA、编排代理、启动验证、从 Claude 调用),以及令牌轮换、证书续期和常见故障的排查方法。

一、MCP Tunnels 是什么,以及它解决什么问题

MCP(Model Context Protocol)服务器通常运行在需要被 Claude 调用的位置。如果你的 MCP 服务器位于公司内网、家庭网络或云端私有网络,传统做法是开放入站端口、配置公网入口并做 IP 白名单——这既增加攻击面,又难以维护。

MCP Tunnels提供的是一条相反路径:流量经由一条仅出站(outbound-only)的连接流向 Anthropic 的隧道边缘(tunnel edge),再由 Claude 侧按主机名路由访问,源端不需要任何入站端口。插件 README 开篇即点明其价值:mcp-tunnels 的 README 将其描述为"通过 Anthropic MCP Tunnel 连接位于私有网络中的 MCP 服务器——无需入站端口、无需公网暴露、无需在源站做 IP 白名单,流量只走出站连接"。

需要特别注意的是,该项目在 README 中明确标注为Research preview(研究预览):按"原样"提供,无可用性(uptime)或支持承诺,且依赖第三方传输提供商(Cloudflare)。在发送任何敏感数据之前,应先阅读其官方安全模型文档。这是你在决定是否将生产流量放入隧道前必须了解的前提。

二、插件结构与核心命令

该插件遵循本仓库的标准插件布局(见根目录 README.md 中描述的commands/ + README.md + LICENSE结构),由以下文件组成:

文件作用
commands/create-docker-mcp-tunnel.md命令本体:驱动 MCP Tunnels quickstart 从零到通的 10 步完整流程
README.md插件说明:命令用法、证书跨机复制、容器栈、需求与适用范围
LICENSEApache License 2.0

插件通过 Claude Code 的插件市场安装(/plugin install mcp-tunnels@claude-plugins-official)后,即可使用核心命令:

/create-docker-mcp-tunnel /create-docker-mcp-tunnel ~/work/my-tunnel

命令接受一个可选参数[deployment-dir](部署目录),默认值为./mcp-tunnel。它会在你的机器上端到端驱动官方 quickstart 流程:使用 Docker Compose + 手动提供的凭据(manual credentials),是本地测试的最短路径。命令文档 create-docker-mcp-tunnel.md 的 frontmatter 显示,该命令允许使用的工具包括Bash、Read、Write、Edit与AskUserQuestion——也就是说,它既会在本地执行命令,也会在需要人工操作控制台(Console)的环节暂停并询问你。

三、你会得到什么:一个三容器栈

命令文档与 README 都描述了最终构建的容器栈,核心是三个容器:

容器角色
mcp-proxyAnthropic 的代理。使用你控制的证书终止内层 TLS 握手,校验上游 IP,按主机名路由
cloudflared隧道代理。仅出站连接到 Anthropic 隧道边缘;与代理共享网络命名空间
hello-mcp(可选)FastMCP 示例服务器,仅在你还没有自己的 MCP 服务器可暴露时使用

当整个栈运行起来后,被路由的服务器可以从 Claude 通过https://<subdomain>.<your-tunnel-domain>/<path>访问,而宿主机没有任何公网端口在监听。

四、前置条件与网络要求

开始之前,请确认以下条件(README 的 Requirements 小节与命令文档 Step 0 均列出了它们):

  • Docker 与 Docker Compose:必须可用(Compose v2 优先;若仅有 v1 的docker-compose,也可使用,compose 文件是 v2 兼容的)。
  • OpenSSL 1.1.1 或更新:证书生成命令使用了-addext扩展参数,该参数仅在 1.1.1+ 可用。
  • Claude Console 中拥有可管理 MCP tunnels 的角色权限。
  • 出站连通性:能访问api.anthropic.com:443,以及隧道边缘(198.41.192.0/19、2606:4700:a0::/44)的7844 端口(TCP 与 UDP)。全程不需要打开任何入站端口。

五、分步实操:从零到 Claude 调用私有 MCP 服务器

以下 10 步完整复刻命令文档 create-docker-mcp-tunnel.md 的流程。下文以$DIR指代部署目录(默认为./mcp-tunnel)。整个流程是本地命令与只有你能在 Console 完成的操作(创建隧道、上传 CA)的混合——命令会在每一步给出简要说明、执行命令、检查输出,失败时给出明确诊断。

Step 0 — 预检(Preflight)

先运行以下命令,报告缺失项后再继续:

docker --version && docker compose version && openssl version
  • Docker + Docker Compose 是必需的;openssl1.1.1+ 是必需的(后续命令使用-addext)。
  • 确认主机具备到api.anthropic.com:443及隧道边缘(198.41.192.0/19、2606:4700:a0::/44)7844 端口 TCP/UDP 的出站访问。不开任何入站端口。

Step 1 — 创建隧道(Console,用户操作)

这一步需要你在 Claude Console 中操作:侧边栏Manage → MCP tunnels → New tunnel并命名;关闭"Set up programmatic access"——本快速流程使用手动凭据。打开隧道后,从Connection区域复制两个值:

  • Domain:形如abcd1234.tunnel.anthropic.com
  • Token:点击眼睛图标后复制

重要安全约定:不要要求用户把 Token 粘贴进聊天记录。Token 是认证出站隧道连接的秘密,必须保持它在对话记录之外。命令会创建$DIR/.env文件,由你(用户)自行把 Token 粘贴进去;或者让你在运行 compose 的 shell 中export TUNNEL_TOKEN='eyJ...'。Domain 则记录为TUNNEL_DOMAIN供后续步骤使用。

Step 2 — 创建部署目录

mkdir -p "$DIR"/{config,data} cd "$DIR"

Step 3 — 凭据文件(.env)

创建$DIR/.env(Compose 会自动加载它;与 shell 的export不同,它能跨重启存活)。命令会自己写入TUNNEL_DOMAIN,并为秘密留占位符,由用户填写:

TUNNEL_DOMAIN=<the domain from step 1> TUNNEL_TOKEN=PASTE_TUNNEL_TOKEN_HERE

然后锁定权限并确保它永远不会被提交:

chmod 600 "$DIR/.env" printf '.env\ndata/\n' > "$DIR/.gitignore"

暂停并让用户把PASTE_TUNNEL_TOKEN_HERE替换为真实 Token(告知确切文件路径)。不打印地验证它已设置:

cd "$DIR" && grep -q '^TUNNEL_TOKEN=eyJ' .env && echo "token looks set" || echo "token NOT set — edit .env"

在本 shell 中加载它供 openssl/config 步骤使用:

cd "$DIR" && set -a && . ./.env && set +a && echo "domain: $TUNNEL_DOMAIN"

Step 4 — 生成 CA 与服务器证书

代理终止的是由你控制的 CA 所签发证书的内层 TLS 握手。下面同时生成 CA 与服务器证书(Linux/macOS 写法;官方 quickstart 还提供 Windows PowerShell 变体——如果用户在 Windows 上,可提供该变体):

cd "$DIR" 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" cat > data/tls.ext <<EOF subjectAltName = DNS:${TUNNEL_DOMAIN},DNS:*.${TUNNEL_DOMAIN} authorityKeyIdentifier = keyid,issuer extendedKeyUsage = serverAuth EOF 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 chmod 644 data/tls.key

为什么用这些参数(理解底层原理):

  • 显式的-addext扩展让 CA 无论发行版openssl.cnf默认值如何,都能满足隧道的证书要求。
  • 用-extfile(而非-copy_extensions,后者仅 OpenSSL 3.0+ 可用)是为了在 OpenSSL 1.1.x 上也能工作,并补上代理要求的AuthorityKeyIdentifier。
  • chmod 644 data/tls.key是必须的:openssl 会把密钥写成0600,但代理容器以非 root 用户运行,必须能读到它。

data/tls.key与data/ca.key是敏感文件——它们位于data/下,已被 Step 3 的.gitignore排除。

Step 5 — 注册 CA(Console,用户操作)

在隧道详情页滚动到Certificates → Add certificate,上传$DIR/data/ca.crt(或粘贴其内容——用cat data/ca.crt打印以便复制)。一旦注册了证书,隧道状态即翻转为 Active;在此之前,隧道不会出现在 Agent 选择器中。等待用户确认隧道显示Active再继续。

Step 6 — 选择上游 MCP 服务器

通过提问让用户二选一:

  • "我已经有 MCP 服务器":获取其可达地址为scheme://host:port形式(端口必填,不允许带路径——代理在加载配置时若上游值带路径会拒绝)。它必须能从代理容器访问,且解析到 RFC1918 私有地址(10/8、172.16/12、192.168/16);代理默认拒绝公网/环回上游(SSRF 防护)。若它作为 Compose 服务运行,则把它加进 compose 文件共享网络;若它跑在宿主机上,见下文"host process"排查项。与用户一起选一个路由子域名(如wiki)。
  • "使用示例服务器":把下面的 FastMCPhello-server作为 Compose 服务hello-mcp搭建,路由子域名为echo。

示例服务器源码(仅在选择该选项时写入$DIR/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")

Step 7 — 代理配置(mcp-proxy.yaml)

写入$DIR/config/mcp-proxy.yaml。tunnel_domain是必填项(代理会从入站主机名中剥离它,从而在routes中找到子域名)。routes是子域名 → 上游 URL 的扁平映射(map),不是列表:

listen_addr: ":8080" log_level: info tunnel_domain: <TUNNEL_DOMAIN> tls: cert_file: /data/tls.crt key_file: /data/tls.key routes: echo: http://hello-mcp:9000

替换为真实的TUNNEL_DOMAIN;若用户自带服务器,则把routes:块替换为所选子域名 → 上游的映射(例如wiki: http://wiki-mcp.internal:8080),且可以保留多个路由。

Step 8 — Compose 编排文件

写入$DIR/docker-compose.yaml。镜像按 digest 固定版本(digest-pinned):

services: mcp-proxy: image: us-docker.pkg.dev/anthropic-public-registry/images/mcp-proxy@sha256:6b9adedbf2763143ec72f106ecaf0ce7fd3294e89b208f54a1db97a33d14c5ba command: ["-config", "/etc/mcp-proxy/config.yaml"] volumes: - ./config/mcp-proxy.yaml:/etc/mcp-proxy/config.yaml:ro - ./data:/data:ro restart: unless-stopped cloudflared: image: cloudflare/cloudflared@sha256:6b599ca3e974349ead3286d178da61d291961182ec3fe9c505e1dd02c8ac31b0 command: tunnel --no-autoupdate run --url http://localhost:8080 environment: - TUNNEL_TOKEN network_mode: "service:mcp-proxy" restart: unless-stopped

几个必须理解的要点:

  • --url http://localhost:8080在手动流程中是必需的:因为没有在服务端推送 ingress 规则,缺了它 cloudflared 会对每个请求返回 503。
  • network_mode: "service:mcp-proxy":共享代理的网络命名空间,这样localhost:8080才能到达代理。
  • environment: - TUNNEL_TOKEN(不带值):把变量从.env透传进容器。

若选择了示例服务器,追加该服务:

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

若用户自带服务器且已容器化,也应在此追加其服务,使其与代理共享 Compose 网络。(对于加固的单主机部署——非 root 用户、只读 rootfs、cap_drop: ALL、no-new-privileges——官方文档另有专门的 Compose 部署指南;此 quickstart 保持最小化以加速本地测试。)

Step 9 — 启动并验证

cd "$DIR" && docker compose up -d sleep 5 docker compose logs mcp-proxy | grep -i "route configured" docker compose logs cloudflared | grep -i "Registered tunnel connection"

预期每个路由出现一行route configured,以及四行Registered tunnel connection。容器需要几秒启动;如果日志为空请重跑 grep(不要在第一次空结果就判定失败)。若持续为空,进入故障排查章节。

Step 10 — 从 Claude 调用

命令文档提供了两条路径:

Managed Agents(Console):Managed Agents → Sessions→ 新会话 → Agent 选择器Create new agent→+ MCP Server→ 选择该隧道 →Subdomain= 路由(echo),Path=mcp(FastMCPstreamable-http在/mcp提供服务)。然后提问:"Use the hello tool to greet tunnel."——预期看到一次工具调用及其结果。

Messages API:主机为<subdomain>.<tunnel-domain>;路径取决于上游提供什么(FastMCP 为/mcp)。使用创建隧道所在工作区的 API key:

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-4-7\", \"max_tokens\": 1024, \"mcp_servers\": [{\"type\": \"url\", \"name\": \"echo\", \"url\": \"https://echo.${TUNNEL_DOMAIN}/mcp\"}], \"tools\": [{\"type\": \"mcp_toolset\", \"mcp_server_name\": \"echo\"}], \"messages\": [{\"role\": \"user\", \"content\": \"call hello with name=tunnel\"}] }"

安全边界提醒:隧道承载加密流量,但不对上游做身份认证。如果上游 MCP 服务器自身需要认证,你需要像对待任何其他 MCP 服务器一样自行提供。

六、把 CA 证书复制到另一台机器

你通常在浏览器中于 Console 注册 CA——而这台机器往往与运行整个栈的机器不同(例如隧道跑在远端 homespace,而你从笔记本/开发机上上传ca.crt)。只有证书(<deployment-dir>/data/ca.crt,约 1 KB 的 PEM)会离开宿主机——data/ca.key与data/tls.key永远不会。

文件很小,最简方式就是打印并直接粘贴到 Console 的证书字段:

cat <deployment-dir>/data/ca.crt # default: ~/mcp-tunnel/data/ca.crt

若要作为文件用scp复制,从能 SSH 到另一端的机器上执行(scp无法在两台远程机器之间中转)。从 homespace 拉取到你的开发机——如果你已运行coder config-ssh,主机名为coder.<workspace>:

scp coder.<workspace>:<deployment-dir>/data/ca.crt . # generic form: scp <homespace-ssh-host>:~/mcp-tunnel/data/ca.crt .

或者,若宿主机能到达开发机,从宿主机推送过去:

scp <deployment-dir>/data/ca.crt <user>@<devbox-host>:~/

七、故障排查矩阵(按此顺序诊断)

命令文档提供了一张完整的排查表,覆盖了手动 quickstart 中最常见的坑。诊断顺序建议:先查出站连接 → 再查内层 TLS 握手 → 最后查上游路由。以下为完整矩阵:

症状原因修复
调用方看到 HTTP 500;cloudflared 日志No ingress rules were definedcloudflared 没有本地目标确保--url http://localhost:8080与network_mode: "service:mcp-proxy"都在,然后docker compose up -d
代理退出cannot unmarshal !!seq into map[string]stringroutes被写成 YAML 列表使用routes: { name: http://host:port },而不是对象列表
代理退出open /data/tls.key: permission denied密钥为0600,而代理以非 root 运行chmod 644 data/tls.key
代理日志no route for host(调用方得到502 No route configured for host)tunnel_domain缺失或错误设为隧道详情页上的精确域名;然后重启代理(见下一行)
改了配置但毫无变化代理不会热加载config.yaml(仅热加载tls.cert_file)docker compose restart mcp-proxy——文件内容变化时up -d不会重建它
tls handshake failed ... unknown certificate authority该隧道上 CA 未注册或已吊销在 Console 重新上传data/ca.crt(Step 5)
tls handshake failed ... bad certificate服务器证书 SAN ≠*.<tunnel-domain>,或已过期用正确的TUNNEL_DOMAIN重新生成服务器证书(Step 4)
IP validation failed: <ip> is not a private address上游解析到 RFC1918 之外(如127.0.0.1、公网 IP)把上游作为 Compose 服务运行在代理网络上;或刻意收窄upstream.allowed_ips(本地测试之外避免0.0.0.0/0)
dial tcp ...: connect: connection refused(针对host.docker.internal)rootless Docker 无法到达宿主网络命名空间把 MCP 服务器作为 Compose 服务运行,而非宿主机进程
HTTP 502,代理日志无request startedcloudflared 尚未完成注册,或正在滚动更新等待 ×4Registered tunnel connection后重试
隧道在 Agent 的+ MCP Server选择器中缺失没有有效证书,或工作区不对注册 CA 证书(Step 5);在隧道所在工作区打开会话
curl https://<proxy>:8080失败wrong version number预期行为——监听器是明文 WS,TLS 在 WS 流内部不要直接 curl 代理;通过 Managed Agent 或 Messages API 验证

两条首要诊断命令是docker compose logs cloudflared(Token / 边缘可达性)与docker compose logs mcp-proxy(配置 / 证书 / 路由)。官方文档另有更多案例。

八、运维要点:令牌轮换与证书续期

命令文档明确提醒:这些操作只需简要提及,不要未经请求就执行。

  • 令牌轮换(Token rotation):Console 中Rotate token会立即令旧令牌失效。更新.env中的TUNNEL_TOKEN后执行docker compose up -d cloudflared。
  • 证书续期(Cert renewal):服务器证书有效期 90 天。用同一个 CA 重新签名(已注册的 CA 不变)并替换data/tls.crt;代理会轮询并热加载它,无需重启。
  • 配置变更始终需要docker compose restart mcp-proxy。

九、适用范围与更进一步的部署

本插件定位的是手动凭据、单主机、本地测试这条路径。如果你需要以下能力,README 明确指向官方部署指南:

  • 加固的单主机部署(非 root、只读 rootfs、dropped capabilities);
  • Kubernetes 部署(官方提供 Helm 部署指南);
  • 程序化访问(通过 Workload Identity Federation 以编程方式获取凭据,替代手动复制 Token)。

也就是说:mcp-tunnels 插件是通往官方 MCP Tunnels 能力的便捷入口,它把最繁琐的本地验证路径自动化,但生产级部署仍应参考官方提供的 Compose/Helm 硬化方案。

十、总结与文件指引

通过本插件,你可以在十几分钟内完成一次"私有网络 MCP 服务器 → Anthropic 隧道 → Claude 调用"的完整闭环,全程无入站端口。涉及的关键仓库文件:

  • 插件说明与命令用法:plugins/mcp-tunnels/README.md
  • 10 步完整流程、证书命令、Compose 配置与排查矩阵:plugins/mcp-tunnels/commands/create-docker-mcp-tunnel.md
  • 许可证:plugins/mcp-tunnels/LICENSE

最后再次强调安全底线:Token 是.env(chmod 600、已 gitignore)中的活体密钥;本方案处于研究预览阶段、面向本地测试,承载敏感或生产流量前务必先阅读官方安全模型。

  • AI 插件
  • 开发工具
  • 插件系统

【免费下载链接】claude-plugins-official

Official, Anthropic-managed directory of high quality Claude Code Plugins.

项目地址:https://gitcode.com/GitHub_Trending/cl/claude-plugins-official
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询