Tinycast AI Chat 集成 MCP 服务器:配置、权限模型与工具调用机制全解析
2026/9/20 5:21:18 网站建设 项目流程

Tinycast AI Chat 集成 MCP 服务器:配置、权限模型与工具调用机制全解析

【免费下载链接】tinycastTinycast — a tiny, fully native macOS launcher, hotkeys, and clipboard history.项目地址: https://gitcode.com/GitHub_Trending/ti/tinycast

Tinycast 的 AI Chat 支持通过 Model Context Protocol(MCP)服务器向模型开放真实世界的工具调用能力——无论是远程 HTTP 服务还是本机命令进程。本文基于 website/content/docs/ai/mcp.md 展开,结合 Tinycast/Features/MCP 下的源码实现与 Tests/mcp-test.swift 测试用例,完整讲解从服务器接入、密钥安全存储、@slug句柄寻址到信任决策链路的每一个环节,帮助你在 Tinycast 中安全、可控地接入并使用 MCP 工具。

MCP 在 Tinycast 中的角色

Model Context Protocol(MCP)服务器向模型提供可调用的工具:读取一个文件夹、检索 issue 跟踪器、查询某项数据。接入一台服务器后,AI Chat 会在对话过程中把这些工具交给模型使用。

MCP 功能的开关位于Settings → AI → MCP Servers → Enable MCP servers,默认关闭。它只在 AI Chat 开启时才有意义——只要 AI Chat 或 MCP 开关任一关闭,就不会连接任何服务器,也不会运行任何服务器进程。从源码看,这一约束由 MCPCoordinator.swift 中的isActivesettings.aiEnabled && settings.mcpEnabled)统一把关:一旦失活,manager.stop()会立即终止所有连接与子进程。

// Tinycast/Features/MCP/UI/MCPCoordinator.swift var isActive: Bool { settings.aiEnabled && settings.mcpEnabled } func applyEnabled() { guard isActive else { manager.stop() // 任一开关关闭:不连接、不驻留进程、不向模型暴露任何工具 return } manager.reconcile(store.enabledServers) }

添加一台 MCP 服务器

点击Add MCP Server打开编辑器,字段说明如下:

字段填写内容
Name任意名称,会成为服务器的handle(句柄),例如@github
ConnectionHTTP(远程服务器)或Command(在本机运行)
URL仅 HTTP 使用。远程服务器必须使用 HTTPS;纯 HTTP 只允许用于localhost
Header仅 HTTP 使用。一个请求头名称与值,例如AuthorizationBearer …
Command仅本地服务器使用,例如npx
Arguments例如-y @modelcontextprotocol/server-filesystem ~/Desktop
EnvironmentNAME=value,每行一个,例如GITHUB_TOKEN=…
TrustAsk Each ChatAlways AllowNever Allow

两种连接方式在源码中对应 MCPServer.swift 的MCPTransportKind枚举:

enum MCPTransportKind: Codable, Equatable, Hashable, Sendable { case http(url: String, headerName: String) // 远程,默认头名 Authorization case stdio(command: String, arguments: [String], environmentKeys: [String]) }

Test Connection会执行一次真实的 MCP 握手(initializenotifications/initializedtools/list),并报告服务器提供了多少工具,因此拼写错误会在这一步暴露,而不是等对话进行到一半才失败。握手过程可见于 MCPServerConnection.swift:连接建立后依次发送initialize(携带协议版本与clientInfo,其中客户端名为tinycast)、notifications/initialized通知,最后通过tools/list拉取工具清单。

密钥只进 Keychain

Header 值与 Environment 值存储在登录钥匙串(login Keychain)中,绝不会写入偏好设置、日志或备份。删除服务器时会一并删除这些密钥。

这由 MCPSecretStore.swift 保证:每台服务器对应一条独立的 Keychain 条目(以服务器 UUID 为键),save时若 secrets 为空则直接移除条目;读取失败视为“无密钥”,服务器会在连接阶段失败而不是在存储层报错。

⚠️ 安全提示:本地服务器以你自己的用户账户运行,因此只应添加你信任的命令。模型调用工具的能力边界由下文“权限”一节控制,但命令本身的执行身份就是你的账户。

在对话中使用工具

所有已启用服务器的工具都会提供给模型。当模型调用某个工具时,回复中会内联显示一行记录,运行期间带有 spinner 动画;工具完成后回复继续输出,这行记录会随聊天一起保存。

只和某一台服务器对话:@handle

以句柄开头输入消息即可限定范围,例如@filesystem list my desktop。此时只有该服务器的工具会被提供给模型,且句柄会在消息发出前被移除。若句柄没有匹配任何服务器,消息会按原样发送。

句柄的生成规则在 MCPServer.swift 的MCPSlug中实现:由服务器名称小写化、非字母数字字符折叠为连字符得到(最长 24 字符);重名时自动追加-2-3等后缀,而不是拒绝——同名服务器可以共存。例如GitHub Issues归一化为github-issues(Tests/mcp-test.swift 中有对应断言)。@github list my issues这种消息的解析逻辑在MCPComposerAddress.parse中实现,测试覆盖了“句柄出现在消息中间不算寻址”“单独一个@不寻址任何服务器”等边界情况。

在源码层面,@slug作用域通过 MCPCoordinator.swift 的tools(scopedTo:)完成:传入 slug 时只返回该服务器的工具;此外该处还过滤掉信任级别为.never的服务器。

运行权限:Ask Each Chat 的完整决策链

默认信任级别为Ask Each Chat,此时会话中第一次工具调用会弹出询问对话框:

  • Always Allow:记住该服务器的选择(对这台服务器永久放行)
  • Allow This Chat:仅本次对话放行
  • Don't Allow:仅拒绝这一次调用;按esc效果相同,下一次调用会再次询问

Never Allow设置在服务器行上,效果是保留服务器但不提供其任何工具,且只有设置界面能设置该级别——对话中的“拒绝”永远只是单次或单会话的临时决定。

信任决策由 MCPTrustPolicy.swift 这个纯函数实现,Tests/mcp-test.swift 对其四个分支均有断言:.never恒拒绝、.always恒放行、.ask在会话已授权时放行否则询问。

// Tinycast/Features/MCP/Model/MCPTrustPolicy.swift static func decide(trust: MCPTrust, isGrantedForChat: Bool) -> Verdict { switch trust { case .never: return .refuse case .always: return .allow case .ask: return isGrantedForChat ? .allow : .ask } }

会话级授权的“记忆”由 MCPCoordinator.swift 的chatGrants维护:以(chat: UUID, servers: Set<UUID>)记录“哪次对话已给哪些服务器授权”,换一次对话(新的 chat UUID)授权即失效。当模型调用工具时,调用会被重写为slug__toolname这种带命名空间的 wire name(由 MCPTool.swift 的MCPToolName.compose生成,总长不超过 64 字符以满足 OpenAI 等更严格的提供方限制),收到调用后由MCPToolName.parse反解出 slug 与工具名,再路由到对应连接执行。

被拒绝或失败的调用不算错误

一次被拒绝或执行失败的调用不会中断对话。模型会被告知发生了什么,然后可以在没有该工具结果的情况下继续作答。

哪些模型会获得工具

只有API 连接会被提供工具:OpenAI API、Anthropic Claude、Google Gemini、OpenRouter 以及 OpenAI Compatible 端点。

Apple Intelligence 以及本机安装的 Codex、Claude、Grok、OpenCode、Cursor 命令永远不会获得工具——对这些模型,对话行为与没有 MCP 时完全一致(详见 AI Chat 文档 中“Installed AI”一节:Claude/Grok/OpenCode 运行在工具、文件访问与 shell 访问全部关闭的纯聊天模式)。

运行限制

Tinycast 对 MCP 的使用施加了以下边界:

  • 一次回复最多经历10 轮工具调用。模型如果只反复调用工具而不回答,视为停止作答,回复会终止并明确说明。
  • 单个工具结果、以及一次回复中所有结果的总和,都有大小上限。
  • 服务器在进入聊天时启动,闲置10 分钟后停止,或 Tinycast 退出时停止。这一点在 MCPServerManager.swift 中以idleTimeout = .seconds(600)实现,且每次使用都会调用markUsed()重新计时——倒计时衡量的是“闲置时长”而非“运行时长”。
  • Tinycast 不会向服务器暴露任何自身能力。服务器发起的请求(如 sampling)一律被拒绝,对应的 MCP 错误码为-32601,消息为"Tinycast exposes no MCP capabilities."(见 MCPProtocol.swift)。

此外,服务器在运行期间可以通过notifications/tools/list_changed通知增删工具,MCPServerConnection.swift 会据此重新拉取工具清单;一次失败的服务器在下一次进入聊天时会自动重试连接,网络抖动导致的临时失败不会让服务器永久失效。

备份与可移植性

MCP 开关和服务器列表都不会随备份迁移(参见 backup 文档)。原因很直白:服务器列表可以在你的 Mac 上执行代码,因此添加服务器必须是你在当前机器上亲手完成的操作,而不是从备份里悄悄恢复出来的内容。

小结

Tinycast 的 MCP 集成可以概括为三个设计原则:默认关闭、按需启动、密钥隔离。服务器仅在 AI Chat 与 MCP 开关同时打开时才会连接,进程随聊天启停并受 10 分钟闲置超时约束;Header 与环境变量只存 Keychain;信任决策按“单次调用 / 单次会话 / 永久”三级授予,且只有设置界面能永久禁用一个服务器。对于希望让本地模型快速获得工具能力的用户,建议从 HTTP 远程服务器(@modelcontextprotocol/server-filesystem这类 npx 命令)开始,先用Test Connection验证握手,再用@slug句柄在小范围内试跑工具调用,最后再根据使用频率调整信任级别。

【免费下载链接】tinycastTinycast — a tiny, fully native macOS launcher, hotkeys, and clipboard history.项目地址: https://gitcode.com/GitHub_Trending/ti/tinycast

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

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

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

立即咨询