mcpField
T
Tailscale MCP Server

Tailscale MCP Server

本地服务
yaw.sh云与基础设施351 周前更新

关于 Tailscale MCP Server

Tailscale MCP Server 将 Tailscale v2 管理 API 提供给 AI 助手,用于交互式管理 tailnet。它面向希望通过结构化工具跨设备、ACL、DNS、密钥、用户等领域组合读取和变更操作的管理员。

主要功能

  1. 01覆盖广泛的 Tailscale v2 管理 API
  2. 02提供类型化工具和结构化响应
  3. 03可配置工具组和只读模式
  4. 04通过写入提示控制变更确认
  5. 05可选本地 CLI 诊断和 API 资源

适用场景

  1. 01按最近活动时间或密钥过期设置查找设备
  2. 02审阅并总结 DNS 相关的审计变更
  3. 03起草并验证 ACL 变更
  4. 04轮换已使用较久的身份验证密钥

MCP 相关

该服务向 MCP 客户端提供 97 个管理 API 工具、6 个可选本地 CLI 诊断工具、一个目录工具和 4 项资源。工具组和只读设置用于控制可用能力。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"yawlabs-tailscale": {
"command": "npx",
"args": [
"-y",
"@yawlabs/tailscale-mcp"
]
}
}
}
启动命令npx -y @yawlabs/tailscale-mcp

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

安装包
npm@yawlabs/tailscale-mcp0.23.0

工具

98

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

参数类型必填说明
toolNamestring否要查询的特定工具,例如 'tailscale_delete_device'。省略则列出所有组。

详细介绍

@yawlabs/tailscale-mcp

添加到 Yaw MCP

点击一次即可将其添加到本地 Yaw MCP 配置,让你在每个 Yaw Terminal 会话中都能使用。也可以按照下文手动安装。

npm 版本 许可证:MIT GitHub 星标数 发布

向 Agent 询问有关 tailnet 的问题,并让它根据答案采取行动。 97 个管理 API 工具 + 6 个可选的本地 CLI 诊断工具 + 1 个始终启用的目录工具 + 4 个资源,覆盖 Tailscale v2 API 的设备、ACL、DNS、密钥和信任凭据、用户、邀请、Webhook、日志流、Posture、服务和组织 tailnet。由 1900 多个单元测试和一套选择加入的实时 tailnet 集成测试提供支持。

由 Yaw Labs 构建并维护。

如果 API 已经存在,为什么还需要这个工具?

你可以使用 curl 调用 Tailscale API。它的目的不是取代 curl,而是让 Agent 无需编写脚本,就能在一次交互中组合多个端点,完成工作流:

  • “哪些设备已 30 天未签到,且禁用了密钥过期?” — 列出设备,按 lastSeen 筛选(在线设备没有该字段),再按 keyExpiryDisabled 筛选,并返回表格。三个端点,一个问题。
  • “凌晨 2 点有人弄坏了 DNS——过去 24 小时内是谁改了什么?” — 拉取审计日志,筛选与 DNS 相关的操作人和端点,读取每项更改的前后内容,并用英文总结。
  • “起草一项 ACL 更改,让 tag:mobile 可以访问 tag:dashboard,但不能访问 tag:db,同时保留我的注释。” — 读取当前 HuJSON,提出最小化差异,根据 API 验证,并返回差异供你应用。
  • “轮换所有超过 90 天的身份验证密钥,并打印新密钥。” — 遍历密钥,创建带有匹配标签的新密钥,并撤销旧密钥。
  • “为我们的 CI 流水线创建一个 OAuth 客户端,权限限定为 devices:core:read 和 dns:read。” — 通过 tailscale_create_key 创建信任凭据,设置 keyType=client,并仅返回一次凭据(请立即保存)。

curl 可以完成每一步。Agent 则能将它们组合起来。这正是它的价值所在,也是这些工具的设计目标——每个读取端点都是一等功能,方便 Agent 综合信息;每个写入端点都标记了 destructiveHint 或 idempotentHint,因此 MCP 客户端可以按照你的配置限制变更操作。

如果你只需要在 CI 作业中调用一个端点,请使用 curl——针对常见的从 Git 部署 ACL 场景,我们还提供了一个 CLI 子命令。MCP 适用于交互式、探索性的“我还不知道自己需要什么”工作。

为什么选择 MCP,而不是技能或 tailscale CLI?

问得好。两者各有用武之地。MCP 更胜一筹的地方:

  • 广泛覆盖管理 API。 tailscale CLI 的作用范围仅限于运行它的节点。ACL、用户、邀请、webhook、日志流、态势集成、身份验证密钥、OAuth 客户端和联合身份等管理功能,都位于 v2 HTTP API 中。你最终还是得调用 curl。
  • 类型化的工具接口,而非字符串解析。 每个工具都有经过 Zod 验证的输入架构和结构化响应。无需依赖脆弱的 tailscale status --json | jq 管道,也不用担心它们会在架构演进时失效。
  • 可供不同客户端使用,更新通过版本升级提供。 MCP 服务可用于 Claude Code、Claude Desktop、Cursor、Windsurf、VS Code 以及任何支持 MCP 的产品;符合 Agent Skills 标准的技能也能在不同 Agent 间使用,但它本质上是需要你维护的文本。更新通过 npx 发布——Tailscale 新增端点时,无需任何人重写技能说明。
  • 默认安全的写入操作。 每个工具都声明了 readOnlyHint / destructiveHint / idempotentHint,客户端因此可以跳过读取操作的确认,并要求确认变更操作。通过技能调用 CLI 则无法表达这些信息。
  • 真正的测试。 1900 多个单元测试覆盖每个工具的输入验证、API 结构和错误处理。此外,还有一个可选的实时 tailnet 集成测试套件(RUN_INTEGRATION_TESTS=1 + tailnet API 密钥),用于检测结构漂移。大多数技能只是没有专属测试层的简短 Markdown 提示词——如果供应商更改输出格式,没有任何机制会替你发现。

如果你已经有技能覆盖了 10% 的 Tailscale 工作流,那很好——继续使用。MCP 面向的是另外 90%。

Tailscale 自己的 MCP 端点和技能呢? 截至 2026-09-19,它们解决的是不同的问题,这里没有重复实现任何功能。Tailscale 的官方 MCP 工具是 Aperture 中两个 Alpha 版内置连接器:Tailnet 的 Tailnet_provision_node 会返回一次性身份验证密钥,让 Agent 在人员批准后加入一个新节点;Tailscale SSH 的 TailnetSSH_list_machines 和 TailnetSSH_run_command 会发现已启用 SSH 的机器,并在其中一台上运行一条命令。它们需要 Aperture。 tailscale/tailscale-skill 是一个 Alpha 版、仅提供知识的技能——它是参考资料,教 Agent 如何通过 curl 调用 v2 API,本身不提供服务。两者都不将管理 API 暴露为类型化工具,因此与本服务几乎没有重叠。Aperture 目前也无法代理本服务:本服务使用 stdio 通信,而 Aperture 只代理可通过 URL 访问的 Streamable-HTTP 或 SSE 服务。这两款产品都处于 Alpha 阶段,因此请将本段落中的日期视为其有效期的截止日期。

可信度依据

Reddit 上有人提出了公允的批评:一个声称“积极维护”却没有可见测试的新仓库,可信度确实为零。以下是实际可验证的内容:

  • 1900 多个测试(node --test),覆盖每个工具的输入验证、API 结构和错误处理。运行 npm test,即可在本地查看测试通过。
  • 本地发布流程,通过 release.sh 完成:从工作站执行 lint、测试、版本升级、打标签、推送、npm 发布和 MCP Registry 发布。无需维护 CI 工作流。
  • Dependabot 警报会显示在此仓库中,并会得到修复,而不是被忽略。
  • 每个工具都对应 OpenAPI 规范中的真实端点。 如果某个工具出现在工具列表中,它调用的就是当前 v2 API 中有文档记载的路径——没有占位用的 404 工具。需要明确其局限:此仓库没有附带任何已记录的实时交互(fixtures/live/ 有意保持为空),这里的任何说法也都不是基于对实时 tailnet 的观测。

问题和 PR 都会进行分流处理。如果发现问题,请提交一个——github.com/YawLabs/tailscale-mcp/issues。

快速开始

1. 设置 API 密钥

在 Tailscale Admin Console > Settings > Keys 获取 API 密钥,并将其设置为 MCP 客户端可读取的值。第 2 步中的 .mcp.json env 区块在所有平台上的用法都相同,也是首选方式;如果想改为在 shell 配置文件中导出(~/.bashrc、~/.zshrc、~/.config/fish/config.fish):

macOS / Linux / WSL(bash、zsh):

export TAILSCALE_API_KEY="tskey-api-..."

fish:

set -Ux TAILSCALE_API_KEY tskey-api-...

Windows(PowerShell 5.1 和 7)——[Environment]::SetEnvironmentVariable 会将设置持久保存到当前用户;而 $env: 仅在当前会话期间有效:

[Environment]::SetEnvironmentVariable('TAILSCALE_API_KEY', 'tskey-api-...', 'User')

2. 在项目根目录创建 .mcp.json

macOS / Linux / WSL:

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

Windows:

{
  "mcpServers": {
    "tailscale": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "@yawlabs/tailscale-mcp@latest"]
    }
  }
}

为什么 Windows 上还要多做一步? 在 Windows 上,npx 是一个 .cmd 文件,而 Node 20+ 会拒绝直接启动 .cmd 文件。用 cmd /c 包装是标准的解决方法。

3. 重启并批准

重启 Claude Code(或你的 MCP 客户端),并在出现提示时批准 Tailscale MCP 服务。

就是这么简单。现在可以向你的 Agent 提问:

“列出过去 7 天内未被检测到的 Tailscale 设备”

“总结审计日志中昨天发生的所有 ACL 变更”

“起草一条 ACL 规则,仅允许 tag:ci 通过端口 5000 访问 tag:registry”

工具太多?缩减工具集。

97 个工具确实不少。如果你已经配置了十几个 MCP 服务,并且客户端开始变得臃肿,可以缩减此服务公开的工具。可组合使用以下三个选项:

下面的 env 区块仅显示正在讨论的变量。凭据来自环境,按快速开始中的说明设置即可——请将凭据保存在 shell 配置文件中,而不要放进客户端的 JSON 配置中;大多数系统上的该配置都可被所有用户读取,也很容易意外提交到版本库。

选项 1:TAILSCALE_PROFILE(预设,最简单)
{
  "env": {
    "TAILSCALE_PROFILE": "core"
  }
}
  • minimal(20 个工具)——status、devices、audit。查看 tailnet 状态并读取审计日志。
  • core(52 个工具)——增加 acl、dns、keys、users。日常管理所需的工具集。
  • full(97 个工具,默认)——全部工具。与省略环境变量相同。

配置名称不区分大小写,并会忽略前后空格(Core 会选择 core)。TAILSCALE_TOOLS 和 TAILSCALE_WRITE_GROUPS 中的组名区分大小写。

选项 2:TAILSCALE_TOOLS(显式指定组列表)
{
  "env": {
    "TAILSCALE_TOOLS": "devices,acl,dns,audit"
  }
}

以逗号分隔的组名。如果两者都已设置,该选项会覆盖 TAILSCALE_PROFILE——当预设不完全符合需求时使用此选项。

有效组名:status、devices、acl、dns、keys、users、tailnet、org-tailnets、webhooks、posture、audit、invites、services、log-streaming。也可使用 local-cli 组,但仅当设置了 TAILSCALE_LOCAL_CLI=1 时可用——请参阅本地 CLI 集成(选择启用)。

选项 3:TAILSCALE_READONLY(移除变更操作)
{
  "env": {
    "TAILSCALE_PROFILE": "core",
    "TAILSCALE_READONLY": "1"
  }
}

设置为 1 或 true,即可移除所有未带有 readOnlyHint: true 的工具。此选项可与 TAILSCALE_PROFILE 或 TAILSCALE_TOOLS 叠加使用,效果为取交集——组合使用可最大限度精简工具集。

确认已加载的配置

服务启动时会将当前生效的筛选条件记录到 stderr:

@yawlabs/tailscale-mcp v0.22.0 ready (20 tools, profile=minimal, readonly)

如果同时设置了 TAILSCALE_PROFILE 和 TAILSCALE_TOOLS,则以 TAILSCALE_TOOLS 为准。横幅会标记配置文件已被覆盖,让优先级一目了然——无需猜测实际应用了哪个筛选条件:

@yawlabs/tailscale-mcp v0.22.0 ready (22 tools, profile=core (overridden by TAILSCALE_TOOLS), groups=devices,acl)

仅当使用实质性配置文件(minimal / core)时,才会显示“(overridden)”标记;profile=full 是无操作的预设,因此若同时设置了 TAILSCALE_TOOLS,则不会显示该标记。

如果未设置任何筛选条件,启动时会打印一条提示,指引你使用预设配置。

Agent 如何感知

以上内容都输出到 stderr——也就是 MCP 客户端的日志。模型看不到这些内容,因此被隐藏的工具和从未实现的工具,在 Agent 看来完全一样。这就是 Agent 最终会绕过限制,而不是报告限制的原因。

tailscale_tool_groups 可以弥补这一点。无论筛选条件如何,它始终都会注册,并以内联方式回答这个问题:

> "Why can't you delete that device?"

  tailscale_tool_groups({ toolName: "tailscale_delete_device" })

  {
    "tool": "tailscale_delete_device",
    "available": false,
    "group": "devices",
    "kind": "write",
    "reason": "TAILSCALE_WRITE_GROUPS is set to \"dns\", which does not grant writes here",
    "toEnable": "add \"devices\" to TAILSCALE_WRITE_GROUPS (e.g. \"dns,devices\")"
  }

它能区分 Agent 原本无法区分的三种情况:

情况Agent 应采取的操作
在任何配置下都不存在此工具寻找其他方法——没有任何设置能启用它
工具存在,但所属组未加载将 toEnable 报告给你;不要绕过限制
工具存在且已加载,但其中的写入操作被隐藏同上——应由你修复,而不是绕过限制

不带参数调用时,它会列出每个组及其可用性;对于任何被隐藏的组,还会列出恢复这些操作所需的确切环境变量更改。它不读取网络,也不需要凭据,因此即使服务配置错误,也能正常工作。

将写入权限限定到特定范围

TAILSCALE_WRITE_GROUPS 用于指定 Agent 可以写入的范围。其他所有内容仍可读取:

{
  "env": {
    "TAILSCALE_WRITE_GROUPS": "devices,keys"
  }
}

这样会提供全部 41 个读取工具,以及 devices 和 keys 组中的 18 个写入工具,并隐藏其他 38 个写入工具——ACL、DNS、用户、tailnet、webhooks、posture、services、invites、org-tailnets 和 log-streaming 的写入工具都不会注册。未设置时不限制写入,这是默认配置。

请先阅读:此设置筛选的是工具列表,而不是 API 令牌。 无论配置如何,服务仍持有一个对整个 tailnet 拥有完全权限的凭据。拥有 shell 的 Agent 可以使用同一个令牌执行 curl api.tailscale.com,完成此设置所隐藏的所有操作。请将 Tailscale OAuth 客户端本身限制为你实际需要的范围(各工具组的范围)——这种限制在此进程之外仍然有效,而此设置则不然。TAILSCALE_WRITE_GROUPS 是一种低门槛的凭据范围限制补充手段,而非替代方案。

授权实际包含什么

组名与 TAILSCALE_TOOLS 使用的相同。各组的写入工具如下:

组写入工具组写入工具
devices13webhooks5
invites7posture3
dns6services3
keys5tailnet3
users5log-streaming3
org-tailnets2acl1

status、audit 和选择启用的 local-cli 组都不包含任何写入工具,因此授予这些组不会产生任何作用。

devices 是范围最广、也最可能被设置的授权。 在 compose 文件中,write=devices 看起来像是“设备管理”,但它会同时授权 delete_device、set_devices_authorized、expire_device、deauthorize_device、set_device_routes、set_device_tags 和 update_device_key,以及 rename_device。没有更细粒度的设置:严格来说,devices 组中“安全的子集”只有 rename_device;而一个有用值仅限于单个工具的设置,也就失去了设置的意义。

三种授权等同于 tailnet 管理员权限

keys、users 和 acl 不会被阻止——CI 的密钥轮换确实需要 keys——但授予这些权限时请知悉:

  • keys — tailscale_create_key 会创建一个 OAuth 客户端,其范围由调用方指定,包括 policy_file 和 all。该凭据的有效期会超过 Agent 的会话,并且不受此处任何设置限制。
  • users — tailscale_update_user_role 接受 owner。
  • acl — tailscale_update_acl 会重写 tailnet 中所有主体的策略。

如果你的授权包含其中任何一项,服务会在启动时打印此提示。

它限制什么,以及不限制什么

它限制 Agent 可以在哪些区域写入,但不限制已授权区域内操作的严重程度:在已授权的组内,写入会在无人监督的情况下执行,包括那些会改变授权方向的操作。当有人在键盘前操作时,可以将它与 TAILSCALE_REQUIRE_APPROVAL=1 配合使用;但请注意,对于无人值守的 Agent,这种配合毫无作用,因为永不弹出提示的客户端会拒绝这些调用,而不是弹出提示。

优先级,以及配置错误时会发生什么
情况结果
未设置、为空、仅含空白字符或仅含逗号不启用写入限制。-e VAR 未指定值时,不得默默撤销所有写入权限。
同时设置了 TAILSCALE_READONLY=1只读设置优先;横幅显示 readonly (TAILSCALE_WRITE_GROUPS ignored)。
名称拼写错误(devises)不授予任何权限,并指出拼写错误。与 TAILSCALE_TOOLS 不同,这里没有回退机制——如果拼写错误的写入授权触发回退,就会在你正要限制写入时交出全部 56 项写入权限。
部分拼写错误(devices,dnss)授予有效部分的权限,并对其余部分发出警告。
已授权的组未由 TAILSCALE_TOOLS / TAILSCALE_PROFILE 加载该授权不起作用;系统会另外发出警告,因为这不是拼写错误。
none、all、off、*这些不是保留字,而是未知组名,因此不会授予任何权限。若要禁止写入,请使用 TAILSCALE_READONLY=1;若要允许所有写入,请将此项留空。服务会提示正确的写法。

名称区分大小写,与 TAILSCALE_TOOLS 一致。

升级承诺:升级此软件包绝不会扩大 Agent 可以写入的区域范围。新组不会自动获得任何人的授权,必须由人手动输入组名。不过,升级可能会在你已授权的区域内添加工具;固定测试会确保这一变更在差异中经过审核,而非悄然发生。

启动横幅会显示生效的配置:

@yawlabs/tailscale-mcp v0.22.0 ready (59 tools, write=devices,keys)

要求不可逆工具的批准

readOnlyHint / destructiveHint 只是建议性提示——MCP 规范规定客户端必须将注释视为不可信信息,而且大多数客户端不会据此限制操作。TAILSCALE_REQUIRE_APPROVAL=1 会发出更强的信号,受支持的客户端会强制执行:

{
  "env": {
    "TAILSCALE_REQUIRE_APPROVAL": "1"
  }
}

随后,九个工具会附带 _meta["anthropic/requiresUserInteraction"],即使允许规则本会自动批准调用,也会强制显示确认提示:

工具列入原因
tailscale_update_acl可能会让 tailnet 中的所有设备都无法访问;除非你已保存之前的 HuJSON(包括注释),否则它将不复存在
tailscale_delete_device该设备必须重新注册
tailscale_delete_user无法撤销删除
tailscale_delete_tailnet会销毁整个 tailnet
tailscale_delete_key不会再次返回该密钥
tailscale_delete_oauth_app同上
tailscale_delete_webhook同上
tailscale_delete_log_stream_config同上
tailscale_delete_posture_integration同上

判断标准是**“此服务无法利用你仍持有的信息撤销操作”**,其范围比标注了 destructiveHint: true 的 23 个工具更窄。tailscale_suspend_user 被刻意排除在外,因为可以用 tailscale_restore_user 撤销该操作。tailscale_deauthorize_device 也同样如此(可用 tailscale_authorize_device 撤销),以及那些提供 get_* 对应工具、可在写入前读取的全量替换设置工具。

请务必自行选择启用,并在启用前阅读以下内容。 在从不显示提示的客户端模式下(例如无人值守的 Agent 或 CI 运行),此标志会拒绝这些调用,而不是执行它们。有人在键盘前时,这才是正确的默认行为;无人值守时则不合适,因此除非你主动设置,否则该功能保持关闭。

需要客户端支持此注释;Claude Code 从 v2.1.199 开始支持。无法识别该注释的客户端会忽略它,因此设置此变量不会比保持关闭更糟。

此外,以下工具始终会声明 _meta["anthropic/maxResultSizeChars"]:它们的响应大小取决于 tailnet 的规模,而非请求本身——tailscale_list_devices、tailscale_list_users、tailscale_get_acl、tailscale_diff_acl_access、tailscale_get_audit_log、tailscale_get_network_flow_logs、tailscale_local_status。这样一来,较大但合理的结果会保留在内联内容中,而不会被截断成文件引用,导致 Agent 必须在任务进行中再读回文件。最后一个工具需要选择启用:只有在 TAILSCALE_LOCAL_CLI=1 注册该工具时,它才会声明上限;否则该工具完全不存在。

与 mcp.hosting / mcph 配合使用

如果你通过 mcp.hosting 运行此服务(使用 @yawlabs/mcph 本地 Agent),这两层过滤可以无缝配合:

  1. 服务端——TAILSCALE_PROFILE / TAILSCALE_TOOLS / TAILSCALE_READONLY 会在 mcph 获取工具之前缩减工具范围。未加载的工具根本不会注册。
  2. 客户端——mcph 的 mcp_connect_activate({ tools: [...] }) 会进一步筛选 tools/list 中显示的工具。未列入该列表的工具仍可通过 mcp_connect_dispatch 访问,因此不会失去功能。

推荐 mcph 用户采用以下模式:在 mcp.hosting 服务配置中设置 TAILSCALE_PROFILE=core(或更精简的配置),然后让 mcph 在此基础上处理各会话的工具激活。这样,服务默认保持精简,而 mcp_connect_dispatch 则可满足临时需求所需的长尾工具。

身份验证

API 密钥(最简单): 在 shell 或 MCP 配置中设置 TAILSCALE_API_KEY。

OAuth(限定范围的访问): 如需精细权限,请改为设置 TAILSCALE_OAUTH_CLIENT_ID 和 TAILSCALE_OAUTH_CLIENT_SECRET。在 Tailscale Admin Console > Settings > Trust credentials 创建 OAuth 客户端,并授予你加载的工具组所需的下列范围。

服务会先检查 API 密钥,然后再回退到 OAuth。如果两者都未设置,工具会返回清晰的错误,告知你需要配置什么;服务仍会启动,因此 MCP 客户端不会陷入反复重启。

Tailnet: 默认自动使用凭据所属的 tailnet(-),这适用于大多数设置。如需明确指定,请将 TAILSCALE_TAILNET 设置为管理控制台中 Settings > General 下显示的 Tailnet ID,格式类似 T1234CNTRL。在 2025 年 10 月之前创建的 Tailnet 仍可使用其旧版组织名称;较新的 Tailnet 没有可用的此类名称。根据 OpenAPI 规范,无论哪种情况,Tailnet ID 都是首选标识符。

TAILSCALE_OAUTH_TAILNET — 指定目标为 仅供 API 使用的 tailnet(通过 tailscale_create_org_tailnet 创建)。使用普通的客户端凭据交换无法访问这些 tailnet:你需要使用属于创建该 tailnet 的 OAuth 客户端(all 范围)进行身份验证,并在令牌请求中指定目标。将此项设置为新 tailnet 的 ID。此设置刻意与 TAILSCALE_TAILNET 分开,以免更改其他用户的默认令牌交换行为。如果设置了此项,请将 TAILSCALE_TAILNET 留空(或设为 -),以便工具请求遵循令牌指定的目标——如果两者指向不同的 tailnet,所有限定 tailnet 的工具都会返回 403,且服务会在启动时发出警告。

按工具组划分的 OAuth 范围

OAuth 客户端为每个 TAILSCALE_TOOLS 组所需的范围。为你加载的组授予“读取”列中的范围,并为你允许其修改内容的组添加“写入”列中的范围;“备注”列列出各组除此之外的需求。all:read(所有读取范围)和 all(所有权限)是最宽泛的授权范围。

分组读取写入备注
statusdevices:core:read、feature_settings:read无读取设备列表和 tailnet 设置;即使其中一项遭到拒绝,仍会返回另一项。
devicesdevices:core:read、devices:routes:read、devices:posture_attributes:readdevices:core、devices:routes、devices:posture_attributes路由工具使用 devices:routes 读写权限对,态势属性工具使用 devices:posture_attributes 读写权限对;其余工具使用 devices:core。持有 devices:core 的凭据必须至少关联一个标签。
aclpolicy_file:read、devices:core:read、devices:posture_attributes:readpolicy_file、devices:posture_attributesTailscale 要求除 policy_file:read 和 policy_file 外,还须具备设备权限范围。如果省略 principals,由 tailscale_diff_acl_access 自行列出用户,则还需要 users:read。
dnsdns:readdns未经验证。 OpenAPI 规范没有为任何 DNS 操作指定权限范围,而这些权限范围的来源——信任凭据文档——未列出 /dns/configuration。该端点是 tailscale_get_dns_configuration 和 tailscale_set_dns_configuration 所使用的端点。
keysauth_keys:read、oauth_keys:read、federated_keys:read、api_access_tokens:read、oauth_apps:readauth_keys、oauth_keys、federated_keys、api_access_tokens、oauth_apps密钥权限范围按密钥类型划分:auth_keys 用于身份验证密钥,oauth_keys 用于 OAuth 客户端,federated_keys 用于联合身份,api_access_tokens 用于个人 API 访问令牌(仅支持读取和删除)。只授予你要管理的类型;只有 all:read 和 all 能列出 tailnet 中的所有访问令牌。OAuth 应用工具使用 oauth_apps;如果 tailscale_create_oauth_app 发送 allowedNodeAttributes,还需要 devices:posture_attributes。
usersusers:readusers
tailnetfeature_settings:read、account_settings:readfeature_settings、account_settings设置按字段划分:网络流日志需要 logs:network:read / logs:network,HTTPS 证书需要 networking_settings:read / networking_settings,两个由外部管理的 ACL 字段需要 policy_file:read / policy_file;其余设置由 feature_settings 管理。联系人工具使用 account_settings。
org-tailnetstailnets:readtailnetstailscale_delete_tailnet 需要 all(参见上文的 TAILSCALE_OAUTH_TAILNET)。
webhookswebhooks:readwebhooks
posturefeature_settings:readfeature_settings同一权限范围也控制大多数 tailnet 设置,因此能够管理态势集成的客户端也能更改这些设置。
auditlogs:configuration:read、logs:network:read无tailscale_get_audit_log 使用第一项,tailscale_get_network_flow_logs 使用第二项。
invitesdevice_invites:readdevice_invites(仅删除)无法使用 OAuth 客户端的令牌创建、重新发送或接受设备邀请(tailscale_create_device_invite、tailscale_resend_device_invite、tailscale_accept_device_invite);创建、删除和重新发送用户邀请(tailscale_create_user_invite、tailscale_delete_user_invite、tailscale_resend_user_invite)则仅允许使用用户所有的密钥。请为这些操作使用 TAILSCALE_API_KEY。规范未为读取用户邀请指定权限范围。
servicesservices:readservicestailscale_list_service_hosts、tailscale_get_service_device_approval 和 tailscale_set_service_device_approval 都需要 services 和 devices:core,因此其中两个读取工具无法用于只读客户端。
log-streaminglog_streaming:readlog_streaming向私有端点进行流式传输还需要 device_invites 和 policy_file。tailscale_create_aws_external_id 和 tailscale_validate_aws_trust_policy 都需要 log_streaming,尽管第二个是读取操作。
local-cli无无运行本地 tailscale 二进制文件,不调用管理 API。
作用域取自截至 2026-09-19 的 Tailscale OpenAPI 规范。该规范未列出的 DNS 行,以及 acl 行中的设备作用域,取自信任凭据文档。所有内容均来自文档,而非在 tailnet 上实测。

可靠性与调试

429 和网关错误重试(内置)。 对幂等方法(GET、PUT、DELETE)收到的 HTTP 429、502、503 和 504,最多重试 3 次,并遵循 Retry-After 标头(支持整数秒和 HTTP 日期两种格式)。若没有该标头,则使用带抖动的指数退避,每次等待最长 30s。无需设置环境变量——默认启用。像“轮换所有超过 90 天的密钥”这样的工作流,不会再因 Tailscale 的每租户速率限制而在循环中途失败;网关短暂故障也不会再导致整个工具调用失败:根据 OpenAPI 规范,每项设备和服务操作都注明可能返回 504,错误消息为“请求处理时间过长,请稍后重试”;日志读取操作则注明可能返回 502。HTTP 500 不会重试——这表示服务器未能处理请求,而不是前置服务放弃了请求。无论状态码如何,POST 和 PATCH 都不会重试。如果 DELETE 在网关错误后重试,随后收到 404,错误信息会说明这一点,因为超时的那次尝试可能已经删除了资源。

TAILSCALE_DEBUG=1 — 将每个 HTTP 方法、URL、状态码和耗时记录到 stderr。绝不会记录 Authorization 标头。当工具返回意外错误,而你想查看实际发出的请求时,可使用此选项。示例:

[tailscale-mcp] GET https://api.tailscale.com/api/v2/tailnet/-/devices
[tailscale-mcp]   <- 200 (148ms)

TAILSCALE_MAX_CONCURRENT=N — 将正在处理的 API 请求数限制为 N。默认不设上限(不选择启用的用户不会有任何行为变化)。当 Agent 向限制比单次调用重试所能应对的限制更严格的 tailnet 大量并发发起请求时,此选项很有用。

TAILSCALE_REQUEST_BUDGET_MS=N — 每个请求的总实际耗时预算,包括重试及其等待时间。默认值为 90000(90s)。如果预计下一次重试的实际耗时会超出预算,调用会立即返回错误,而不会继续等待。对于网关 5xx,预测时还会计入刚刚失败的那次尝试所花的时间:504 只有在网关等待完毕后才会到达,因此重试很可能会再次耗费同样的时间;若把剩余预算都花在重试上,客户端收到的就会是静默无响应,而不是 504。从网关 5xx 开始继续重试的调用,之后也会受限于此预算的一半——默认 45s,低于 MCP 客户端常见超时时间下限 60s;这是因为这些尝试消耗的是网关等待时间,而非退避等待时间,一连串这样的尝试可能会超过客户端的超时时间,而一连串 429 重试则不会。提高此值也会相应提高该上限;429 重试链无论如何都会使用完整预算。如果 MCP 客户端的外层超时时间更短,可将此值调低。非幂等方法(POST、PATCH)绝不会重试——无论预算如何,都会立即返回。

TAILSCALE_RETRY_BASE_DELAY_MS=N — 重试之间指数退避的基础延迟;第 N 次尝试等待 base * 2^N(最长 30s,另加抖动)。默认值为 1000(1s),因此完整耗尽的重试链大约会等待 1s + 2s + 4s。此选项与 TAILSCALE_REQUEST_BUDGET_MS 配合使用:单独降低预算并不会增加重试次数,只会让默认退避更快耗尽预算并放弃。如果你想“积极重试、快速失败”,应同时调低这两个值。服务器提供的 Retry-After 标头始终优先于此值。 TAILSCALE_EXTRA_WEBHOOK_EVENTS=eventA,eventB — 用于启用 Tailscale 在此软件包最新版本发布后新增的 webhook 事件类型的备用选项。Webhook 工具会根据严格的静态目录验证 subscriptions,因此拼写错误和过期的事件名称会立即报错并给出清晰提示;如果静态目录尚未更新,而你需要使用全新事件,可在此处列出该事件(以逗号分隔),架构便会接受它。两个类别订阅(categoryTailnetManagement、categoryDeviceMisconfigurations)已在目录中,因此无需在此处列出。也请提交 issue,以便更新静态列表。

TAILSCALE_EXTRA_POSTURE_PROVIDERS=providerA,providerB — 用于设备态势集成提供商的同类备用选项。tailscale_create_posture_integration 会根据静态列表(falcon、fleet、huntress、intune、jamfpro、kandji、kolide、sentinelone)验证 provider;如果 Tailscale 新增了提供商,而此软件包尚未更新,可在此处列出它,无需等待新版本发布。此字段过去是封闭枚举,因此新支持的提供商会变得无法创建,而不只是无法验证。

更友好的错误消息。 显示前会展开格式为 {"message":"..."} 或 {"error":"..."} 的 JSON 错误响应正文,因此你看到的是文字说明,而不是原始 JSON。如果正文还包含 data 数组(ACL 端点会用它报告未通过的策略测试),数组内容会显示在消息下方,这样策略被拒绝时会指出哪个用户以及哪项断言未通过,而不只是显示 test(s) failed。401 错误仍会使用完整的多行身份验证错误格式化程序(适用时会附带 Windows 环境变量提示)。

本地 CLI 集成(可选启用)

大多数工具都与 Tailscale v2 管理 API 交互——它们描述的是tailnet。有时你想查询的是这台机器的视角:它是否真的已连接?它当前使用哪个 DERP 区域?从这里到 my-laptop 有多远?这些答案来自本地 tailscale 二进制文件,而不是管理 API。

设置 TAILSCALE_LOCAL_CLI=1(在 shell 中或 .mcp.json 的 env 块中),即可添加 6 个只读诊断工具:

工具对应的 CLI 命令用途
tailscale_local_statustailscale status --json [--peers=false] [--active]查看这台机器的连接状态及其能看到的对等节点;peers: false 和 activeOnly: true 可缩小对等节点映射范围
tailscale_pingtailscale ping <target>探测到另一个 tailnet 节点的延迟(直连或经 DERP 中继)
tailscale_netchecktailscale netcheck --format=jsonNAT 类型、DERP 延迟映射、IPv4/IPv6 支持情况
tailscale_local_versiontailscale version查看实际运行的客户端版本
tailscale_local_whoamitailscale whoami查看这台机器以哪个用户和设备身份进行身份验证(需要 tailscale >= 1.102.1)
tailscale_local_service_listtailscale service list查看此节点可见的 Tailscale 服务(需要 tailscale >= 1.102.1)

要求:必须能找到 tailscale 二进制文件。系统会先在 PATH 中查找,然后检查以下默认安装路径;TAILSCALE_BINARY 可通过你指定的绝对路径覆盖这两种查找方式。

平台PATH 之外的查找位置备注
macOS/Applications/Tailscale.app/Contents/MacOS/Tailscale、/opt/homebrew/bin/tailscale、/usr/local/bin/tailscale标准安装会将 CLI 放在应用包内,且不会将其添加到 PATH。从 Dock 或 Spotlight 启动的 MCP 客户端继承的也是精简版 PATH,而非 shell 的 PATH,因此即使 tailscale 在终端中可以正常运行,直接查找也可能失败。
Linux/usr/bin/tailscale、/snap/bin/tailscalesnap 包装器不在某些精简版 PATH 中。
Windows—安装程序会将 tailscale.exe 添加到机器的 PATH。如果设置 TAILSCALE_BINARY,请使用 Windows 路径(C:/Program Files/Tailscale/tailscale.exe),而不要使用 Git Bash 路径(/c/...)——在 MSYS 提示符中输入时,这种写法会被转换;但从 JSON 配置或 .env 中读取时不会转换。
WSL/usr/bin/tailscale、/snap/bin/tailscale这些工具报告的是 Linux 节点,因此需要在发行版中安装 Tailscale 并运行 tailscaled。 在全新安装的 WSL 中,唯一可用的 tailscale 是 Windows 版本;Linux 进程无法执行 tailscale.exe。如果将 TAILSCALE_BINARY 指向 /mnt/c/.../tailscale.exe,工具报告的将是 Windows 主机的 Self、对等节点、whoami 身份和 netcheck 结果,而这里的每个工具都会声称报告的是“这台机器”的信息。系统刻意不会自动选用 tailscale.exe。

MCP 服务无需 root 权限即可运行这些工具——它们都只用于诊断,不会更改状态。需要提升权限的操作(tailscale up、set --advertise-routes、lock sign)不会开放。

启用此功能后,启动横幅会体现这一状态:@yawlabs/tailscale-mcp v0.22.0 ready (103 tools, local-cli=on)——这 6 个本地 CLI 工具是在默认的 97 个工具基础上额外添加的。

资源(4 个)

MCP 资源会公开只读数据,客户端无需调用工具即可浏览。

资源URI描述
Tailnet 状态tailscale://tailnet/status设备数量和 tailnet 设置
设备tailscale://tailnet/devices所有设备的状态和 IP 地址
ACL 策略tailscale://tailnet/acl完整的 ACL 策略(保留 HuJSON 格式)
DNS 配置tailscale://tailnet/dns名称服务器、搜索路径、分割 DNS、MagicDNS

工具(97 + 6 个可选启用)

状态(1 个工具) | 工具 | 描述 | |------|-------------| | `tailscale_status` | 验证 API 连接,查看 tailnet 信息和设备数量 |
设备(17 个工具)
工具描述
tailscale_list_devices列出设备(默认字段子集;fields: "all" 会添加路由、连接状态、SSH、发行版和设备状态身份信息)。设备在线时不会显示 lastSeen
tailscale_get_device获取一台设备(使用 fields: "all" 获取完整记录)
tailscale_authorize_device授权待处理设备
tailscale_deauthorize_device取消设备授权
tailscale_set_devices_authorized在一次调用中授权或取消授权多台设备(并行处理,按 ID 报告错误)
tailscale_delete_device从 tailnet 中移除设备
tailscale_rename_device重命名设备(FQDN 或基础名称;空字符串会重置为操作系统主机名)
tailscale_expire_device使设备密钥过期,强制重新认证
tailscale_get_device_routes获取已通告和已启用的子网路由
tailscale_set_device_routes启用或禁用子网路由
tailscale_get_device_posture_attributes获取设备的所有设备状态属性
tailscale_set_device_posture_attribute设置自定义设备状态属性(可选设置过期时间和审计日志备注)
tailscale_delete_device_posture_attribute删除自定义设备状态属性
tailscale_set_device_tags为设备设置 ACL 标签
tailscale_set_device_ip设置设备的 Tailscale IPv4 地址
tailscale_update_device_key更新设备密钥设置(例如,禁用密钥过期)
tailscale_batch_update_posture_attributes批量更新多台设备的自定义设备状态属性
ACL / 策略(5 个工具)— 保留 HuJSON 格式并确保 ETag 安全
工具描述
tailscale_get_acl获取保留格式(HuJSON)并包含 ETag 的 ACL 策略
tailscale_update_acl更新 ACL 策略(为安全地并发编辑,必须提供 ETag;首次写入时使用 ts-default)
tailscale_validate_acl验证策略,但不应用
tailscale_preview_acl预览将应用于用户或 IP 的规则
tailscale_diff_acl_access将拟定策略与当前策略进行比较 — 查看谁会获得或失去访问权限
DNS(11 个工具)
工具描述
tailscale_get_nameservers获取 DNS 名称服务器
tailscale_set_nameservers设置 DNS 名称服务器
tailscale_get_search_paths获取 DNS 搜索路径
tailscale_set_search_paths设置 DNS 搜索路径
tailscale_get_split_dns获取拆分 DNS 配置
tailscale_set_split_dns设置拆分 DNS 配置(完全替换;null 会清除某个域)
tailscale_update_split_dns更新拆分 DNS 配置(部分合并;null 会移除某个域)
tailscale_get_dns_preferences获取 DNS 偏好设置(MagicDNS)
tailscale_set_dns_preferences设置 DNS 偏好设置(MagicDNS)
tailscale_get_dns_configuration获取统一 DNS 配置(一次调用获取所有设置)
tailscale_set_dns_configuration设置统一 DNS 配置(一次调用设置所有设置)
密钥 / 信任凭据(9 个工具)— 涵盖身份验证密钥、OAuth 客户端、联合身份和 OAuth 应用 | 工具 | 描述 | |------|-------------| | `tailscale_list_keys` | 列出密钥(默认集合取决于凭据;设置 `all=true` 可列出整个 tailnet 范围内的密钥:身份验证密钥、API 访问令牌、OAuth 客户端、联合身份) | | `tailscale_get_key` | 获取任意类型密钥的详细信息 | | `tailscale_create_key` | 创建身份验证密钥、OAuth 客户端(`keyType=client`)或联合身份(`keyType=federated`) | | `tailscale_delete_key` | 删除任意类型的密钥,包括此服务使用的 API 访问令牌 | | `tailscale_update_key` | 更新密钥的描述、范围、标签或联合声明设置 | | `tailscale_create_oauth_app` | 创建用于第三方设备配置的 OAuth App(Tailscale alpha) | | `tailscale_get_oauth_app` | 获取 OAuth App 的名称、重定向 URI 和范围 | | `tailscale_list_oauth_apps` | 列出 tailnet 中注册的所有 OAuth App | | `tailscale_delete_oauth_app` | 删除 OAuth App,撤销其配置设备的权限 |
用户(7 个工具)
工具描述
tailscale_list_users列出 tailnet 中的所有用户
tailscale_get_user获取特定用户的详细信息
tailscale_approve_user批准待处理的用户
tailscale_suspend_user暂停用户,撤销其访问权限
tailscale_restore_user恢复已暂停的用户
tailscale_update_user_role更新用户角色(owner、admin、member 等)
tailscale_delete_user删除用户及其所有设备
Tailnet 设置(5 个工具)
工具描述
tailscale_get_tailnet_settings获取 tailnet 设置(HTTPS、设备审批、密钥过期等)
tailscale_update_tailnet_settings更新 tailnet 设置(HTTPS 证书、审批、自动更新、密钥过期、设备状态、区域路由、网络流量日志记录、外部 ACL 管理)
tailscale_get_contacts获取 tailnet 联系人
tailscale_set_contacts设置 tailnet 联系人
tailscale_resend_contact_verification重新发送联系人的验证邮件
Webhooks(7 个工具)
工具描述
tailscale_list_webhooks列出 Webhook
tailscale_get_webhook获取特定 Webhook
tailscale_create_webhook创建 Webhook(原始 JSON,或通过 providerType 设置为适用于 Slack / Mattermost / Google Chat / Discord 的格式)
tailscale_update_webhook更新 Webhook 的端点 URL 和/或订阅
tailscale_delete_webhook删除 Webhook
tailscale_rotate_webhook_secret轮换 Webhook 密钥
tailscale_test_webhook发送测试事件以验证 Webhook 是否正常送达
设备状态集成(5 个工具)
工具描述
tailscale_list_posture_integrations列出设备状态集成
tailscale_get_posture_integration获取设备状态集成
tailscale_create_posture_integration创建设备状态集成
tailscale_update_posture_integration更新设备状态集成
tailscale_delete_posture_integration删除设备状态集成
Tailscale 服务(7 个工具)
工具描述
tailscale_list_services列出 tailnet 中的所有 Tailscale 服务
tailscale_get_service获取特定服务的详细信息
tailscale_update_service更新服务配置
tailscale_delete_service删除服务
tailscale_list_service_hosts列出托管服务的设备
tailscale_get_service_device_approval获取设备对某项服务的审批状态
tailscale_set_service_device_approval批准或拒绝设备托管服务
组织 Tailnet(3 个工具)— 仅限 API 的 Tailnet;需要 OAuth 身份验证

以编程方式创建和删除整个 Tailnet — 适用于每个 Agent 的沙盒、每个租户的隔离环境,以及临时 CI 环境。组织默认可拥有 10 个 Tailnet(包括原有 Tailnet)。与此处的其他所有类别不同,这些端点位于 /organizations 下,仅使用 OAuth 客户端进行身份验证(创建时需要 tailnets 范围,之后访问该 Tailnet 需要 all),并且创建的 Tailnet 不会在管理控制台中管理。设置 TAILSCALE_OAUTH_TAILNET 即可对其中一个 Tailnet 执行操作。

工具描述
tailscale_list_org_tailnets列出组织的 Tailnet(通过 limit / cursor 分页)
tailscale_create_org_tailnet创建仅限 API 的 Tailnet;OAuth 客户端密钥只返回一次
tailscale_delete_tailnet删除 Tailnet(已配置的 Tailnet,或通过 tailnet 指定的 Tailnet)— 此操作不可撤销;confirmTailnet 必须与之匹配
日志流传输(7 个工具)
工具描述
tailscale_list_log_stream_configs列出日志流传输配置(包括审计日志和网络日志)
tailscale_get_log_stream_config获取指定日志类型的日志流传输配置
tailscale_set_log_stream_config设置日志发送位置(Axiom、Datadog、Splunk 等)
tailscale_delete_log_stream_config删除日志流传输配置
tailscale_get_log_stream_status检查日志流传输是否成功
tailscale_create_aws_external_id创建或获取用于 S3 基于角色的日志流传输的 AWS 外部 ID(reusable 默认为 true,在关联之前会返回相同的 ID)
tailscale_validate_aws_trust_policy验证用于 S3 日志流传输的 AWS IAM 角色信任策略
设备邀请(6 个工具)
工具描述
tailscale_list_device_invites列出指定设备的设备邀请
tailscale_create_device_invite创建设备邀请
tailscale_get_device_invite获取设备邀请
tailscale_delete_device_invite删除设备邀请
tailscale_accept_device_invite接受设备共享邀请
tailscale_resend_device_invite重新发送设备邀请邮件
用户邀请(5 个工具)
工具描述
tailscale_list_user_invites列出尚未接受的用户邀请
tailscale_create_user_invite创建用户邀请
tailscale_get_user_invite获取用户邀请
tailscale_delete_user_invite删除用户邀请
tailscale_resend_user_invite重新发送用户邀请邮件
日志记录(2 个工具)
工具描述
tailscale_get_audit_log获取配置审计日志(谁在何时更改了什么);可选的服务端操作者 / 目标 / 事件筛选条件
tailscale_get_network_flow_logs获取设备之间的网络流量日志
本地 CLI(6 个工具,可选启用)— 请参阅 本地 CLI 集成 | 工具 | 描述 | |------|-------------| | `tailscale_local_status` | 本机看到的 tailnet 状态(自身连接状态、对等节点、DERP 区域);可通过 `peers: false` 或 `activeOnly: true` 缩小范围 | | `tailscale_ping` | 从本机探测到另一个 tailnet 节点的延迟 | | `tailscale_netcheck` | NAT 类型、DERP 延迟映射、IPv4/IPv6 支持诊断 | | `tailscale_local_version` | 本地 `tailscale` 二进制文件版本 | | `tailscale_local_whoami` | 本机通过哪个用户和设备进行身份验证(需要 tailscale >= 1.102.1) | | `tailscale_local_service_list` | 此节点可见的 Tailscale Services(需要 tailscale >= 1.102.1) |

GitOps:从 CI 部署 ACL

对于简单的“合并后从 git 部署 ACL”工作流,你不需要 MCP 服务或 Agent——使用内置 CLI:

# PR check: validate the proposed policy without touching the tailnet
npx -y @yawlabs/tailscale-mcp@latest validate-acl tailscale/acl.json

# On merge: ETag fetch + validate + deploy with If-Match, fail-closed at every step
npx -y @yawlabs/tailscale-mcp@latest deploy-acl tailscale/acl.json

可在任何 CI 系统中运行。将 TAILSCALE_API_KEY 设置为环境变量;TAILSCALE_TAILNET 为可选项——不设置时会操作该密钥所属的 tailnet,或将其设置为 Tailnet ID 以明确指定。两个命令在任何失败时都会以非零状态码退出;deploy-acl 在没有 ETag 时会拒绝部署(因此并发的 Admin Console 编辑绝不会被悄悄覆盖),并会将 412 报告为并发编辑冲突,你可以通过重新运行来解决。

当验证报告策略测试失败时,CI 日志会列出用户和断言(For user [email protected]: / Errors found:),与上游 gitops-pusher 打印的详细信息相同。验证警告——例如未同步的 SCIM 组——也会导致运行失败,这与 gitops-pusher 和 Tailscale 自己的 Go 客户端一致;警告文本也会一并打印,方便你查看具体问题。

完整的 GitHub Actions 工作流——在 PR 上验证,合并后部署:

name: tailscale-acl
on:
  pull_request:
    paths: ["tailscale/acl.json"]
  push:
    branches: [main]
    paths: ["tailscale/acl.json"]

jobs:
  acl:
    runs-on: ubuntu-latest
    env:
      TAILSCALE_API_KEY: ${{ secrets.TAILSCALE_API_KEY }}
      TAILSCALE_TAILNET: T1234CNTRL # Tailnet ID from Settings > General; or omit: defaults to the key's tailnet
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - name: Validate ACL
        if: github.event_name == 'pull_request'
        run: npx -y @yawlabs/tailscale-mcp@latest validate-acl tailscale/acl.json
      - name: Deploy ACL
        if: github.event_name == 'push'
        run: npx -y @yawlabs/tailscale-mcp@latest deploy-acl tailscale/acl.json

为确保部署可复现,请将 @latest 替换为固定版本。

如果你打算用 curl 手动实现: Tailscale 的 ACL 端点仅在 GET 时返回 ETag 标头,而不会在 HEAD 时返回。使用 curl -I(HEAD)获取 ETag 会悄悄返回空值——空的 If-Match 要么会导致不受保护地部署(覆盖并发编辑),要么会触发你的保护逻辑并使部署失败。请使用 GET 获取 ETag(curl -fsS -D - -o /dev/null ...),如果返回值为空,则让作业失败。上面的 CLI 会替你处理这些步骤。

可选: 锁定 Admin Console,防止手动编辑导致其与 git 内容不一致。请让你的 Agent:

“将 aclsExternallyManagedOn 设为 true,并将 aclsExternalLink 设为我们的 repo URL”

这会在 Tailscale Admin Console 中显示一个指向你 repo 的只读横幅。使用 MCP 进行读取和调查,并让 CI 负责部署。

要求

  • 运行服务需要 Node.js 20.11+(开发需要 22+——测试脚本会将 glob 传递给 node --test,该功能从 Node 21 开始支持)
  • Tailscale API 密钥或 OAuth 客户端凭据

在 oam.js 上运行(可选)

oam.js 无需修改即可运行此服务,而 tailscale-mcp 命令始终只使用最新的 oam 版本,目前为 0.18.0。已针对已发布的 oam 0.18.0 进行验证:完整的 MCP 握手、全部 97 个管理 API 工具和 tailscale_tool_groups、全部 4 个资源、完全相同的错误响应,以及干净的 stdout 协议流——无论是使用随附的 bundle,还是直接使用 TypeScript 源码且不执行构建步骤,结果均一致。

oam 0.18.0 是最低要求。 这里设定最低版本是有原因的:0.9.0 之前的版本会通过 shell 运行 child_process.execFile 参数,按空白字符重新拆分参数,并执行参数中的 shell 元字符;而此服务的本地 CLI 工具会调用 tailscale 二进制文件,因此这是一个可触发的漏洞,并非理论上的问题。

tailscale-mcp 命令(bin/tailscale-mcp.mjs)选择运行时的方式:

  • TAILSCALE_MCP_RUNTIME=auto(默认值)——如果客户端已经通过 oam 0.18.0 或更高版本的 oam run 启动此服务,服务就在该进程中运行。否则,如果 OAM_BIN 指向的版本为 0.18.0 或更高版本,则使用它;否则会向找到的每个 oam 二进制文件查询版本,并选择不低于最低要求的最新版本——先检查已设置的 OAM_INSTALL_DIR,然后在 Windows 上检查 %LOCALAPPDATA%\oam\bin 和 ~/.oam/bin,在其他系统上检查 ~/.oam/bin,最后检查 PATH(版本相同时优先使用已安装的副本)。如果找不到符合条件的版本,则使用 Node。如果 oam 宿主版本低于 0.18.0,它绝不会直接运行此服务:而是转交给最新的可用 oam,或 PATH 中的 Node;如果两者都没有,则报错退出。每当查找 oam 时,stderr 都会说明被跳过的 OAM_BIN 及原因;只有在找不到可用的 oam 时,才会列出找到但跳过的 oam 二进制文件,并分别说明原因。
  • TAILSCALE_MCP_RUNTIME=oam——与上述方式相同,但如果无法使用 oam,则报错退出,而不是回退到 Node。错误信息会针对实际发现的情况说明解决方法:对于低于最低要求的 oam,提示运行 oam self-update;对于无法运行的二进制文件,提示检查该二进制文件;只有完全找不到 oam 时才提示安装 oam(而对于 oam 未发布构建的 linux-arm64,即使如此也不会提示安装)。
  • TAILSCALE_MCP_RUNTIME=node——始终使用 Node:在 npx 下于当前进程中运行;如果客户端通过 oam run 启动命令,则转交给 PATH 中的 Node。

此值不区分大小写;其他任何值都会在 stderr 上发出警告,并按 auto 处理。在 Windows 上,只有 oam.exe 符合条件:绝不会运行 oam.cmd / oam.bat shim,且只有在找不到可用的 oam 时才会在 stderr 上列出它。

沙盒(选择启用)

设置 TAILSCALE_MCP_SANDBOX=1,即可在 oam 的 --permission 模型下运行:网络仅允许访问 api.tailscale.com:443——这是 bundle 会联系的唯一主机,包括 OAuth 令牌交换;所有请求均使用 HTTPS——并禁止文件系统访问。子进程权限仍会保留,因为本地 CLI 工具会调用 tailscale 二进制文件。该子进程会继承服务的环境变量;在沙盒下,环境中仅包含获准的变量。因此,除 TAILSCALE_* 设置外,允许列表还包括 PATH(用于查找二进制文件)以及 Windows 程序启动所需的变量——SYSTEMROOT、WINDIR、SYSTEMDRIVE、TEMP/TMP、USERPROFILE、HOMEDRIVE/HOMEPATH、APPDATA、LOCALAPPDATA——以及 HOME。oam 也会从经过筛选的环境中获取 Windows 添加到每个子进程的变量,因此如果没有这些变量,启动的 CLI 将没有 SYSTEMROOT。oam 会严格区分这些名称的大小写,因此在 Windows 上,启动器还会按环境实际使用的拼写授予每个变量(例如客户端从 Explorer 继承的 Path、SystemRoot、SystemDrive、windir)。

在沙盒下,TAILSCALE_BINARY 必须指向原生的 tailscale CLI,而不能指向基于 Node 的包装脚本:与 Node 一样,oam 会通过 NODE_OPTIONS 将权限标志传递给每个子进程,而 Node 会拒绝其中的 --allow-net 和 --allow-env,并在运行任何内容之前退出。原生 CLI 会忽略此变量。 之所以选择显式启用,而不是默认启用,是因为授权错误不会明确报错。对于未获授权的环境变量,oam 会将其从 process.env 中移除,而不是抛出异常,因此权限不足的 TAILSCALE_API_KEY 读取结果会是“未认证”,而不是“被拒绝”。启动器中的环境变量允许列表是根据已发布的 bundle 实际读取的内容生成的——如果添加了新的 process.env 查询,也要将其加入该列表。

沙盒由 tailscale-mcp 命令应用,该命令会为其启动一个全新的 oam——即使客户端是通过 oam run 启动该命令也是如此——因为 --permission 是进程级标志。如果找不到可用的 oam 来启动,TAILSCALE_MCP_RUNTIME=auto 仍会在不启用沙盒的情况下启动服务;设置 TAILSCALE_MCP_RUNTIME=oam 则会将此情况视为错误。TAILSCALE_MCP_RUNTIME=node 会使用 Node 运行,因此绝不会应用沙盒。

沙盒也会应用于 CLI 子命令,并且由于文件系统访问被拒绝,tailscale-mcp validate-acl <file> / deploy-acl <file> 无法读取策略文件。运行这些命令时,请取消设置 TAILSCALE_MCP_SANDBOX——例如,如果你在 shell 配置文件中为服务导出了该变量,请运行 TAILSCALE_MCP_SANDBOX= tailscale-mcp validate-acl policy.hujson。

{
  "mcpServers": {
    "tailscale": {
      "command": "oam",
      "args": ["run", "/path/to/tailscale-mcp/dist/index.js"]
    }
  }
}

请在自己的硬件上测量启动速度。 MCP 客户端会在每个会话中冷启动一次此服务,因此启动耗时才是真正需要付出的成本。在进行测量的机器上,Node 表现更好——在 10 次预热运行中,Node 耗时 437ms,而 oam run 耗时 1554ms(此前一轮 5 次运行的结果为 326ms 对 427ms;机器当时负载较高,因此具体数值有波动,应关注结果趋势)。这些运行使用的 oam 早于 0.18.0 的最低版本要求,此后也没有重新测量,因此不要将这些数据解读为当前的性能排名。

已发布的 tailscale-mcp 命令会优先选择找到的最新可用 oam(见上文)。未安装 oam 时,几乎没有额外开销:发现过程只检查文件是否存在,不会启动子进程;回退方案会在 npm 已启动的 Node 进程中运行服务。不过,安装了 oam 时,该命令会启动 Node,对找到的每个 oam 二进制文件运行 --version 以选出最新版本,然后才启动 oam,因此它总是比直接将客户端指向运行时更慢——oam 的配置如上所示,Node 则使用 node /path/to/tailscale-mcp/dist/index.js。TAILSCALE_MCP_RUNTIME=node 会完全跳过 oam。

在此代码库中,oam 确实有两个更胜一筹的用途,两者都需要显式启用,且都不会影响 npm 包:

  • npm run check:oam——通过 oam check 进行类型检查(使用 tsgo,即 TypeScript 7 原生实现)。实测耗时 4015ms,而 tsc --noEmit 为 7680ms,检查结果同样无错误。npx tsc --noEmit 仍是通用默认方案。
  • npm run build:binary:oam——通过 oam compile 构建独立二进制文件(实测约 57.7 MB)。文件会写入 bin/<platform>-<arch>/(跨平台构建时则写入 bin/$TAILSCALE_MCP_BINARY_TARGET/),之后由 scripts/stage-release-asset.mjs 按公开资源名称暂存该文件。如果你重新分发该二进制文件,它会包含 oam 的运行时,因此请同时附上 oam 的 LICENSE、NOTICE 和 THIRD_PARTY_LICENSES.md。跨平台构建(TAILSCALE_MCP_BINARY_TARGET=<platform>-<arch>)会下载目标平台的 oam 发布二进制文件作为载体,并使用 ssh-keygen -Y verify(OpenSSH 8.1+),根据 scripts/oam-release-keys/ 中的 oam 发布密钥验证发布方签名的 RELEASE-MANIFEST;若签名、清单或校验和验证失败,则会中止构建。对于早于 oam 开始签署发布版本的 v0.18.0 的 OAM_VERSION,只有在其 SHA256SUMS 文件与 scripts/oam-release-keys/presigning-sums 中为该标签固定的摘要匹配后,才会进行校验。

源代码有意保持与运行时无关:任何地方都没有 oam: 导入,测试也继续使用 node:test。这样才能确保 Node 回退方案真正可用,而不只是名义上的回退。请注意,任何 oam 调用都会在工作目录的 oam/ 中写入字节码缓存——该目录已包含在 .gitignore 中。

贡献

欢迎贡献。有关 PR 工作流程和 AI Agent 指南,请参阅 CONTRIBUTING.md。除拼写错误修正外,如有其他改动,请先提交议题讨论,再发起 PR。

git clone https://github.com/YawLabs/tailscale-mcp.git
cd tailscale-mcp
npm install
npm run lint       # Biome check
npm run lint:fix   # Auto-fix
npm run build      # tsc + esbuild bundle
npm test           # node --test (full suite)

要针对你自己的 tailnet 进行集成测试,请设置 TAILSCALE_API_KEY 并运行 node dist/index.js。

安全

发现漏洞?请参阅 SECURITY.md——请使用 GitHub 的私密漏洞报告功能,而不要提交公开议题。

许可证

MIT

在 X 上关注 @YawLabs

评论

支持 Markdown

第一次接触 MCP?

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

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