---
title: "TSLink 作为 MCP 服务器"
description: "通过 stdio 或 tailnet-only HTTP 控制面，使用 44 个 owner 工具分享和管理本地服务"
url: "https://tslink.md/zh/docs/mcp-server"
locale: "zh"
product_version: "0.1.1"
source: "https://github.com/anydoor7/tslink/blob/v0.1.1/docs/agents.md"
---

> Documentation index: https://tslink.md/zh/llms.txt · Installed binary is authoritative: `tslink manifest`.

场景指南：[在手机上使用编程 agent 的 Web UI](https://tslink.md/zh/docs/agent-ui-phone.md)。

## `tslink mcp` 是什么

TSLink 的同一个 registry 通过两种传输提供 44 个 owner 工具：本地 stdio 子进程（`tslink mcp`）和可选的 tailnet-only Streamable HTTP endpoint（`tslink serve --mcp`）。本页说明如何控制 TSLink 本身。代理已有第三方 MCP server 见 [MCP 服务器托管](https://tslink.md/zh/docs/mcp-hosting.md)。

## 注册到本地 MCP client

```json
{"mcpServers":{"tslink":{"command":"tslink","args":["mcp"]}}}
```

如果 client 的 `PATH` 不同，使用已安装二进制的绝对路径。不要在 client 配置中加入凭据。默认分享不需要存储凭据；需要浏览器注册时，TSLink 返回 `needs_login`。

MCP 进程本身不监听网络。调用 `share`、`add`、`template_apply` 可能安装或启动独立的后台网关及其 tsnet 服务；正常安装公告写入 stderr。

## stdio 契约

| 项目             | 行为                                                                                                                                   |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| stdout         | 仅 JSON-RPC frames，每行一个 JSON object                                                                                                   |
| stderr         | 诊断、日志和正常安装公告；成功 session 不保证 stderr 为空                                                                                                |
| `--json`       | `tslink mcp --json` 以 exit `2` 拒绝；stdout 保留给协议 frames                                                                                |
| 版本             | 当前 `2026-07-28`；兼容 `2025-11-25`、`2025-06-18`、`2025-03-26`、`2024-11-05`                                                               |
| 协商             | 当前 client 在每个请求的 `_meta` 中提供版本，不需要 `initialize`。旧 client 使用 `initialize` 后发 `notifications/initialized`；旧握手回显支持版本，否则回退为 `2025-11-25` |
| EOF            | 已读请求的答案排空后退出；关闭 stdin 时仍需继续读取 stdout                                                                                                 |
| EOF watchdog   | stdin 关闭 6m 后仍运行的调用会被取消；给 handler 5s 返回，之后命令 exit `1`。stdout 若仍阻塞，再最多等待 5s 后放弃响应                                                     |
| 信号             | SIGINT/SIGTERM 取消在途调用，回滚仍等待 URL 的 `share`，并 exit `1`。第二个信号立即终止                                                                       |
| 结束 session 的输入 | malformed JSON、不是 JSON-RPC message 的 JSON 值、JSON-RPC batch 或超过 1,048,576 bytes 的记录会结束 session、丢弃在途答案，后面的记录不再读取                       |
| 重复在途 id        | 不会得到答案；调用完成前不要复用 id                                                                                                                  |
| URL 轮询         | `url.wait` 是 Go duration，上限 `5m`；超过上限是 usage error                                                                                   |

不要假设 malformed 输入会获得可恢复的 JSON-RPC error。session 结束后重新启动子进程。协议协商和错误由 SDK 处理。`serverInfo.version` 标识已安装构建，未打版本时为 `dev`。

旧 client 的握手起始如下：

```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0.0"}}}
```

```json
{"jsonrpc":"2.0","method":"notifications/initialized"}
```

## 工具与完整输入字段

owner 的 `tools/list` 提供 44 个工具；精简会话只展示其被允许的集合，每个工具提供 `inputSchema` 与 `outputSchema`。输入严格校验，未知字段和不正确类型会被拒绝。下表列出全部输入字段；已安装构建的实时 schema 仍是权威。daemon 生命周期、安装、login/logout 和配置仍仅通过 CLI 提供。

### 会话工具索引

本地 owner 提供 44 个、viewer 12 个、people-manager 18 个工具，请用真实会话 tools/list 发现。下表明确必填参数，可选字段仍遵守实时 schema；参数不能扩大角色。V = viewer、A = app-operator、P = people-manager，全部行对 owner 可用。精简角色另受应用/期限范围限制，请求工具还需 portal-owner 检查。

| 工具                 | 必填参数                                        | 可选参数                                                                                                                                                                                                                                                                                                                                             | 精简角色    |
| ------------------ | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
| `access_explain`   | `service`: string                           | 无                                                                                                                                                                                                                                                                                                                                                | V/A/P   |
| `access_log`       | 无                                           | `app`: string, `decision`: string, `limit`: integer, `since`: string, `until`: string, `who`: string                                                                                                                                                                                                                                             | V/A/P   |
| `access_summary`   | 无                                           | `app`: string, `decision`: string, `limit`: integer, `since`: string, `until`: string, `who`: string                                                                                                                                                                                                                                             | V/A/P   |
| `add`              | `name`: string, `type`: string              | `allow`: array, `control_url`: string, `dir`: string, `ephemeral`: boolean, `funnel`: boolean, `funnel_ttl`: string, `health`: object, `no_auto_provision`: boolean, `no_daemon_install`: boolean, `preserve_host`: boolean, `public_ack`: boolean, `request_limits`: object, `requestable`: boolean, `tags`: array, `target`: string            | 仅 owner |
| `app_restart`      | `app`: string                               | 无                                                                                                                                                                                                                                                                                                                                                | A       |
| `apps_detect`      | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `doctor`           | 无                                           | `probe_external`: boolean                                                                                                                                                                                                                                                                                                                        | V/A/P   |
| `extend`           | `service`: string                           | `ack_never`: boolean, `for`: string, `regrant`: boolean, `until`: string, `who`: string                                                                                                                                                                                                                                                          | A/P     |
| `guest_create`     | `app`: string, `for`: string                | `label`: string, `pin`: string, `print_link`: boolean, `public`: boolean                                                                                                                                                                                                                                                                         | 仅 owner |
| `guest_list`       | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `guest_revoke`     | `id`: string                                | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `guest_show`       | `id`: string                                | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `health`           | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | V/A/P   |
| `invite_device`    | `email`: string, `service`: string          | `allow_exit_node`: boolean, `multi_use`: boolean, `print_link`: boolean                                                                                                                                                                                                                                                                          | 仅 owner |
| `invite_list`      | 无                                           | `show_urls`: boolean                                                                                                                                                                                                                                                                                                                             | 仅 owner |
| `invite_resend`    | `invite_id`: string, `kind`: string         | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `invite_revoke`    | `invite_id`: string, `kind`: string         | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `invite_user`      | `email`: string                             | `print_link`: boolean, `role`: string                                                                                                                                                                                                                                                                                                            | 仅 owner |
| `list`             | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | V/A/P   |
| `logs`             | 无                                           | `last`: integer, `level`: string, `since`: string, `source`: string                                                                                                                                                                                                                                                                              | 仅 owner |
| `mcp_audit`        | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `people_add`       | `apps`: array, `who`: string                | `ack_never`: boolean, `for`: string, `invite`: boolean, `print_links`: boolean, `qr`: boolean, `qr_invite`: string, `until`: string                                                                                                                                                                                                              | 仅 owner |
| `people_grant`     | `app`: string, `for`: string, `who`: string | 无                                                                                                                                                                                                                                                                                                                                                | A/P     |
| `people_list`      | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | V/A/P   |
| `people_remove`    | `who`: string                               | `reconcile_invites`: object                                                                                                                                                                                                                                                                                                                      | 仅 owner |
| `people_revoke`    | `app`: string, `who`: string                | 无                                                                                                                                                                                                                                                                                                                                                | A/P     |
| `people_update`    | `who`: string                               | `ack_never`: boolean, `apps`: array, `for`: string, `invite`: boolean, `print_links`: boolean, `qr`: boolean, `qr_invite`: string, `reconcile_invites`: object, `replace_invites`: object, `until`: string                                                                                                                                       | 仅 owner |
| `portal_disable`   | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `portal_enable`    | `owner`: string                             | `admins`: array, `funnel`: boolean, `hostname`: string                                                                                                                                                                                                                                                                                           | 仅 owner |
| `recipe_apply`     | `recipe_id`: string                         | `allow`: string, `control_url`: string, `ephemeral`: boolean, `force_unsafe_public`: boolean, `funnel`: boolean, `funnel_ttl`: string, `health`: object, `name`: string, `no_auto_provision`: boolean, `no_daemon_install`: boolean, `preserve_host`: boolean, `public_ack`: boolean, `request_limits`: object, `tags`: string, `target`: string | 仅 owner |
| `recipe_list`      | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | V/A/P   |
| `recipe_plan`      | `recipe_id`: string                         | `allow`: string, `control_url`: string, `ephemeral`: boolean, `force_unsafe_public`: boolean, `funnel`: boolean, `funnel_ttl`: string, `health`: object, `name`: string, `no_auto_provision`: boolean, `no_daemon_install`: boolean, `preserve_host`: boolean, `public_ack`: boolean, `request_limits`: object, `tags`: string, `target`: string | 仅 owner |
| `requests_approve` | `for`: string, `id`: string                 | `ack_never`: boolean                                                                                                                                                                                                                                                                                                                             | P       |
| `requests_deny`    | `id`: string                                | `reason`: string                                                                                                                                                                                                                                                                                                                                 | P       |
| `requests_list`    | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | P       |
| `share`            | `target`: string                            | `allow`: array, `ephemeral`: boolean, `funnel`: boolean, `funnel_ttl`: string, `name`: string, `no_daemon_install`: boolean, `preserve_host`: boolean, `public_ack`: boolean, `request_limits`: object, `tags`: array                                                                                                                            | 仅 owner |
| `status`           | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | V/A/P   |
| `tags_list`        | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | V/A/P   |
| `tags_set`         | `service`: string, `tag`: string            | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `template_apply`   | `name`: string                              | `no_daemon_install`: boolean                                                                                                                                                                                                                                                                                                                     | 仅 owner |
| `template_list`    | 无                                           | 无                                                                                                                                                                                                                                                                                                                                                | V/A/P   |
| `template_plan`    | `name`: string                              | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `unshare`          | `name`: string                              | 无                                                                                                                                                                                                                                                                                                                                                | 仅 owner |
| `url`              | `name`: string                              | `wait`: string                                                                                                                                                                                                                                                                                                                                   | V/A/P   |

`extend` 必须给 for/until 之一，精简角色必须指定 who。Guest 创建需 for，首次启用 gate 需 public: true。成员永久授权需 ack\_never: true；新的 guest/公开拒绝 never。普通 qr 返回 payload 文本，MCP 没有 qr\_png 参数。portal\_enable.funnel: true 被拒绝。

### `share`

分享已有文件、目录或 HTTP 端口。目录目标提供可浏览内容；单文件目标只提供该文件。匹配的 target/name 可以复用；无关的名称冲突会加数字后缀。

| 字段                  | 类型 / 必填      | 行为                                                                                          |
| ------------------- | ------------ | ------------------------------------------------------------------------------------------- |
| `target`            | string，必填    | 已有路径、`1..65535` 端口或 `host:port` HTTP 目标                                                     |
| `name`              | string       | 可选 DNS label，最多 63 字符，`^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`                                     |
| `ephemeral`         | boolean      | 默认 `true`；指 tailnet 节点生命周期，不自动删除 registry                                                   |
| `no_daemon_install` | boolean      | 要求网关已经运行，不自动安装                                                                              |
| `allow`             | string array | 登录邮箱或 `tag:`；省略则无额外 allow 规则，人员策略仍生效；与 Funnel 冲突                                            |
| `tags`              | string array | 每项以 `tag:` 开头；有存储凭据的模式使用已配置默认标签                                                             |
| `funnel`            | boolean      | 默认 `false`；公开要求 HTTP 端口目标、`public_ack: true` 且无 `allow`                                     |
| `public_ack`        | boolean      | 默认 `false`；明确确认公开互联网访问                                                                      |
| `funnel_ttl`        | string       | 共同相对/绝对期限语法，至少 1h，默认 24h，公开上限默认 7d；新的公开拒绝 never。                                            |
| `preserve_host`     | boolean      | 仅 proxy，转发节点 canonical 外部 Host；默认 false 重写 upstream Host，Origin 保持不变                        |
| `request_limits`    | object       | `max_body`、`unlimited_ack`、`header_timeout`、`read_timeout`、`idle_timeout`；限制上传大小与空闲，不限制请求频率 |

`share` 最多等待 30s 获取就绪或授权信息。`status` 始终存在；`ready` 带 `url`、`name`，`needs_login` 带 `auth_url`。公开分享还可能带 `funnel_expires_at`、`funnel_rearmed`。复用仍有效的分享会保留原截止时间；已过期 Funnel 可以按请求时长重新启用。

### `add`

写入或替换具名 registry 服务。默认确保网关存在，返回当前 URL/授权证据，不额外等待 URL；用 `url` 轮询。

| 字段                  | 类型 / 必填      | 行为                                                                                             |
| ------------------- | ------------ | ---------------------------------------------------------------------------------------------- |
| `name`              | string，必填    | DNS label，最多 63 字符，与 `share.name` 同一格式；同名条目被替换                                                 |
| `type`              | string，必填    | `proxy`、`file`、`tcp`                                                                           |
| `target`            | string       | proxy/TCP 必填、file 拒绝。proxy 接受 `host:port` 或 URL，TCP 接受 `host:port`                             |
| `dir`               | string       | file 要求绝对目录路径；proxy/TCP 拒绝                                                                     |
| `allow`             | string array | HTTP 登录邮箱或 `tag:`；TCP 及 Funnel 拒绝                                                              |
| `tags`              | string array | `tag:` 条目；有存储凭据模式使用已配置默认标签                                                                     |
| `ephemeral`         | boolean      | 默认 `false`                                                                                     |
| `funnel`            | boolean      | 默认 `false`；要求 proxy、`public_ack: true`、无 `allow`、无 `control_url`                               |
| `public_ack`        | boolean      | 默认 `false`；明确公开确认                                                                              |
| `funnel_ttl`        | string       | 共同相对/绝对期限语法，至少 1h，默认 24h，公开上限默认 7d；新的公开拒绝 never。                                               |
| `no_daemon_install` | boolean      | 保存配置，不安装后台服务                                                                                   |
| `no_auto_provision` | boolean      | 默认 `false`；关闭 Funnel 策略自动配置，仅 Funnel 可用                                                        |
| `control_url`       | string       | 如 Headscale 的自定义 control server；与 Funnel 冲突                                                    |
| `preserve_host`     | boolean      | 仅 proxy，转发节点 canonical 外部 Host；默认 false 重写 upstream Host，Origin 保持不变                           |
| `request_limits`    | object       | `max_body`、`unlimited_ack`、`header_timeout`、`read_timeout`、`idle_timeout`；限制上传大小与空闲，不限制请求频率    |
| `health`            | object       | `path`、`status_min`、`status_max`、`body_contains`、`timeout`、`interval`；path/status/body 仅 proxy |
| `requestable`       | boolean      | 明确在私有 portal 请求表单披露名称；默认 false，仅私有 HTTP/文件。                                                    |

读取 `created`、`url`、`url_pending`、`endpoint`、`exposure`、`funnel_rearmed`，以及可选的 `auth_url` / `next` / `warnings`，区分注册与就绪。目标校验拒绝字面量 link-local、unspecified、cloud-metadata IP 及 `metadata.google.internal`；不会解析其它主机名，也不在连接时重新检查目的地址。获授权 agent 可以指定 daemon 网络可达的其它地址。

### 其余 17 个工具

标记为无字段的工具，完整输入就是空 object `{}`。

| 工具               | 完整输入字段                                                                                                                                               | 结果 / 语义                                                                                                                              |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `list`           | 无                                                                                                                                                    | `services`：准确或 pending URL/state，以及 `funnel_requested`、`funnel_active`、`funnel_state`、可选截止时间/剩余时间/error                              |
| `unshare`        | `name`：必填 DNS-label string                                                                                                                           | `ok`、`name`、`removed`、`device_cleaned`、`device_cleanup_skipped`，可选 `device_skip_reason` / `device_warning`                           |
| `status`         | 无                                                                                                                                                    | `authenticated` 是 `node_authorized` 别名；分别读取 `credential_stored`、授权/服务数量、`daemon_running`、`supervision`，可选 `status`、`auth_url`、`next` |
| `url`            | `name`：必填 DNS-label string；`wait`：可选 Go duration，最多 `5m`，空或非正数不轮询                                                                                    | 准确的 `name`、`url`、`state`；pending 返回 `url_not_ready`，不会猜主机名                                                                           |
| `tags_list`      | 无                                                                                                                                                    | 注册服务名和本地记录的 tags                                                                                                                     |
| `tags_set`       | `service`：必填 string；`tag`：必填、以 `tag:` 开头的 string                                                                                                     | 用一个 tag 替换服务的本地 tags；返回 `service`、`tags`                                                                                             |
| `access_explain` | `service`：必填 string                                                                                                                                  | 本地暴露/执行证据、未知外部策略、后端认证假设；不是有效 tailnet 授权证明                                                                                            |
| `doctor`         | `probe_external`：可选 boolean，默认 `false`                                                                                                               | findings、counts、supervision、运行时/凭据证据；`health_exit_code` 只报告 CLI 健康严重性，warning/critical 本身不让 MCP tool 失败                              |
| `logs`           | `source`：`err` 或 `out`，默认 `err`；`last`：integer `1..1000`，默认 `100`；`level`：可选最低 `debug`、`info`、`warn`、`error`；`since`：正 Go duration，默认 `1h`，最多 `168h` | 只读、有界日志窗口，见下文                                                                                                                        |
| `invite_user`    | `email`：必填 string；`role`：可选 `member`、`admin`、`billing-admin`、`it-admin`、`network-admin`、`auditor`，默认 `member`；`print_link`：boolean，默认 `false`        | 真实 tailnet 邀请，需确认收件人和 role；`print_link` 返回 bearer URL 而不发邮件                                                                          |
| `invite_device`  | `service`、`email`：必填 strings；`print_link`、`multi_use`、`allow_exit_node`：booleans，默认 `false`                                                          | 给 tailnet 外的人发送一个已证明归属服务设备的真实邀请                                                                                                      |
| `invite_list`    | `show_urls`：boolean，默认 `false`                                                                                                                       | 读取未完成邀请；默认隐藏 bearer URLs；`complete: false` 表示部分设备未能检查                                                                                |
| `invite_revoke`  | `kind`：必填 `user` 或 `device`；`invite_id`：必填 string                                                                                                    | 取消真实邀请；结果含 `revoked` 和 remote-side-effect plan                                                                                       |
| `invite_resend`  | `kind`：必填 `user` 或 `device`；`invite_id`：必填 string                                                                                                    | 给原收件人重发真实邮件；不支持 `print_link` 邀请                                                                                                      |
| `template_list`  | 无                                                                                                                                                    | 内置模板与服务数；不安装第三方应用                                                                                                                    |
| `template_plan`  | `name`：必填 string                                                                                                                                     | 只读计划；`dry_run: true`、`applied: false`                                                                                                |
| `template_apply` | `name`：必填 string；`no_daemon_install`：可选 boolean                                                                                                      | 写入模板缺失服务、保留已有同名条目；未禁用时按需安装网关；读取 `applied`、`created`、`skipped`                                                                        |

邀请 URL 是 bearer credential。公开 Funnel 和邀请变更会产生真实外部影响；agent 应在调用前与用户确认具体动作。MCP 发送非 `member` role 的用户邀请或允许 exit-node use 的设备邀请，还要求 owner 通过 `mcp.allow_elevated_invites` 显式允许，否则返回 `mcp_elevated_invite_refused`。`unshare` 也标记为 destructive：它执行与 `tslink remove` 相同的精确所有权设备及 node-state 删除，server instructions 要求客户端先与用户确认。

### `logs` 与身份边界

应用/访问日志写入 stderr（`tslink.err.log`）；`out` 是 daemon stdout。MCP 返回 `source`、`file`、可选 `level`、`since`、`since_at`、`lines`、`count`、`matched`、`truncated`、可选 `truncated_reason`（`line_limit` / `byte_limit`），以及 `redacted: true`。脱敏后的返回文本还限制在 256 KiB 内。

凭据材料、可识别的 Tailscale 登录/邀请 URLs 和邮箱被脱敏，这会减少偶然进入模型上下文的内容，但不保证清除所有 secret 形态。`tslink logs` CLI 原样读取同一文件，所以脱敏不是阻止有 shell 的 agent 访问 secret 的边界。用 access\_log / access\_summary 查看[访问历史](https://tslink.md/zh/docs/access-history.md)中的有界记录与 receipt，身份可缺失，也可能丢失或有崩溃缺口。Proxy 身份头保留独立的 best-effort 缓存边界。

## 完整示例：报告到 URL

完成适用版本协商后调用：

```json
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"share","arguments":{"target":"/absolute/path/report.html","name":"report"}}}
```

成功交接把同一载荷作为 JSON 放进 `content[0].text`，并作为已解析 object 放进 `structuredContent`：

```json
{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\"status\":\"needs_login\",\"auth_url\":\"https://login.tailscale.com/a/...\"}"}],"structuredContent":{"status":"needs_login","auth_url":"https://login.tailscale.com/a/..."}}}
```

把 `auth_url` 交给用户。完成授权后，用 `{"name":"report","wait":"30s"}` 调用 `url`，把 `structuredContent.url` 交回。用 `list` 查看就绪状态，无需重发 share。用完后，用 `{"name":"report"}` 调用 `unshare`。

`unshare` 是幂等的：不存在的名称可以同时返回 `ok: true` 和 `removed: false`。本地删除与远端设备清理分开；远端清理要求 API client 和准确所有权证明。默认零凭据流程可以删除 registry 条目，但留下远端设备。

## 错误与取消

工具/业务失败返回 `isError: true`，`content[0].text` 为可读错误，`structuredContent` 包含 `ok: false`、数字 CLI `code` 和带稳定 code/message、可能有 `next` 的 `error`。`needs_login` 是成功结果。未知 method（`-32601`）和无效参数（`-32602`）等属于 JSON-RPC 错误，不是 CLI 信封。结束 session 的输入遵循上方终止规则，不是可逐行恢复的错误。

使用唯一 request id；放弃请求时使用 MCP cancellation notifications。关闭 stdin 会排空已读请求，不会立即取消。要取消整个进程应发信号，并持续读取 stdout 直到退出。

## 远程 MCP 控制面

`tslink serve --mcp` 在专用 TLS tsnet 节点的 `https://<node>.<tailnet>.ts.net/mcp` 提供同一组 44 个 owner 工具。默认名 `tslink-mcp`，可用 `mcp.node_name` 覆盖；状态目录为 `~/.config/tslink/mcp-node/`。它不是 registry 服务，不能通过 Funnel 发布。

### 启用

控制面默认关闭。设置 `--mcp` 或 `mcp.enabled: true`；两者都要求 `config.json` 中非空 owner `mcp.allow` 或明确 `mcp.bindings`。MCP 配置需直接编辑；`tslink config set` 也管理受支持的 access-log 设置：

```json
{"mcp":{"enabled":true,"allow":["you@example.com","tag:ops"],"node_name":"tslink-mcp","events_keepalive":"20s"}}
```

配置后采用明确的 daemon 重启或前台 `serve --mcp` 流程；已有网关运行时不要启动第二个。

### 边界

* listener 只在自己的 tsnet 节点上提供 tailnet-only TLS，不绑定主机接口，也不通过 Funnel。获授权 peer 有高权限控制能力，包括公开分享和真实邀请。
* `mcp.allow` 匹配 WhoIs 登录邮箱 / `tag:`；没有有效 owner 条目或 bindings 会拒绝启动。Scope 身份拒绝使用 HTTP 403 与 `mcp_scope_denied`，见[角色与应用范围](https://tslink.md/zh/docs/mcp-scopes.md)。
* `Origin` 若存在，必须与 endpoint 自己的 HTTPS origin 完全一致，否则在授权前 `403`；无 `Origin` 的请求继续进入授权。
* Streamable HTTP 为 stateless，请求 body 上限 1 MiB。client 请求必须来自能访问 tailnet 的设备；云端 connector 不会因为你的电脑可达就能访问私有地址。
* 有存储凭据的控制面节点是 ephemeral；零凭据浏览器注册节点是持久的，禁用后可能需要显式删除 tailnet 设备。崩溃也可能留下等待 Tailscale 清理的设备。

## `/events` 事件流

同一远程节点提供仅 owner 可用的 SSE，沿用 Origin 与调用者检查。精简角色得到 404，改为轮询工具。只发具名 `snapshot`、`update`、`keepalive`，不发默认 `message`。必须为这些名称注册 handler，只有 `onmessage` 不会收到任何事件。

每个 payload 带 `type`。SSE `id:` 是 instance-global 的 `event_id`，与每条 stream 的 `sequence` 不同；按 `event_id` 去重。`instance` 变化意味着 daemon 重启，应丢弃缓存状态。没有 `retry:` 字段，也没有 `Last-Event-ID` replay；每次重连都收到完整 snapshot。

`mcp.events_keepalive` 是 Go duration，默认 `20s`，范围 `5s` 到 `5m`。此 endpoint 属于远程控制面，不是 roadmap 的 admin REST/dashboard API。

## 相关文档

* [命令参考](https://tslink.md/zh/docs/commands.md)
* [任务示例](https://tslink.md/zh/docs/use-cases.md)
* [MCP 服务器托管](https://tslink.md/zh/docs/mcp-hosting.md)

## 人员与应用 recipe 工具

本地默认 owner；已交付的 [MCP 角色与应用范围](https://tslink.md/zh/docs/mcp-scopes.md)限制操作，不隔离 shell/文件系统，也不授予应用访问。变更 receipt 有界，见[访问历史](https://tslink.md/zh/docs/access-history.md)。

| 工具              | 完整输入字段                                                                                                                                                                | 含义                                                                                                 |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `people_add`    | `who`：必填登录账户；`apps`：必填非空 string array；`for`：时长或 `never`；`invite`、`print_links`：boolean ; `until`: string; `ack_never`, `qr`: boolean; `qr_invite`: string             | 保存私有 HTTP/文件授权，首次授权收紧应用。创建邀请需用户自己的 API token，明确 print 才展示 bearer link                              |
| `people_list`   | 无                                                                                                                                                                     | 读取人员、授权、期限与撤销记录                                                                                    |
| `people_update` | `who`：必填；`apps`、`for`、`invite`、`print_links`；`reconcile_invites`、`replace_invites`：应用到 ID 的 object ; `until`: string; `ack_never`, `qr`: boolean; `qr_invite`: string | 需指定应用、期限、QR 生成或 `invite: true`。Invite-only 重试复用完成 ID；reconcile 需主人核对；replace 需 invite-only 且保留授权期限 |
| `people_remove` | `who`：必填；`reconcile_invites`：应用到 ID 的 object                                                                                                                          | 先保存拒绝，再清理待接受邀请；查看 `complete` 与 `cleanup`，已接受网络分享可能保留                                               |
| `apps_detect`   | 无                                                                                                                                                                     | 有界 loopback GET 检测；`complete: false` 为部分结果，不能证明应用安全                                                |
| `recipe_list`   | 无                                                                                                                                                                     | 带版本 catalog，含端口、应用配置、健康路径与安全级别                                                                     |
| `recipe_plan`   | 下方字段                                                                                                                                                                  | 只读预览                                                                                               |
| `recipe_apply`  | 与 `recipe_plan` 相同                                                                                                                                                    | 应用审阅过的 plan，已有名称不变，不安装或配置后端                                                                        |

两个 recipe 工具接受以下全部字段：

| 字段                                        | 类型与行为                                                      |
| ----------------------------------------- | ---------------------------------------------------------- |
| `recipe_id`                               | 必填 string，从 `recipe_list` 取得                               |
| `name`、`target`                           | 可选 string，覆盖服务名及 loopback HTTP(S) 主机端口                     |
| `allow`、`tags`                            | 可选、逗号分隔的 string，与 service 工具的 array 不同                     |
| `health`、`request_limits`                 | Object，与上方 `add` 字段相同                                      |
| `preserve_host`                           | Boolean 覆盖；省略使用 recipe 的 Host 默认值                          |
| `ephemeral`、`no_daemon_install`           | 可选 boolean                                                 |
| `funnel`、`public_ack`、`no_auto_provision` | 可选 boolean；公开需要 `funnel: true`、`public_ack: true` 和合适的应用认证 |
| `funnel_ttl`                              | 共同相对/绝对期限语法，至少 1h，默认 24h，公开上限默认 7d；新的公开拒绝 never。           |
| `control_url`                             | 可选 string，与 Funnel 冲突                                      |
| `force_unsafe_public`                     | 危险的 boolean override，覆盖 never-public recipe 拒绝，不代表应用已认证    |

以相同选项先调用 `recipe_plan` 再 `recipe_apply`。人员修改工具要求确认人、应用与期限，因为它们可能收紧已有访问。TCP 和 Funnel 无法按人授权。撤销阻止新请求，不关闭已接受的流。见[人员分享](https://tslink.md/zh/docs/people-sharing.md)。

七天授权的工具参数：

```json
{"who":"alice@example.com","apps":["preview"],"for":"7d"}
```

注册并完成 `preview` 入网后，用 `people_add` 执行。读取 `person`、`complete`、`invites`、`message` 与 `invite_requirement`；命令成功仍可能有未完成的邀请。

来源：[TSLink MCP 服务注册](https://github.com/anydoor7/tslink/blob/v0.1.1/cmd/mcp.go)、[人员工具](https://github.com/anydoor7/tslink/blob/v0.1.1/cmd/mcp_people.go)、[recipe 工具](https://github.com/anydoor7/tslink/blob/v0.1.1/cmd/apps_mcp.go)。

## 新访问工具的使用边界

`health` 读取后端观察，`access_log`/`access_summary` 查询保留的范围内历史。`people_grant`/`people_revoke` 修改已存在人员的单应用授权。`extend` 设为当前时间加时长，到期需明确 regrant。`app_restart` 排队重启 gateway 节点，不是后端重启或已完成结果，之后轮询 status/health；精简 operator 不能重启已有公共 Funnel 应用。

`guest_create/list/show/revoke` 仅 owner 可用，支持单 HTTP proxy 应用；链接/PIN 可转发，不证明人的身份。`portal_enable/disable` 管理每台主机的私有节点；远程 enable 需当前 portal owner，首次设置/恢复需本地进行。`requests_list/approve/deny` 只给 owner/people-manager；远程还需当前真人 portal-owner 身份，admin designation 本身不够。精简角色不能新建未知人员或修改受保护的 portal-owner/admin 记录。

`mcp_audit` 仅 owner 可用。变更前持久保存 intent，缺 completion 表示结果未知。访问历史与 receipt 分别有界且可能有缺口，不保证完整审计或合规。见[访客链接](https://tslink.md/zh/docs/guest-links.md)、[portal/请求](https://tslink.md/zh/docs/portal-requests.md)、[角色](https://tslink.md/zh/docs/mcp-scopes.md)、[期限](https://tslink.md/zh/docs/durations.md)和[访问历史](https://tslink.md/zh/docs/access-history.md)。
