Files
oc_session/README.md
T

133 lines
6.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 对调之后插件会消失):
```jsonc
{
"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」双保险(v3 改为 GET+merge 补 shell)**:对调并写好
`mcp.on.flag` 之后、reload 之前,先把活配置里的 `mcp` 推进**运行中的 OC**:
1. `GET /api/config?directory=` 取运行中配置的 `info.shell`(GET → 活文件 → `null`
三级兜底;`PATCH` body **必含 `shell`**,缺则 400 `Missing key at ["shell"]`,
裸 `PATCH /config` 是 405,必须走 `/api/experimental/config`);
2. 口令链 `service.json` → 环境变量 `OPENCODE_PASSWORD`/`OPENCODE_SERVER_PASSWORD`
→ `opencode.json server.password`,鉴权 `Basic base64("opencode:<口令>")`;
3. SDK 两跳 `config.update({ shell, mcp })` / `({ body })` → 兜底原生
`fetch PATCH /api/experimental/config?directory=`。
推送成功再 reload,MCP **百分百加载**;推送失败只记日志,自动降级为原 reload 单通道,
不影响后续流程。TUI 插件 `/mcpon`(v10)与 CLI `mcpctl on` 是同一套语义
(GET+merge 补 shell → PATCH 真实路由),TUI 走进程内三跳、CLI 走端口发现+探活。
reload 走三连尝试:`client.location.reload({location})` → `({})` → 无参 →
兜底 `POST /api/location/reload`。全部失败时配置**已经对调完成**(若推送已成功则
OC 内已是新配置),重启 OpenCode 一样生效。
---
## 三、格式说明(双导出)
```ts
// 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 v3 server 插件已加载(命名导出,推送走 GET+merge 补 shell)` | 命名导出**被调用了**(legacy loader 入口) |
| `ai-mcp v3 server 插件已加载(default/setup,推送走 GET+merge 补 shell)` | default 导出**被调用了**(V2 校验入口) |
| 什么都没有 | **没被加载** → 检查 `plugins` 数组是否注册、路径是否写对 |
| `无法加载 @opencode-ai/plugin` | 依赖没装,去插件目录 `npm install` |
> 注意:插件在 **session 初始化时**才加载,不是进程启动时。
> 只启动 `opencode serve` 不建 session,是看不到日志的。