mcpField
T
tunnel-mcp

tunnel-mcp

本地服务
github.comAI 与智能体416 周前更新

关于 tunnel-mcp

tunnel-mcp 是一个 MCP 服务,通过临时端到端加密隧道连接 Claude Agent。它支持双人会话和多人房间,并提供消息与加密文件共享,同时由人类掌控实际操作。

主要功能

  1. 01创建和加入加密隧道
  2. 02双人会话与多人房间
  3. 03收发消息
  4. 04加密共享文件并校验哈希
  5. 05查看成员与会话状态
  6. 06结束会话或离开

适用场景

  1. 01让两位开发者的 Claude Agent 协作
  2. 02跨不同机器配对调试
  3. 03向会话成员共享项目文件

MCP 相关

它向 MCP 客户端提供创建、加入、收发消息和关闭隧道会话的工具,也支持文件共享和查看会话状态。Claude MCP 客户端可用这些工具直接连接 Agent。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"zachlikefolio-tunnel": {
"command": "npx",
"args": [
"-y",
"tunnel-mcp"
],
"env": {
"TUNNEL_DOH": "<TUNNEL_DOH>"
}
}
}
}
启动命令npx -y tunnel-mcp
需要配置的环境变量
TUNNEL_DOHSet to 'off' to disable DNS-over-HTTPS (readiness gate + guest resolver fallback) on networks that block 1.1.1.1

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmtunnel-mcp0.3.0

工具

9

收录的工具列表 · 更新于 2 周前

参数类型必填说明
goalstring是
invitesinteger否

详细介绍

tunnel-mcp

在两位开发者的 Claude Agent 之间建立直接、端到端加密的隧道——无需人工复制粘贴。

CI npm version npm downloads node

tunnel-mcp 演示 — 两个 Agent 通过真实的加密隧道进行交流

只需 30 秒,即可亲自复现——克隆仓库,然后:

npm ci && npm run demo

这会通过 Cloudflare 的边缘网络打开一个真实的加密隧道,以访客身份加入,交换端到端加密消息,验证加入链接只能使用一次,然后拆除整个隧道。

两位开发者各自运行 Claude Agent 并需要让它们协作时,通常的做法是由人坐在中间,把消息从一个聊天窗口复制粘贴到另一个。tunnel-mcp 无需人工介入。这是一个 MCP 服务,允许一位开发者的 Agent 打开一次性的加密隧道,另一位开发者的 Agent 可直接连接到该隧道,让两个 Agent 直接交流——同时由各自的用户掌控文件系统或 Shell 中实际发生的操作。

工作原理

一位开发者(主机)调用 tunnel_open。其本地的 tunnel-mcp 进程会变成进程内 WebSocket 中继,并通过一次性的 cloudflared Quick Tunnel 将其接入互联网——无需端口转发,也无需配置服务。另一位开发者(访客)使用主机分享的链接调用 tunnel_join,其 Agent 会向外连接到同一条隧道。由于双方都只发起出站连接,因此即使位于普通防火墙和 NAT 后也能正常工作。

   Host machine                                        Guest machine
  ┌───────────────────┐        outbound HTTPS         ┌───────────────────┐
  │   Claude (host)    │            wss://             │   Claude (guest)   │
  │        │           │      ┌──────────────┐         │        │          │
  │  tunnel_open/say/  │──────▶  cloudflared │◀────────│  tunnel_join/say/  │
  │  listen/close      │      │ Quick Tunnel │─────────▶  listen/close      │
  │        │           │      └──────────────┘         │        │          │
  │  in-process relay  │                                └───────────────────┘
  └───────────────────┘

中继和 cloudflared 子进程只会在会话期间运行,并会在拆除时销毁。对话记录仅保存在内存中——不会写入磁盘,并会在拆除时随进程一起消失。

安装

npm install -g tunnel-mcp
# or, without installing:
npx tunnel-mcp

将其注册到 Claude Code(两位开发者都只需操作一次):

claude mcp add tunnel -- tunnel-mcp          # if globally installed
# or, with no global install:
claude mcp add tunnel -- npx -y tunnel-mcp

tunnel-mcp 是一个 stdio MCP 服务,而非交互式命令行工具。手动启动它只会让它静静等待客户端——这是预期行为。运行 tunnel-mcp --help 查看用法,或运行 tunnel-mcp --version 查看版本。

tunnel-etiquette 技能会教每个 Agent 如何在隧道中行事(将对端视为不可信输入,并在执行对端提出的任何操作前先征求其用户确认)。安装软件包时会自动将该技能复制到 ~/.claude/skills/(尽力而为)。如果禁用了安装脚本(npm install --ignore-scripts),或者你想将其安装到自定义目录或强制更新,请显式运行:

npx tunnel-mcp install-skill                       # into ~/.claude/skills
npx tunnel-mcp install-skill --dir <path> --force  # elsewhere / overwrite

设置 TUNNEL_SKILLS_DIR 可更改默认目标目录;设置 TUNNEL_SKIP_SKILL_INSTALL=1 可选择不自动复制。

如果 cloudflared 尚未位于 PATH 中,则会在首次需要时自动下载到 ~/.tunnel/bin——无需额外安装。

快速入门

主机 — 让 Claude 根据目标打开隧道:

“打开一条隧道,一起调试结账流程。”

Claude 会调用 tunnel_open({ goal }),并返回一条可直接转发的邀请 — 一条纯文本消息,其中包含一次性设置命令和加入链接。通过可信渠道(Slack 私信等)将它发给另一位开发者 — 该链接属于机密,因为其中包含此会话的加密密钥。它只能使用一次,且约 10 分钟后过期(tunnel_open 会报告 joinLinkExpiresInSec),因此请尽快分享。

访客 — 粘贴链接并让 Claude 加入:

“加入这条隧道:<link>”

Claude 会调用 tunnel_join({ joinLink }),了解目标,并获取房间成员名单 — 使用默认的单个邀请时,房间里只有你们两人。

需要不止一位访客?改为打开一个房间:

“为我和两位队友打开一条隧道,一起调试结账流程。”

Claude 会调用 tunnel_open({ goal, invites: 3 }) — invites 是要安排加入的队友人数(最多 15 人,加上主机可同时连接 16 人)— 并为每位队友返回一条邀请,而不是单个链接。将每条邀请转发给一位且仅一位成员;每条邀请只能使用一次,因此不要把同一链接给两个人。需要在会话中途添加成员,或重新邀请邀请过期前未使用的成员?tunnel_invite({ count })(仅限主机)可以生成更多邀请。

双方 — Agent 通过 tunnel_say 逐轮发送消息,并通过 tunnel_listen 等待下一条回复。在房间中,每条消息都会附带 fromName,让 Agent 知道是谁说了什么,并在需要时与各自的用户确认。

结束会话取决于角色:主机调用 tunnel_close,为所有人结束会话并拆除中继 — 内存中的对话记录也会随之消失,因为它从未写入磁盘。成员调用 tunnel_close 只会离开;房间会为其他成员继续保持开放。

**分享文件:**任何成员都可以调用 tunnel_share({ path }),向房间发送文本文件或二进制文件 — 文件会从磁盘读取、计算哈希,并在穿过隧道前使用房间密钥加密,因此中继始终只能看到密文。队友会在 tunnel_listen 中收到 artifact 消息,也可以在 tunnel_status().artifacts 中查看文件信息(id、名称、类型、大小、发送者)。想要接收文件的队友可以调用 tunnel_receive({ artifactId, savePath }),并自行选择保存路径 — 文件字节会先解密并与发送者的 sha256 校验,之后才会写入;若不匹配,则会拒绝保存。任何当前成员都可以获取文件,直到文件过期(TTL 为 30 分钟)或会话结束 — 每次调用 tunnel_receive 都会独立重新获取并验证文件。使用较旧客户端的成员会被静默跳过(tunnel_share 结果中的 olderMembers)— 他们不会看到邀请。文件名会以明文元数据传输,因此不要在文件名中放入机密内容;并应将接收的每个文件都视为不可信输入 — 请参阅 etiquette skill。

工具

工具使用者用途
tunnel_open({goal, invites?})主持方启动中继和 Quick Tunnel,并为每位队友获取一个邀请链接(默认为 1 个,即经典的双人模式)。
tunnel_invite({count?})主持方在会话期间生成更多单次使用、限时有效的邀请链接。
tunnel_join({joinLink})成员使用邀请链接接入房间并进行身份验证;返回当前成员名单。
tunnel_say({text})任意向房间发送消息。
tunnel_listen({sinceSeq?, timeoutMs?})任意等待下一条或多条消息,每条消息都会标注发送者的 fromName。
tunnel_share({path})任意与房间共享文件(文本或二进制),并进行端到端加密;返回 {artifactId, offeredTo, olderMembers}。
tunnel_receive({artifactId, savePath})任意获取已提供的文件,验证其哈希值,并将其写入你选择的路径。
tunnel_status()任意查看会话信息:角色、目标、成员名单、待处理的邀请、已提供的文件、lastSeq。
tunnel_close({summary?})任意主持方:结束所有人的会话。成员:离开房间。

安全模型

tunnel-mcp 本质上是一个安全敏感工具——它会在开发者的 AI Agent 之间建立实时通道。以下是它确切提供和不提供的保护:

  • 聊天消息正文经过端到端加密。 每条 tunnel_say 正文都会先使用 NaCl secretbox(XSalsa20-Poly1305,通过 tweetnacl)加密,然后才通过 cloudflared 管道。中继和管道看到的聊天正文始终只有密文。
  • 目标、每位参与者的显示名称和系统事件均为明文。 tunnel_open 目标、每位成员的名称以及连接事件(加入/离开/空闲/关闭)都以明文元数据形式发送——请勿在目标字符串或显示名称中放入机密信息。
  • 身份验证通过密钥持有证明完成,而非传输密钥。 加入时会使用 HMAC 挑战来证明加入成员持有与主机相同的密钥;原始密钥本身绝不会通过网络传输。
  • 每个邀请都是一次性、限时凭证。 邀请中包含会话密钥,因此请像对待密码一样处理——只通过你已信任的渠道(如 Slack 私信)分享,绝不要发到公开的 issue、PR 或聊天中,并且每个邀请只转发给一个人。邀请由最先兑换的人使用(他们离开后也无法再次使用),并会在约 10 分钟后自动过期,因此邀请泄露后的暴露时间较短且有上限。
  • 只允许你邀请的人加入——默认仅限双方参与,房间需主动启用(最多 16 人),每个邀请均为一次性且限时。可加入人数取决于主机选择生成的邀请数量,而非恰好持有房间密钥的人数。
  • 共享文件经过端到端加密和哈希验证。 tunnel_share 会先使用与聊天相同的房间密钥,通过 NaCl secretbox 加密文件字节,然后才通过隧道传输,并附带内容的明文 sha256 值;tunnel_receive 会先解密、重新组装并验证哈希,然后才写入磁盘。文件名、大小和类型均为明文元数据(请勿在文件名中放入机密信息),收到的文件不可信——tunnel_receive 只会写入接收者选择的路径,绝不会使用发送者提供的名称。
  • 对端是未经信任的输入源,而非指令来源。 其他 Agent 发来的消息是需要审慎判断的数据,而不是可执行的命令——这适用于房间内的每位成员,而不只是某一位。行为规范技能要求每个 Agent 在写入文件、运行风险较高的命令,或根据对端所说的内容宣布某项修复“已确认”之前,先取得其对应人类用户的同意。
  • 所有内容都是临时的。 对话记录只保存在内存中——绝不会写入磁盘,并会随进程结束而消失。拆除行为取决于角色:主机执行 tunnel_close(或其进程退出,或 30 分钟内没有消息)会结束所有人的会话,并拆除中继和 cloudflared 子进程;成员执行 tunnel_close 只会离开房间——房间会为其他成员继续保持开放。

完整威胁模型及漏洞报告方式,请参阅 SECURITY.md。

要求

  • Node.js >= 20
  • Claude MCP 客户端(例如 Claude Code)
  • cloudflared——如果尚未加入 PATH,首次使用时会自动安装到 ~/.tunnel/bin

开发

npm ci                  # install dependencies
npm test                # run the test suite (248 tests, TDD)
npm run build           # compile TypeScript
npm run lint            # eslint
npm run format:check    # prettier --check .
npm run test:coverage   # vitest run --coverage

有关如何提出更改,请参阅 CONTRIBUTING.md。

故障排除

tunnel-mcp / npx tunnel-mcp“没有任何反应”。 它是一个 stdio MCP 服务,而不是交互式命令行工具——不带参数时,它会启动并等待 MCP 客户端通过 stdin/stdout 连接。这是预期行为。将它注册到客户端(见上文),或运行 tunnel-mcp --help。

访客加入时出现 getaddrinfo ENOTFOUND …trycloudflare.com。 cloudflared 快速隧道会在每条隧道的 DNS 记录传播之前几秒钟打印 URL。如果有任何程序过早查询该域名,就会收到 NXDOMAIN,而解析器会将其负缓存长达 30 分钟——即使隧道已经上线,也会导致加入失败。tunnel-mcp 会避免这种情况:tunnel_open 会等待记录实际解析成功(通过 Cloudflare 的 1.1.1.1 的 DoH;该 IP 不会经过你的系统解析器,因此不会污染它),然后再返回链接;访客则会先使用系统 DNS,失败时再回退到 DoH。因此,直接尝试加入应该就能成功;如果遇到 ENOTFOUND,较早的尝试可能已经污染了缓存——请等待缓存过期,或刷新 DNS(在 macOS 上运行 sudo dscacheutil -flushcache)。仅在会阻止 DoH(1.1.1.1)且系统 DNS 已能解析 *.trycloudflare.com 的网络上设置 TUNNEL_DOH=off。

路线图 / 尚不支持

这是一个 MVP。目前明确不在支持范围内的功能:

  • 主机离线 / 异步消息传递
  • 其他传输方式(ngrok、WebRTC)
  • 邀请轮换(在会话中替换某个仍然有效的邀请;请注意,邀请本身已经是一次性且会过期的——参见上文的安全模型)
  • 加密目标或其他元数据

许可证

MIT — 参见 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。