mcpField
T
Tailscale MCP

Tailscale MCP

本地服务
tmhsdigital.github.io云与基础设施14 天前更新

关于 Tailscale MCP

Tailscale MCP 是通过 stdio 让 Agent 和开发工具查看、管理本地已认证 Tailscale 守护进程的 MCP 服务,涵盖 tailnet 发现、SSH 配置、端口共享和延迟检查,并提供结构化错误与默认关闭的公网暴露。

主要功能

  1. 01查看 tailnet 状态与节点
  2. 02生成 SSH 配置
  3. 03通过 Serve 或 Funnel 共享端口
  4. 04检查节点连通性与延迟
  5. 05控制只读模式和 Funnel 权限

适用场景

  1. 01部署前查找在线 tailnet 节点
  2. 02为节点生成 SSH 主机配置
  3. 03向 tailnet 成员共享开发端口
  4. 04判断节点连接是直连还是中继

MCP 相关

通过 stdio 向 MCP 客户端提供结构化的 Tailscale 状态、SSH 配置、共享和 ping 工具。工具注解与输出架构说明只读及状态变更操作。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"tmhsdigital-tailscale": {
"command": "npx",
"args": [
"-y",
"@tmhs/tailscale-mcp"
],
"env": {
"TAILSCALE_MCP_ALLOW_FUNNEL": "<TAILSCALE_MCP_ALLOW_FUNNEL>",
"TAILSCALE_MCP_READONLY": "<TAILSCALE_MCP_READONLY>",
"TAILSCALE_MCP_BIN": "<TAILSCALE_MCP_BIN>",
"TAILSCALE_MCP_TIMEOUT_MS": "<TAILSCALE_MCP_TIMEOUT_MS>"
}
}
}
}
启动命令npx -y @tmhs/tailscale-mcp
需要配置的环境变量
TAILSCALE_MCP_ALLOW_FUNNELSet to 1 to let share_port expose a port to the open internet with Funnel (off by default)
TAILSCALE_MCP_READONLYSet to 1 for monitoring only: no share tools, and no SSH config writes
TAILSCALE_MCP_BINPath to the tailscale binary if it is not on PATH or in the default install location
TAILSCALE_MCP_TIMEOUT_MSPer-call timeout for tailscale commands in milliseconds (default 10000)

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

安装包
npm@tmhs/tailscale-mcp0.4.0

工具

6

收录的工具列表 · 更新于 3 天前

参数类型必填说明
onlineOnlyboolean否仅包含当前在线的对等节点(默认值:false)

详细介绍

Tailscale MCP

用于安全地以编程方式访问本地 Tailscale 守护进程的 MCP 服务:发现 tailnet、生成 SSH 配置、通过 Serve/Funnel 共享端口,以及生成延迟矩阵。

许可证:CC-BY-NC-ND-4.0 npm 版本 CI


通过 stdio,为 Agent 和开发者工具提供安全、结构化的本地 Tailscale 守护进程访问接口。它会调用 tailscale CLI(从 PATH 查找,也会回退到 Windows 和 macOS 上的默认安装位置),且不会处理身份验证密钥或 tailnet 凭据:CLI 会与已完成身份验证的本地守护进程通信。

如果缺少二进制文件、守护进程已停止,或设备需要登录,每个工具都会返回包含 code 和确切 remedy 命令的结构化错误,而不是抛出异常。

安装

添加到 Cursor 在 VS Code 中安装 下载 Claude Desktop 版本

  • Claude Code: claude mcp add tailscale -- npx -y @tmhs/tailscale-mcp
  • Claude Desktop: 从最新版本下载 tailscale-mcp.mcpb 并打开。安装对话框中有只读模式和 Funnel 的开关。
  • Cursor / VS Code: 使用上方按钮。
  • MCP Registry: 已列入官方 MCP Registry,名称为 io.github.TMHSDigital/tailscale-mcp,支持 Registry 的客户端和目录可以找到它。

也可以手动将其添加到任何 MCP 客户端的配置中:

{
  "mcpServers": {
    "tailscale": {
      "command": "npx",
      "args": ["-y", "@tmhs/tailscale-mcp"]
    }
  }
}

需要 Node 22+(当前 LTS 版本)以及已安装并登录的 Tailscale 客户端。

查找 tailscale CLI

服务会先在 PATH 中查找 tailscale,然后查找平台默认安装位置:Windows 上的 C:\Program Files\Tailscale\tailscale.exe,以及 macOS 上的 /Applications/Tailscale.app/Contents/MacOS/Tailscale、/opt/homebrew/bin/tailscale 和 /usr/local/bin/tailscale。因此,Mac App Store 安装版本无需额外设置即可使用。若要使用其他二进制文件,请设置 TAILSCALE_MCP_BIN:

{
  "mcpServers": {
    "tailscale": {
      "command": "npx",
      "args": ["-y", "@tmhs/tailscale-mcp"],
      "env": { "TAILSCALE_MCP_BIN": "/path/to/tailscale" }
    }
  }
}
超时

每次 tailscale 调用都有超时限制,默认值为 10 秒。若守护进程无响应,会返回结构化的 TIMEOUT 错误,而不会让 Agent 卡住。对于速度较慢的机器或规模很大的 tailnet,可设置 TAILSCALE_MCP_TIMEOUT_MS 来提高超时限制。share_port 最多等待 15 秒;ping 的等待时间随 count 和 timeoutMs 变化;ping_all 的总等待时间上限为 45 秒。

配置参考

所有设置都是服务器 env 块中的环境变量。布尔标志接受 1/true/yes/on 或 0/false/no/off。任何其他值都会导致服务器在启动时停止,因此拼写错误绝不会悄然放宽安全设置。

变量默认值作用
TAILSCALE_MCP_ALLOW_FUNNELoff允许调用 share_port {"public": true},通过 Funnel 将端口暴露给开放互联网。关闭时,调用会返回 FUNNEL_DISABLED,不会共享任何内容。
TAILSCALE_MCP_READONLYoff仅监控模式:不会注册 share_port 和 stop_share,且 generate_ssh_config 会拒绝 write: true(READ_ONLY)。
TAILSCALE_MCP_BIN(search)tailscale 二进制文件的路径。
TAILSCALE_MCP_TIMEOUT_MS10000每次调用的 CLI 超时时间。
Linux:Serve/Funnel 权限

仅限 root 或已配置的操作员在 Linux 上更改 Serve/Funnel 设置。如果 share_port 或 stop_share 返回 PERMISSION_DENIED,请为你的用户授权一次:

sudo tailscale set --operator=$USER

工具

每个工具都会声明 MCP 注释,因此客户端可以自动批准只读工具,并对其余工具进行确认。结果以 structuredContent 的形式返回,其类型由各工具的 outputSchema 定义;同时也会在文本块中重复相同的 JSON,以兼容较旧的客户端。完整定义位于 mcp-tools.json,该文件由服务器生成。

工具只读具有破坏性幂等开放世界
tailnet_status是否是否
share_status是否是否
ping_all是否是否
generate_ssh_config否(仅在 write: true 时写入)否是否
share_port否否是仅在允许 Funnel 时
stop_share否是是否
tailnet_status

精简版的 tailscale status --json 视图:包含自身节点,以及具有主机名、MagicDNS 名称、Tailscale IPv4/IPv6、操作系统、在线标志、上次活动时间、出口节点标志和标签的对等节点。输入:可选的 onlineOnly。

{
  "backendState": "Running",
  "tailnet": "[email protected]",
  "magicDNSSuffix": "tail1234.ts.net",
  "self": {"hostname": "DEVPC", "dnsName": "devpc.tail1234.ts.net", "ipv4": "100.101.1.10"},
  "peerCount": 3,
  "peers": [
    {"hostname": "raspi", "dnsName": "raspi.tail1234.ts.net", "ipv4": "100.101.1.20", "os": "linux", "online": true, "exitNodeOption": true, "tags": []}
  ]
}
generate_ssh_config

为 tailnet 节点生成 ssh-config Host 块(优先使用 MagicDNS 名称,回退到 Tailscale IP)。默认进行试运行:仅返回生成的文本。输入:write、target、onlineOnly、includeShared、user。

  • 每个 Host 别名都是节点的第一个 MagicDNS 标签(raspi.tail1234.ts.net → raspi),若没有则回退到经过净化的操作系统主机名(仅允许 [a-z0-9-])。别名冲突时会添加数字后缀,并列在 renamed 下。Mullvad 出口节点以及你共享给其他用户的节点(除非 includeShared: true)会被排除,并列在 skipped 下。
  • write: true 会写入专用文件 ~/.ssh/tailscale_dev_config,并返回添加到 ~/.ssh/config 的 Include tailscale_dev_config 指令(不会自动应用)。
  • target: "user_ssh_config"(同时设置 write: true)会直接编辑 ~/.ssh/config,在 # BEGIN tailscale-mcp 和 # END tailscale-mcp 标记之间以幂等方式更新。标记之外的内容绝不会被修改。如果标记格式错误(孤立、顺序颠倒或重复),工具会返回 SSH_CONFIG_MARKERS_CORRUPT,且不会写入任何内容。
  • 写入采用原子方式(临时文件 + 重命名),此前的 ~/.ssh/config 会保留为 config.tailscale-mcp.bak,新文件会以 0600 权限创建(保留现有文件的权限),符号链接配置文件会通过链接写入,而不会替换链接。
{
  "dryRun": true,
  "hostCount": 2,
  "configText": "# BEGIN tailscale-mcp\nHost raspi\n    HostName raspi.tail1234.ts.net\n\nHost devbox\n    HostName devbox.tail1234.ts.net\n# END tailscale-mcp"
}
share_port

通过 Tailscale Serve 共享本地端口。默认仅限 tailnet。 输入:port(必需)、public、path。

{"port": 3000, "public": false, "scope": "tailnet-only (Serve)", "urls": ["https://devpc.tail1234.ts.net/"]}

public: true 会切换到 Funnel,将端口暴露给开放互联网。除非设置了 TAILSCALE_MCP_ALLOW_FUNNEL=1,否则会拒绝此操作;请参阅下方的安全说明。

share_status

将活动的 Serve/Funnel 会话作为结构化端点报告,数据解析自 tailscale serve status --json。每个端点都有自己的 public 标志;当 Funnel 将其公开到互联网时,该标志为 true。只要有任何内容公开,publicExposure 就为 true:

{
  "active": true,
  "publicExposure": true,
  "endpoints": [
    {"url": "https://devpc.tail1234.ts.net/", "host": "devpc.tail1234.ts.net", "httpsPort": 443, "scheme": "https", "path": "/", "target": "http://127.0.0.1:3000", "targetType": "proxy", "public": true, "foreground": false}
  ]
}

原始 TCP 转发会显示在 tcpForwards 下。对于不支持 --json 的旧版 CLI,文本状态会出现在 status 下,且 publicExposure 为 null。

stop_share

停止共享。必须准确指定一个目标:

  • httpsPort 和/或 path 会关闭一个挂载。httpsPort 是 share_status 中显示的 Serve 端口(默认为 443,而非代理的本地端口),path 是传给 share_port 的挂载路径(默认为 /)。例如,{"path": "/api"} 会撤销 share_port {"port": 3000, "path": "/api"}。
  • mine: true 只会停止此服务会话期间由 share_port 创建的共享。
  • all: true 会清除整个 serve/funnel 配置,包括你在此服务之外设置的共享。

不提供参数时不会停止任何内容:工具会返回 TARGET_REQUIRED 并列出活动端点。每次成功调用都会返回 removed(已移除的端点)和 remaining(之后的 share_status 视图)。

挂载路径必须以 / 开头,且只能包含字母、数字和 . _ ~ - /,不能有 . 或 .. 路径段。末尾的斜杠会被移除。

ping_all

对节点并发执行 tailscale ping(最多同时进行 5 次,并设置每次 ping 的超时时间)。输入:count、timeoutMs、onlineOnly(默认值为 true)。

{
  "pinged": 2,
  "reachable": 1,
  "timedOut": false,
  "matrix": [
    {"hostname": "raspi", "target": "100.101.1.20", "reachable": true, "latencyMs": 3, "path": "direct", "via": "192.168.1.20:41641", "attempts": 3, "replies": 3},
    {"hostname": "exitbox", "target": "100.101.1.40", "reachable": false, "latencyMs": null, "path": null, "via": null, "attempts": 1, "replies": 0}
  ]
}

path 的值为 direct(点对点)、derp(通过 Tailscale DERP 服务中继)、peer-relay(通过你的某个节点中继)或 unknown,因此 Agent 可以区分“可用但通过中继”与“快速直连路径”。tailscale ping 会持续 ping,直到建立直连路径,因此 path 和 latencyMs 描述的是最后一次回复,也就是稳定后的路径。整个调用最长持续 45 秒:届时仍未回复的节点会返回 error 和 timedOut: true。

Agentic 工作流示例

如果 Agent 接到“将此部署到我的开发 VPS 并展示结果”的请求,可以通过此服务完成整个发现过程:

  1. tailnet_status {"onlineOnly": true} 会找到 VPS 节点及其 MagicDNS 名称(devbox.tail1234.ts.net),无需硬编码 IP。
  2. generate_ssh_config {"write": true, "user": "deploy"} 会写入 ~/.ssh/tailscale_dev_config;Agent 会显示返回的单行 Include 指令,用户添加后,ssh devbox 就会通过 tailnet 解析。
  3. ping_all 会确认节点是否可达,以及路径是直连还是中继,然后再开始大规模传输。
  4. 部署完成后,share_port {"port": 8080} 会返回一个仅限 tailnet 访问的 URL,tailnet 上的队友可以打开。除非你已通过 TAILSCALE_MCP_ALLOW_FUNNEL=1 启用 Funnel,且明确告知 Agent 传入 public: true,否则不会有任何内容暴露到公共互联网。

Funnel 安全说明

  • share_port 默认为仅限 tailnet 的 Serve。tailnet 之外无法访问任何内容。
  • 除非你主动启用,否则 Funnel 处于关闭状态。 public: true 会使用 Tailscale Funnel,使 URL 可被互联网上的任何人访问,而不仅限于你的 tailnet。默认安装会拒绝此操作并返回 FUNNEL_DISABLED,因此遭到提示词注入的 Agent 无法自行暴露端口。若要允许此操作,请在客户端配置中设置 TAILSCALE_MCP_ALLOW_FUNNEL=1。即便如此,工具描述仍会附带警告,因此 Agent 会在操作前提示用户。
  • TAILSCALE_MCP_READONLY=1 会完全移除共享工具,适用于只能观察的 Agent。
  • 必须在管理控制台中为每个 tailnet 启用 Serve 和 Funnel。未启用时,工具会返回结构化的 SERVE_NOT_ENABLED 错误,其中包含准确的启用 URL,且不会进行任何更改。
  • stop_share {"all": true} 是紧急停止开关:它会清除整个 serve/funnel 配置。不带参数调用时绝不会删除任何内容。
  • 此服务绝不会读取或存储 TS_AUTHKEY 或任何其他凭据。

开发

npm install
npm run build      # tsc
npm test           # vitest, fully offline (fixture-driven, no live tailnet)
npm run typecheck  # src and tests
npm run gen:tools  # regenerate mcp-tools.json after changing a tool

要在自己的 tailnet 上试用构建版本,请在 MCP Inspector 中运行:

npm run build
npx @modelcontextprotocol/inspector node dist/index.js

提供程序适配器模式:src/providers/types.ts 定义了 TailscaleProvider 接口;CliProvider(目前唯一的实现)通过可注入的进程运行器启动 CLI,因此测试不会启动真实的二进制文件。该接口为未来通过本地套接字或命名管道使用 HTTP 通信的 LocalAPI 提供程序预留了空间。

项目结构

tailscale-mcp/
  src/index.ts        stdio entry point
  src/config.ts       Environment variable parsing
  src/providers/      TailscaleProvider interface + CliProvider
  src/tools/          MCP tool registrations and output schemas
  src/sshconfig.ts    Pure ssh-config rendering and managed-block editing
  src/__tests__/      vitest suites (offline, mocked CLI runner)
  test/fixtures/      Sanitized CLI output used by the tests
  mcp-tools.json      Generated tool definitions (npm run gen:tools)
  docs/               GitHub Pages site
  .github/            CI/CD workflows

路线图

完整的项目路线图请参阅 ROADMAP.md。

贡献

贡献指南请参阅 CONTRIBUTING.md。

许可证

CC-BY-NC-ND-4.0——详情请参阅 LICENSE。


由 TMHSDigital 构建

评论

支持 Markdown

第一次接触 MCP?

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

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