Skip to content

功能规格说明:MCP 支持 ​

规格文件:docs/specs/ecosystem/mcp.md创建日期:2026-01-21

用户场景与测试 (必填) ​

用户故事:通过 MCP 使用外部工具(优先级:P1) ​

作为开发者,我希望将代理连接到外部 MCP 服务器,以便使用代理未内置的专用工具(如天气、数据库访问或自定义脚本)。

优先级原因:这是 MCP 支持的核心功能,实现可扩展性。

独立测试:连接到简单的 MCP 服务器(例如 "hello world" 服务器)并验证代理可以列出和调用其工具。

验收场景:

  1. 假设 有有效的 .mcp.json 配置,当 代理启动时,则 它必须读取并注册这些服务器,但不得在此刻拉起任何服务器进程——拨号时机见「按需连接 MCP 服务器」。
  2. 假设 MCP 服务器已连接且工具池未收敛,当 代理列出工具时,则 它必须包含带有 mcp__ 前缀的 MCP 工具。
  3. 假设 MCP 服务器已连接且工具池收敛已生效(池非空且 Exec 可声明,见 docs/specs/core/exec-tool.md),当 代理列出工具时,则 逐条扁平声明让位于 Exec 的目录——撤下的只是"声明"形态,工具本身照常可调用。
  4. 假设 AI 决定调用 MCP 工具,当 工具执行时,则 请求必须发送到正确的 MCP 服务器并将结果返回给 AI。
  5. 假设 AI 在 Exec 脚本里嵌套调用 MCP 工具,当 该调用执行时,则 请求必须同样发送到正确的 MCP 服务器、结果回到脚本(与扁平调用共用同一执行漏斗与权限检查)。

用户故事:把服务器自带的使用说明播报给模型(优先级:P2) ​

作为用户,我希望 MCP 服务器通过 initialize 自述的使用说明(instructions)在它变为可用的那一刻播报一次,这样"限流是多少、调用前要满足什么前提、整个服务器怎么用"这类不调用也要知道的内容不会丢失,同时服务器在会话中途连接时也不会让已经缓存的前缀失效。

优先级原因:这是上下文保真度而非工具能力。工具描述是可以被目录压缩的(模型要看原文得先搜索命中,见 docs/specs/core/exec-tool.md),而服务器级的使用约束一旦被压缩掉,模型就不知道自己在违反什么限制。另一面是缓存:这份内容只在"连接发生"时才有变化,若逐轮重算进系统提示,一次中途连接就会改写整个已缓存前缀(见 docs/specs/core/prompt-cache-control.md 边界情况 10);作为消息追加在尾部则不改写任何已有前缀。

独立测试:连接一个在 initialize 响应里返回多行 instructions 的 MCP 服务器,断言对话历史里出现了这段原文并标明来源服务器,且随后几轮不再重复出现;断开后断言只播报一次"已下线";服务器文本超过上限时断言被截断并标明。

验收场景:

  1. 假设 某 MCP 服务器在 initialize 响应里返回了 instructions,当 连接成功时,则 McpManager 必须保存这段文本,不得丢弃。
  2. 假设 某服务器带有 instructions 且尚未播报过,当 它变为可用(连接成功,或 reconnecting 且保留上次工具快照),则 必须在该轮 API 调用之前追加一条持久化的系统提示消息(isMeta,对 UI 隐藏),内容包含该服务器原文并标明来源服务器(多台服务器时彼此可区分)。
  3. 假设 instructions 是多行文本,当 播报时,则 必须原样保留(含换行),不得按宽度裁剪、也不得只保留首行;但 单台服务器的文本超过 2048 个字符时,则 必须截断到该上限并在末尾标明已被截断,不得静默丢弃。
  4. 假设 某服务器的工具被权限规则全部排除,当 计算本轮可播报集合时,则 不得播报该服务器的 instructions(说明与工具同源,不能让被拒服务器的内容绕过规则进入上下文);服务器一个工具都没有时照常播报。规则是在播报之后才收紧时,已播报的原文按"历史不改写"留在历史里,但不得再次播报。
  5. 假设 一台已播报过的服务器断开、连接失败或转为 error,当 后续轮次计算可播报集合时,则 必须播报一次"该服务器已下线、上述说明不再适用",此后不得再次播报它;不得声称会把它已经播报过的原文从历史里删除(历史不改写),也不得因此重算系统提示。
  6. 假设 本轮既没有新增也没有下线的服务器,当 计算可播报集合时,则 不得追加任何消息(无内容 = 不输出空消息、空段落或只有标题的空章节)。
  7. 假设 工具池已收敛、MCP 工具不再逐条扁平声明,当 服务器播报说明时,则 说明仍必须出现——它是服务器级上下文,不随工具声明形态变化。
  8. 假设 同一台服务器已经播报过且仍然可用、原文未变,当 后续每一轮到达时,则 不得重复播报(播报状态以对话历史中的标记为唯一真源,不另设进程内状态)。
  9. 假设 对话历史因压缩或回退导致播报标记不再存在,当 该服务器仍带 instructions 可用时,则 下一轮必须重新播报(宁可重复,不可丢失)。
  10. 假设 服务器断开后重新连上,当 它再次变为可用时,则 必须再播报一次它的 instructions(第一次播报已被"下线"公告作废,重复优于丢失)。
  11. 假设 会话中途有服务器连接或断开,当 对照前后两轮的系统提示文本时,则 系统提示(静态块与动态块)文本不得因 instructions 的来去而变化——工具声明随连接变化属既有行为(见 docs/specs/core/prompt-cache-control.md 边界情况 9)。

用户故事:管理 MCP 服务器生命周期(优先级:P2) ​

作为用户,我希望手动连接或断开 MCP 服务器并检查其状态,以便排查连接问题或管理资源。

优先级原因:提供对外部依赖的必要控制和可见性。

独立测试:使用 agent.getMcpServers() 检查状态并使用 agent.connectMcpServer() 重新连接失败的服务器。

验收场景:

  1. 假设 MCP 服务器已配置,当 调用 getMcpServers() 时,则 它必须返回当前状态(已连接、错误等)。
  2. 假设 服务器已断开,当 调用 connectMcpServer() 时,则 它必须尝试重新建立连接。

用户故事:通过 Agent 构造函数传递 MCP 服务器(优先级:P2) ​

作为集成 SDK 的开发者,我希望直接将 MCP 服务器配置传递给 Agent 构造函数,以便以编程方式配置服务器而不依赖 .mcp.json 文件。

优先级原因:为 SDK 使用者启用编程式 MCP 配置。

独立测试:在选项中带有 mcpServers 创建 Agent 并验证服务器在没有 .mcp.json 文件的情况下连接。

验收场景:

  1. 假设 mcpServers 传递给 Agent.create(),当 代理初始化时,则 这些服务器必须自动注册(并进入服务器列表),连接的时机与 .mcp.json 来源一致——按需拨号,创建时不拉进程。
  2. 假设 构造函数的 mcpServers 和 .mcp.json 文件同时存在,当 代理加载配置时,则 构造函数提供的服务器对于重复名称必须具有优先权。

用户故事:按需连接 MCP 服务器(优先级:P1) ​

作为用户,我希望 MCP 服务器在真正要用的时候才启动进程,而不是我每打开一个会话就为我从没用过的工具付一份常驻内存,以便长时间开着客户端也不被几十棵服务器进程拖垮(issue #2758)。

优先级原因:一个 stdio MCP 服务器在本机是 uvx → uv → 服务器 → python×2 这样一棵约 130 MB 的进程树。此前 Agent.create 就无条件拨号(initializeService 的 autoConnect=true),而桌面端按设计把真实会话的 Agent 池化到应用退出(切换会话不销毁),于是残留进程数 = 本次运行里创建过 Agent 的会话数,与"现存几个会话"无关——现场实测:应用索引里 3 个会话、wave --stdio 子进程下挂着 11 棵树,且其中 10 棵属于已然不在会话列表里的会话。放大这一条的是宿主形态:桌面端 wave --stdio 子进程、wave --daemon 的长驻 AgentBridge、IM 桥接服务(pm2 长驻、in-process Agent.create、每个 IM 会话一个 Agent)都是"一个进程养很多 Agent",后两者还没有"退出应用"这个天然重置点。再叠上销毁链路的两个失败逃逸口(引用先丢、MCP 回收排在可能抛错的步骤之后,见边界情况「销毁必须先于引用丢弃、且回收不得被前置失败阻断」),失败一次就是一棵永久孤儿树。

独立测试:Agent.create() 后断言无任何 MCP 子进程、且服务器已出现在列表中;发送第一条消息后断言进程树已拉起且本回合就能调用 MCP 工具;手动断开后再发消息断言不会被自动拉起。

验收场景:

  1. 假设 会话刚创建、尚未发送任何消息,当 Agent.create() 完成时,则 不得为任何 MCP 服务器拉起子进程(getMcpServers() 仍必须列出全部已配置服务器,状态为未连接)。
  2. 假设 该会话第一次发送消息,当 回合开始时,则 必须在构造本轮工具配置之前完成拨号,使本轮就能列出并调用 MCP 工具(拨号与本回合其余准备工作并行,串行代价仅剩拨号本身的剩余时间)。
  3. 假设 会话已在用(服务器已连接),当 用户继续发消息时,则 不得重复拨号(已连接即复用)。
  4. 假设 某服务器按需拨号失败,当 本会话后续回合开始时,则 不得再次自动拨号(避免每轮一个超时等待、也避免进程反复拉起),状态保持错误;用户显式点「连接」才重试。
  5. 假设 用户在设置页/MCP 列表里显式「连接」某服务器,当 该动作完成时,则 它必须真的拉起进程(显式连接不受"未使用不拨号"约束)。
  6. 假设 用户显式断开了某服务器,当 后续回合开始时,则 不得因按需拨号把它重新拉起(手动断开优先,见边界情况「手动断开不得被自动重连撤销」)。
  7. 假设 会话在拨号进行中被销毁(删会话/关进程),当 拨号随后成功时,则 必须立刻关掉这条连接与其进程树,不得留下无人拥有的孤儿进程。
  8. 假设 任意服务器被断开或销毁,当 直接子进程(如 uvx)在断开后仍然存活时,则 必须整树终止它(Windows 用 taskkill /PID <pid> /T /F),不得只杀直接子进程把 uv/python 留下。
  9. 假设 某服务器从未在本机连接过(无缓存快照),当 打开 /mcp 或设置页「MCP 服务」时,则 该服务器必须照常出现在列表里,状态为未连接、工具列为空,可在面板内点「连接」。
  10. 假设 某服务器连接成功过,当 之后再次打开 /mcp 或设置页且它尚未拨号时,则 必须用上次的工具快照把工具清单展示出来,并标明来源是缓存和上次连接时间(不得把缓存冒充成"当前已连接")。
  11. 假设 服务器配置(命令、参数、URL、传输类型、环境变量)相对缓存生成时已经变化,当 展示缓存时,则 必须判定缓存失效、不展示旧工具清单(配置变了,旧工具不再可信),直到重新拨号成功。
  12. 假设 服务器已从配置中删除,当 展示列表时,则 它的缓存条目不得出现在任何一端的列表里,并在下一次写入缓存时被清理。
  13. 假设 连接成功、工具列表刷新,当 该轮结束或面板收到状态变化时,则 必须用最新工具覆盖缓存(含清空:服务器现在没有工具就写空,不得保留旧工具)。
  14. 假设 快照缓存文件缺失、不可读或结构损坏,当 代理启动或打开面板时,则 必须静默按"无缓存"处理(列表退化成本会话真实状态),不得因此启动失败或抛错。
  15. 假设 缓存里有工具清单,当 构造本回合的工具配置时,则 不得把缓存里的工具当成可调用工具声明给模型(缓存只服务面板可见性,工具声明与调用必须以真实连接为准)。

用户故事:插件端 MCP 管理对话框(优先级:P2) ​

作为插件端用户,我希望通过 /mcp 打开 MCP 管理界面,查看各服务器的连接状态并手动连接或断开,以便在不切换到 CLI 的情况下排查连接问题。

优先级原因:插件端用户无法使用 CLI 的 MCP 管理界面,需要在插件内获得同等的状态可见性与基本控制能力;但属于辅助管理功能,非核心对话流程。2026-08-29 用户拍板:/mcp 从独立对话框改为唤起设置页并选中「MCP 服务」选项卡(与 /agents、/skills 一致)。

独立测试:在 IDE 中输入 /mcp,验证打开设置页并选中「MCP 服务」选项卡,列表列出服务器及其状态;对已断开的服务器点击连接,观察状态变为已连接;对已连接的服务器点击断开,观察状态变为未连接。

验收场景:

  1. 假设 用户处于图形界面三端(VS Code 扩展 / JetBrains 插件 / 桌面端),当 用户输入 /mcp 并发送,则 打开设置页并选中「MCP 服务」选项卡(桌面端打开全页设置,IDE 打开编辑器区域设置标签页),不再弹出独立对话框。
  2. 假设 设置页「MCP 服务」选项卡已打开,则 列表显示每个服务器的名称、来源(用户级 / 项目级)、连接状态(已连接/连接中/重连中/错误/未连接,以不同颜色标识)、工具数量,以及上次连接时间。
  3. 假设 某服务器处于错误状态,当 列表渲染时,则 该服务器额外显示红色错误原因,且操作按钮显示为"重连"。
  4. 假设 用户点击某服务器的"连接"或"断开",当 操作进行中时,则 按钮显示进行中文案("连接中..."/"断开中...")并禁用,完成后状态刷新——断开操作必须有确定结果:即使进程无法干净退出、teardown 抛错或连接条目已缺失,host 也要回写最新服务器列表(或失败提示),按钮不得无限停留在"断开中..."。
  5. 假设 服务器状态在后台发生变化(如自动重连),当 列表打开时,则 列表实时刷新为最新状态。
  6. 假设 用户未配置任何 MCP 服务器,当 打开列表时,则 显示空状态引导文案,提示创建用户级或项目级 MCP 服务。
  7. 假设 设置页已打开,当 用户点击「返回」或切换其他选项卡,则 回到会话视图或切换到对应选项卡,设置页不产生任何消息。

用户故事:按来源 Tab 展示 MCP 服务(优先级:P1) ​

作为 GUI 用户,我希望设置页「MCP 服务」选项卡按来源以 Tab 形式展示 MCP 服务(用户级 / 项目级 / 插件),其中项目级在「项目级 MCP」Tab 下平铺展示(仅当前项目,不做多项目分组),以便快速定位某个来源下的 MCP 服务,并知道它属于哪一类(用户 / 项目 / 插件)。

为什么是这个优先级:MCP 服务来源决定其适用范围(用户级全局可用 / 项目级仅当前项目),Tab 化让长列表可扫读,与技能页形态统一(2026-08-29 用户拍板:MCP 区分用户级和项目级,用户级配置存 ~/.wave/mcp.json,项目级仍用项目根 .mcp.json;2026-09-01 用户拍板:设置页只针对当前项目,删除项目分组卡片,项目 Tab 直接平铺)。

独立测试:在具备用户级、项目级、插件 MCP 服务的环境中打开设置页 MCP 服务选项卡,验证来源 Tab 存在、项目级服务在「项目级 MCP」Tab 平铺列出并可执行管理操作。

验收场景:

  1. 假设 环境中存在用户级、项目级、插件来源的 MCP 服务,当 MCP 服务选项卡打开,则 顶部展示来源 Tab(用户级 MCP / 项目级 MCP / 插件 MCP),点击切换显示对应来源的服务
  2. 假设 存在项目级 MCP 服务,当 用户位于「项目级 MCP」Tab,则 服务平铺展示(不按项目分组、无项目卡片)
  3. 假设 项目 Tab 下存在多个 MCP 服务,当 列表展示,则 列出所有服务(名称、类型、命令或 URL、连接状态),并提供「编辑」「删除」操作入口
  4. 假设 用户级 MCP 配置存在,当 用户位于「用户级 MCP」Tab,则 列出 ~/.wave/mcp.json 中定义的所有服务
  5. 假设 某来源没有任何 MCP 服务,当 切换到该来源 Tab,则 显示空状态提示,不渲染空白分组

用户故事:新建 MCP 服务(优先级:P1) ​

作为 GUI 用户,我希望在 MCP 服务页点击「新增 MCP 服务」后打开 AI 对话框并预填一条新建提示词,通过自然语言描述即可创建 MCP 服务;配置文件不存在时由 AI 直接创建,已存在时也交由 AI 更新——「新增」一律只预填提示词、不打开文件(与技能 / 子代理 / 钩子的新建一致)。

为什么是这个优先级:手写 MCP 配置 JSON 门槛高;由 AI 根据自然语言生成配置是用户需求的核心(2026-08-29 用户需求:区分用户级和项目级,没有 .mcp.json 时跳转 AI 对话框通过提示词创建;2026-09-10 用户拍板:打开文件只发生在「编辑」,新增沿用技能 / 子代理 / 钩子的「只预填」语义)。

独立测试:在 MCP 服务页点击「新增」,验证 AI 对话框打开并预填提示词;补充描述发送后配置被写入(用户级 ~/.wave/mcp.json 或项目级 .mcp.json);返回 MCP 服务页验证新服务出现在对应来源分组。

验收场景:

  1. 假设 用户在 MCP 服务页「用户级 MCP」Tab,当 用户点击「新增用户级 MCP 服务」,则 关闭设置页回到会话视图,AI 对话框打开并预填用户级提示词,如 /settings 帮我配个用户级 MCP 服务器<名字>:连<command/url>,参数<args>
  2. 假设 用户在「项目级 MCP」Tab 点击「新增」,当 输入框预填,则 预填项目级提示词并带上项目名,如 /settings 帮我在【项目名称】下配 MCP 服务器<名字>:连<command/url>,参数<args>
  3. 假设 对应配置文件(~/.wave/mcp.json 或项目 .mcp.json)尚不存在,当 用户补充描述后发送,则 由 AI 创建配置文件并写入新服务,不额外打开文件
  4. 假设 对应配置文件已存在,当 用户点击「新增」,则 仍只预填提示词、不打开文件(打开文件仅发生在「编辑」;用户可在会话中让 AI 展示当前配置)
  5. 假设 MCP 服务创建成功,当 用户重新打开 MCP 服务页或列表刷新,则 新服务出现在对应来源分组(Tab)中,并带来源标识(用户 / 项目 / 插件)

用户故事:编辑 MCP 服务(优先级:P2) ​

作为 GUI 用户,我希望在 MCP 服务页点击「编辑」后打开 AI 对话框并预填一条编辑提示词,同时打开对应配置文件,以便基于当前内容描述修改点,由 AI 更新 MCP 服务配置。

为什么是这个优先级:MCP 配置修改通过 AI 自然语言描述更顺畅;同时打开配置文件让用户与 AI 都能直接看到/编辑实际 JSON(2026-08-29 用户需求:编辑跳转 AI 对话框提示词,并打开 .mcp.json 文件)。

独立测试:在 MCP 服务页点击某服务的「编辑」,验证 AI 对话框打开并预填编辑提示词、对应配置文件在编辑器打开;描述修改点并发送后配置文件被更新;返回 MCP 服务页验证服务配置已更新。

验收场景:

  1. 假设 用户在 MCP 服务页某服务条目上,当 用户点击「编辑」,则 关闭设置页回到会话视图,AI 对话框打开并预填编辑提示词,如 帮我编辑 MCP 服务器<名字>:把<要改的内容>改成<新内容>
  2. 假设 用户点击「编辑」,则 该服务所在配置文件(~/.wave/mcp.json 或项目 .mcp.json)同时打开便于对照修改(桌面端在会话视图右侧文件面板打开该文件,即消息中 read/edit/write 工具路径点击同款只读面板;IDE 在 VS Code / JetBrains 自身编辑器打开标签页);该路径由宿主解析为绝对路径后随 mcpConfigPathsResponse 下发,webview 不自造 ~ / 相对路径——宿主按 OS 绝对路径打开文件、无法展开 ~
  3. 假设 编辑提示词已预填,当 用户补充具体修改点后发送,则 消息以普通用户消息发送,由 AI 更新配置文件
  4. 假设 MCP 服务修改成功,当 用户重新打开 MCP 服务页或列表刷新,则 服务配置反映修改后的内容

用户故事:删除 MCP 服务(优先级:P1) ​

作为 GUI 用户,我希望在 MCP 服务页对用户级 / 项目级 MCP 服务执行「删除」时先出现二次确认,确认后服务配置从对应配置文件中移除并从列表删除,以便清理不再使用的 MCP 服务。

为什么是这个优先级:删除配置不可逆,需要确认;用户需求明确「二次确认后可删」且删除不依赖 AI(2026-08-29 用户拍板:确认框 + 直接删除配置)。

独立测试:在 MCP 服务页点击某服务「删除」,验证出现确认对话框;确认后服务配置从配置文件中移除、列表删除该服务;取消则无任何变化。

验收场景:

  1. 假设 用户在 MCP 服务页某用户级 / 项目级服务条目上,当 用户点击「删除」,则 弹出二次确认对话框,说明将删除的服务名及其配置文件路径
  2. 假设 确认对话框已显示,当 用户点击「取消」或关闭对话框,则 不执行删除,服务保持原样
  3. 假设 确认对话框已显示,当 用户点击「确认删除」,则 服务配置从对应配置文件(~/.wave/mcp.json 或项目 .mcp.json)中移除,列表删除该服务,不经过 AI
  4. 假设 删除成功,当 用户重新打开 MCP 服务页或列表刷新,则 该服务不再出现在任何来源分组中
  5. 假设 服务由插件提供,当 列表展示,则 不提供「删除」入口(只读来源不可删除)

用户故事:用户级 MCP 配置(优先级:P2) ​

作为用户,我希望在 ~/.wave/mcp.json 中配置常用的 MCP 服务器,以便这些服务器对所有项目可用,无需在每个项目根目录重复配置。

优先级原因:用户级配置是常见 MCP 服务器(数据库、代码搜索等)的复用基础,也是设置页 MCP 视图「用户级/项目级」双 tab 的数据支撑(2026-08-31 用户拍板:先支持用户级 MCP 配置,再实现 MCP 设置视图)。

独立测试:在 ~/.wave/mcp.json 配置一个服务器并在无项目 .mcp.json 的新目录启动代理,验证服务器自动注册并可连接;同时配置用户级与项目级同名服务器,验证项目级覆盖用户级。

验收场景:

  1. 假设 ~/.wave/mcp.json 存在且包含 mcpServers,当 代理在任何工作目录初始化时,则 用户级服务器必须自动注册(进入服务器列表),但不得在初始化时拉起进程——拨号时机见「按需连接 MCP 服务器」,与项目 .mcp.json 一致。
  2. 假设 用户级与项目级配置了同名服务器,当 代理合并配置时,则 项目级(.mcp.json)覆盖用户级(~/.wave/mcp.json),构造函数传入的 mcpServers 优先级最高(构造函数 > 项目 > 用户 > 插件)。
  3. 假设 用户级 ~/.wave/mcp.json 不存在,当 代理初始化时,则 正常继续,不报错(用户级配置为可选)。
  4. 假设 用户级 ~/.wave/mcp.json 格式错误,当 代理初始化时,则 记录错误并跳过用户级来源,其余配置源(项目/构造函数)正常加载。

边界情况 ​

  • 按需拨号 vs 手动操作:自动拨号只发生在"服务器从未被拨过、且没有被用户断开过"的情况下。用户显式断开的服务器在本次会话内保持断开、不再被按需拨号拉起;用户显式连接的服务器立刻拉起,不等下一次回合。没有待拨号的服务器时,回合不得为此多出等待或让出点——不用 MCP 的会话必须与没有这条机制时完全一致。
  • 拨号与销毁竞态:连接请求在飞行中时会话被销毁(删会话、切 workdir 重建、进程退出)时,cleanup() 只能取消定时器、看不到飞行的拨号——所以拨号成功返回后必须检查"是否已被销毁",已销毁则立刻关掉传输与其进程树,不允许出现无人拥有的孤儿服务器进程。
  • 断开后整树终止:stdio 传输的 close() 只对直接子进程做 stdin EOF → SIGTERM → SIGKILL。直接子进程断开后仍存活时,必须整树终止(Windows taskkill /PID <pid> /T /F);不得只杀直接子进程把 uv/python 等后代留在机器上(历史上表现为"服务器进程活到应用退出")。
  • 销毁必须先于引用丢弃、且回收不得被前置失败阻断:Agent.destroy() 里 MCP 回收排在 transcript 落盘(saveSession / reAppendSessionMetadata)之后,而这两步都可能抛错(Windows 文件被占用、worktree 目录已不存在导致 ENOENT)。transcript 落盘失败只允许记 warning 并继续 teardown——不得让它阻断 MCP/LSP 回收;否则调用方(桌面宿主、AgentBridge、IM 桥接服务)都已在销毁前把引用删掉,抛错后谁也无法再找到这个 Agent,其进程树活到宿主退出为止。同理,McpManager.cleanup() 必须幂等:重复调用不得抛错,也不得留下半断开状态。
  • 销毁请求被拒必须有兜底:AgentBridge 在配置重建窗口内会以「Session X is being reconfigured」拒绝 destroy(重建拥有该会话条目,销毁会与重建互相打架)。调用方收到该拒绝时不得只丢掉自己的引用就当删完了(桌面端现在正是 .catch(() => {}) 后照样删索引条目):要么重试到生效,要么把该 Agent 放进可追踪的待回收队列并由宿主的后续动作清掉。沉默的「引用已删、进程还活」是本规格明确禁止的结果。
  • 长驻宿主不以进程退出作为回收兜底:wave --daemon(跨连接复用会话、无闲置驱逐)与 IM 桥接服务(pm2 常驻、每个 IM 会话一个 Agent)可以连续运行数周,没有"退出应用"这个天然重置点,也不存在用户手动删会话的必然动作。因此回收必须由 SDK 侧保证(按需拨号 + 销毁回收 + 销毁后不得复活),不得把责任推给宿主生命周期;IM 桥接服务通过 npm 依赖 wave-agent-sdk 接入,修复随 SDK 版本生效(它 pin 了具体版本,需要升依赖),本次不修改该仓库。
  • 未拨号时的可见性(工具快照缓存):按需拨号后,"什么都没连"不能等于"什么都看不见"。首次连接成功时把该服务器的工具清单写进本机快照缓存(~/.wave/mcp-tools-cache.json,键 = 服务器名 + 配置指纹),面板在未拨号时用缓存展示工具并标明"来自缓存 / 上次连接时间",状态仍是未连接;配置指纹变化即视为失效,不展示旧工具。缓存只服务面板可见性——不得作为模型侧的工具声明来源(否则模型会拿到已经不存在的工具的调用权)。缓存不可读/损坏按"无缓存"处理,不阻塞启动。清理只按写入方自己的项目范围做:一个进程同时托管多个会话(桌面 wave --stdio、daemon),写缓存时只清理"同 workdir 且已不在配置里"的条目,不得因为 B 项目的写入而删掉 A 项目的快照。
  • 手动断开不得被自动重连撤销:用户主动断开某服务器时,teardown 触发的 transport close 不得被指数退避自动重连机制再次拉起;断开后需用户显式点击"连接"才会重连。自动重连仅适用于非人为原因(进程崩溃、传输意外断开)的恢复。
  • 断开 vs 删除:断开仅是运行时动作——终止子进程并把状态置为未连接,配置文件(.mcp.json / ~/.wave/mcp.json)中的服务保留,可随时手动重新连接;从配置中移除服务须走"删除"。
  • 断开竞态护栏:断开时若有并发连接/崩溃后的陈旧进程退出事件,不得误删新建立的连接或误改新状态——只有"当前代际"的传输关闭才允许改写该服务器的连接与状态。
  • 服务器崩溃:如果 MCP 服务器进程意外终止,McpManager 必须检测传输错误并将服务器状态更新为 error。
  • 工具名称冲突:来自不同服务器的同名工具通过添加 mcp__[serverName]__[toolName] 前缀来处理。该扁平全名同时是沙箱 tools 对象上的键与权限规则匹配的身份;工具池收敛只撤下"声明",全名与身份都不变(见 docs/specs/core/exec-tool.md)。
  • 不支持的 Schema 字段:包含 $schema、exclusiveMinimum 或 exclusiveMaximum 等字段的 MCP 工具 schema 必须被清理以确保与 LLM API 的兼容性。
  • 服务器级 instructions 与工具描述的职责边界? 服务器级的 instructions 走独立的播报通道(服务器可用时追加一条 isMeta 消息,见本文件"把服务器自带的使用说明播报给模型")、不参与目录预算也不裁剪,适合承载"不调用也要知道"的内容(限流、前置条件、整体用法约定);单个工具的描述会被目录压缩、要拿原文得靠搜索命中,所以不要把服务器级约束写进工具描述里。
  • instructions 会不会让前缀缓存失效? 不会(这正是把它从系统提示挪到消息通道的原因):播报只追加在消息尾部,不改写系统提示文本,也不改写任何已有历史。对齐对象是 Claude Code 的 mcp_instructions_delta 附件——CC 把同一条内容从"每轮重算的系统提示段"移出,注释写明后者 "busts the prompt cache on late MCP connect"。代价是两点,都是刻意的:①服务器断开不能再把原文从上下文里移除(历史不改写,只能追加一条"不再适用");②断开后重连会再播报一次(重复优于丢失)。单台服务器文本上限 2048 字符(对齐 Claude Code 的 MAX_MCP_DESCRIPTION_LENGTH),按英文字符口径计价、不做 CJK 感知(MCP 服务器自述的说明绝大多数是英文,与目录预算同一口径)。
  • 无效配置:如果 .mcp.json 格式错误,代理应记录错误并在没有 MCP 工具的情况下继续。
  • 配置合并:当存在多个配置源(构造函数、项目 .mcp.json、用户 ~/.wave/mcp.json、插件)时,它们按以下优先级合并:构造函数 > 项目(.mcp.json)> 用户(~/.wave/mcp.json)> 插件服务器。
  • SSE 重连:当 SSE EventSource 连接意外断开时,系统必须尝试使用指数退避自动重连。重连期间,服务器状态必须显示 "reconnecting"。如果所有尝试后重连仍失败,状态必须转为 "error"。
  • 无 HTTP→SSE 回退:当基于 URL 的服务器具有 type: "http"(或无 type,默认为 "http")时,如果 Streamable HTTP 连接失败,系统不得回退到 SSE。需要 SSE 的用户必须显式设置 type: "sse"。
  • 未知类型:如果 type 设置为无法识别的值,系统必须在连接时抛出错误。
  • IDE 对话框状态刷新竞态:插件端对话框收到状态推送时,必须忽略比当前列表更旧的快照,防止旧数据覆盖新状态。
  • 删除 MCP 服务失败怎么办? host 更新配置文件失败(权限不足 / 文件不存在)时,向 webview 返回错误提示,列表保持删除前状态,不静默失败
  • 用户级 / 项目级 MCP 配置文件路径? 用户级 ~/.wave/mcp.json,项目级 <项目工作目录>/.mcp.json;两级合并加载,同名服务器项目级覆盖用户级(合并顺序为 插件 → 用户 → 项目 → 构造函数,后合并的覆盖先合并的,见上文"配置合并")
  • 项目级 MCP 的目标项目是哪个? 三端设置页均为单项目模型——展示/管理当前会话 workdir 的项目级配置;「项目级 MCP」Tab 平铺展示,无项目分组归属推断(2026-09-01 用户拍板:设置页只针对当前项目)
  • 项目级 MCP 的目标项目是哪个? 三端设置页均为单项目模型——展示/管理当前会话 workdir 的项目级配置;新建/编辑项目级 MCP 的目标项目 = 当前对话的 workdir,AI 对话框直接写入该项目目录(2026-08-29 用户拍板:不做跨项目选择)
  • 新建/编辑 MCP 提示词中的 /settings 前缀怎么办? GUI 中 /settings 不是可拦截的本地斜杠命令,预填文本作为普通用户消息原样发送给 AI;前缀仅作为自然语言指令的一部分提示 AI 处理 MCP 配置请求
  • IDE 侧「打开配置文件」与「关闭设置页」的先后顺序? 两个动作都由设置页入口向宿主发出,且关闭动作会销毁设置页载体(VS Code 设置 WebviewPanel 被 dispose、JetBrains 设置文件编辑器被 close);打开文件必须先于关闭设置页发出,否则销毁后到达的打开请求被丢弃——表现为四个视图(技能 / 子代理 / 钩子 / MCP 服务)点「编辑」都不打开文件(桌面端设置页与聊天共用一个 webview,不涉及此顺序)。同理,配置文件路径缺失时只预填提示词、不打开文件(不自造占位路径)

假设 ​

  • MCP 服务器可以是本地进程(stdio)或远程端点(http/sse)。
  • 代理具有执行 MCP 配置(.mcp.json / ~/.wave/mcp.json)中指定命令的足够权限。
  • .mcp.json 文件位于代理的工作目录中,用户级 ~/.wave/mcp.json 对所有工作目录生效。
  • MCP 服务器配置可以通过多个源提供:构造函数选项、项目 .mcp.json、用户 ~/.wave/mcp.json、插件配置。
  • 工具快照缓存是本机、跨会话的展示用缓存(~/.wave/mcp-tools-cache.json),与配置文件同一隐私边界,不含任何凭据;同一台服务器在不同 workdir 下的配置指纹不同,互不覆盖。
  • 按需拨号把"会话没被用过就不拉进程"当作默认:代价是第一个真正用到 MCP 的回合要等拨号完成(拨号与本回合其它准备并行),且未拨号前面板只能展示缓存或空工具列表。