Files
oc_session/README.md
T
ypshidifu a25683591e server插件v2:reload前mcp配置推送兜底(PATCH /config三连),文案键值化
- 新增 pushMcpConfig:on 对调写 flag 后、reload 前把活配置 mcp 推进
  运行中 OC —— client.config.update({config}) → ({body}) → 原生
  fetch PATCH /config(无 /api 前缀)三连;成功=双保险,失败降级单通道
- SetResult 增 pushed 字段,工具返回文案按双保险/单通道区分
- 用户可见文案「第1行」全部键值化为「模式」键(mcpcfg 已是键值格式)
- 加载日志版本标识升级 v2(含推送兜底);README 补双保险链路说明
2026-09-23 15:31:55 +08:00

5.4 KiB
Raw Blame History

ai-mcp — 给大模型操作的 MCP 开关 server 插件

注册一个 mcp_switch 工具,让大模型自己切换 MCP 的开/关状态 (配置对调 + location.reload 热重载),配合 TUI 插件的 /mcpon /mcpoff 形成闭环。

分支名:ai-mcp | 文件:ai-mcp.ts


一、安装

加载机制(已确认)

  • ✅ 已确认:插件在 session 初始化时才加载,不是进程启动时。 只启动 opencode serve 而不建 session,看不到任何插件日志 (opencode-btw 的报错都带 http.span= 即为证据)。
  • ✅ 已确认:OpenCode v2 对 default 导出有 schema 校验,缺则报 Plugin must export a default definition with an id and an effect or setup function., 所以 default 导出必须给。
  • ✅ 已验证(2026-09-23 实测):全局 ~/.config/opencode/plugins/ 下的一级 .ts 文件会被自动扫描加载。证据:本机 plugins 数组里没有注册 ai-mcp.ts 时,ai-mcp.log 依然出现 module imported + 插件已加载。 显式 file:/// 注册仍然推荐(意图清晰、跨版本稳),两份配置都写。
  • ✅ 已确认:plugins 数组里写不存在的包名(如已弃用的 opencode-btw) 会让状态栏出现 N plugins failed 并在日志刷屏——数组里只留有效条目。

把插件复制到全局插件目录:

~/.config/opencode/plugins/ai-mcp.ts        # Linux / WSL
C:\Users\<你>\.config\opencode\plugins\ai-mcp.ts   # Windows

然后在 opencode.json 里注册(两份配置都要加,否则 mcpoff 对调之后插件会消失):

{
  "plugins": [
    "file:///root/.config/opencode/plugins/ai-mcp.ts"     // WSL/Linux
    // Windows 用: "file:///C:/Users/<你>/.config/opencode/plugins/ai-mcp.ts"
  ]
}

两份配置(含 MCP 版 + 安静版)的 plugins 数组必须完全一致—— 历史教训:一份注册一份没注册,mcpoff 对调后插件就「消失」; 已弃用的第三方条目(如 opencode-btw)会让状态栏报 N plugins failed,不要留。

plugins 数组只放 server 插件;TUI-only 插件({ id, tui })放进去会被 server loader 拒绝,它们的注册位置是 tui.json 的 plugin 数组。

依赖:插件目录下需有 package.json 声明 @opencode-ai/plugin 并装好 (OpenCode 启动时会跑 bun install;WSL 没有 bun 时手动 npm install --omit=dev)。


二、工具说明

字段 值
工具名 mcp_switch
参数 action:on / off / status
效果 对调两份配置 → 校验活文件 → 先推送 mcp 配置进 OC → location.reload 热重载

status 只读,任何时候都允许;on / off 按 mcpcfg.txt「模式」键门控:

模式 大模型调 mcp_switch 用户 /mcpon /mcpoff
自动 ✅ 允许 ✅(视为手动切换一次)
手动 ❌ 拒绝,提示用户用 /mcpon /mcpoff ✅ 仅此可用
关闭 ❌ 拒绝 ❌ 不注册

开启方向是「推送 + reload」双保险(v2 新增):对调并写好 mcp.on.flag 之后、 reload 之前,先把活配置里的 mcp 推进运行中的 OC —— 三连尝试: client.config.update({ config: mcp })(SDK → PATCH /config,无 /api 前缀) → ({ body: { mcp } }) → 原生 fetch PATCH /config。 推送成功再 reload,MCP 百分百加载;推送失败只记日志,自动降级为原 reload 单通道, 不影响后续流程。TUI 插件 /mcpon(v9)与 CLI mcpctl on 是同一套链。

reload 走三连尝试:client.location.reload({location}) → ({}) → 无参 → 兜底 POST /api/location/reload。全部失败时配置已经对调完成(若推送已成功则 OC 内已是新配置),重启 OpenCode 一样生效。


三、格式说明(双导出)

// 1) 命名导出 —— V1 legacy 形式(loader 直接调用拿 hooks)
export const AiMcp: Plugin = async (ctx) => ({ tool: { mcp_switch: tool({...}) } })

// 2) default 导出 —— V2 校验形式(OpenCode 2.0.x 的硬性要求)
export default { id: "ai-mcp", async setup(ctx) { ... } }

为什么两个都要:OpenCode v2 对 default 导出有 schema 校验,缺失会直接报

Plugin must export a default definition with an id and an effect or setup function.
(Missing key at ["default"])

(opencode-btw 就因为缺 default 在日志里反复报这条)。命名导出则是 legacy loader 的入口。 两者返回同一套 hooks,无论加载器认哪个,mcp_switch 都能注册成功。

tool helper 通过动态 import 装载:某端没装依赖时只写错误日志, 不会让整个插件文件加载失败。


四、排查

日志:~/.config/opencode/ai-mcp.log

日志内容 含义
module imported (pid=...) 文件被 OpenCode import 了(模块级留痕,最先出现)
ai-mcp server 插件已加载(命名导出/default/setup) 插件函数被调用了(session 初始化时触发)
什么都没有 没被加载 → 检查 plugins 数组是否注册、路径是否写对
无法加载 @opencode-ai/plugin 依赖没装,去插件目录 npm install

注意:插件在 session 初始化时才加载,不是进程启动时。 只启动 opencode serve 不建 session,是看不到日志的。