feat(agent): add external MCP client support
Reuse OpenCode 2 HTTP/stdio clients with per-session read-only grants, native approval and sanitized owner-scoped MCP status. Narrow the environment inherited by trusted local MCP processes. Validated in an isolated checkout with bun run check and 20 focused tests.
This commit is contained in:
@@ -23,6 +23,7 @@ POST /api/v1/agent/chat/session
|
||||
POST /api/v1/agent/chat/task-executions
|
||||
GET /api/v1/agent/chat/sessions
|
||||
GET /api/v1/agent/chat/session/:session_id
|
||||
GET /api/v1/agent/chat/session/:session_id/mcp
|
||||
GET /api/v1/agent/chat/session/:session_id/stream
|
||||
POST /api/v1/agent/chat/stream
|
||||
POST /api/v1/agent/chat/abort
|
||||
@@ -166,3 +167,55 @@ client 模式的外部 OpenCode 需要使用 `serviceOpencodeConfig` 加载可
|
||||
|
||||
|
||||
P2 的大结果文件中转、供水瓶颈和服务区算法未迁入。
|
||||
|
||||
## 外部 MCP 客户端
|
||||
|
||||
供水 Agent 复用 OpenCode 2.0.24 的 MCP 客户端,支持远程 Streamable HTTP、管理员配置的本地 stdio、原生 OAuth、工具目录更新和取消调用。当前 MCP 正式协议为 [2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28),配置依据见 [OpenCode MCP 文档](https://opencode.ai/v2/docs/mcp-servers/)。本次接入不发布 TJWater MCP 服务,也不增加 MCP Apps 或 Tasks 的前端界面。
|
||||
|
||||
仓库中的 `mcp.servers` 默认是 `{}`。管理员在服务的 `opencode.json` 或 `OPENCODE_CONFIG_CONTENT` 中配置连接;模型和浏览器不能提交 MCP 地址、进程命令或认证头。所有服务名必须使用 `mcp_` 前缀,其余字符限英文字母、数字、下划线和连字符。下面是配置片段,示例默认禁用;替换为实际地址/程序后再启用:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcp": {
|
||||
"timeout": { "startup": 10000, "catalog": 10000, "execution": 60000 },
|
||||
"servers": {
|
||||
"mcp_docs": {
|
||||
"type": "remote",
|
||||
"url": "https://mcp.example.com/mcp",
|
||||
"protocol": "auto",
|
||||
"oauth": false,
|
||||
"headers": { "Authorization": "Bearer {env:MCP_DOCS_TOKEN}" },
|
||||
"disabled": true
|
||||
},
|
||||
"mcp_company": {
|
||||
"type": "local",
|
||||
"command": ["node", "/opt/company-mcp/server.js"],
|
||||
"cwd": "/opt/company-mcp",
|
||||
"environment": { "MCP_API_KEY": "{env:COMPANY_MCP_API_KEY}" },
|
||||
"protocol": "legacy",
|
||||
"disabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
远程默认 `protocol: "auto"`,探测新协议并兼容旧协议;本地默认 `legacy`,避免对旧 stdio 程序额外启动探测进程。只服务新协议时可显式设为 `"2026-07-28"`。`codemode` 沿用原生默认值 `true`,设为 `false` 可直接暴露工具;两种入口执行相同的会话策略。超时单位为毫秒,全局默认启动/目录各 10 秒、执行 60 秒,已有显式全局值和每个服务的覆盖值优先。
|
||||
|
||||
只有管理员核实为只读的工具才自动放行:在已有 `permissions` 数组的 `mcp_*` 审批规则后追加精确工具名的 `allow`,保留原有敏感路径拒绝规则。例如:
|
||||
|
||||
```json
|
||||
{ "action": "mcp_docs_search", "resource": "*", "effect": "allow" }
|
||||
```
|
||||
|
||||
工具的有效名称为 `<server>_<tool>`,不支持的字符由 OpenCode 规范为 `_`,以状态接口实际返回的名称为准。宽泛的 `mcp_* allow`、服务自报的 `readOnlyHint`、历史“始终允许”都不构成只读白名单。后续匹配的拒绝规则继续生效。普通聊天和任务协作中,白名单外调用进入现有 `permission_request` 审批,即使 `approval_mode=always` 也不会自动批准;后台 `task_execution` 只能调用白名单工具,学习复盘 `review` 禁止 MCP 调用,不等待浏览器审批。原生通用 MCP 资源列举/读取入口也受限制:交互会话审批,后台和复盘会话禁止,不能绕过逐个工具的白名单。外部结果是检索资料,不能直接替代 Server 已保存的业务证据或改变调用权限。
|
||||
|
||||
`GET /api/v1/agent/chat/session/:session_id/mcp` 沿用聊天接口的 Bearer、`X-Project-Id` 与会话归属校验。它返回 `servers`,每项仅含 `name`、`type`、`status`、`configured_protocol`、`tools`。状态为 `connected/pending/disabled/failed/needs_auth`;`configured_protocol` 是配置模式,不是协商后的版本。响应不包含连接地址、命令、认证头、OAuth 凭据或原始错误;查询不会创建或迁移会话目录。插件通过内部令牌保护的 `/internal/mcp/session-policy` 获取主服务已有的会话策略,不能凭请求 body 伪造用户或项目。
|
||||
|
||||
需要 OAuth 的服务应省略 `oauth: false`。管理员用同一服务账号、配置、环境和 XDG 数据目录执行 `opencode2 mcp auth mcp_docs`,认证流程、PKCE 与令牌续期由 OpenCode 管理;本项目不向前端暴露 OAuth 凭据,也不把 TJWater 的 Bearer 或项目头自动转交给外部 MCP。原生客户端发送的 OpenCode session ID 仅供调用关联,不是授权凭据。
|
||||
|
||||
本地 stdio 是管理员信任的宿主进程,**不在会话 Shell 的 Landlock/seccomp 沙箱中**。插件将继承环境中除基础运行变量以外的值置空,只添加该服务明确配置的环境变量,内部 Agent/OpenCode 凭据变量始终置空;它仍具有服务账号的宿主文件和网络权限,因此环境收敛不等于 OS 沙箱。
|
||||
|
||||
配置结构错误会使启动失败;可选服务的连接失败或 `needs_auth` 不使核心 Agent 的 `/health` 变为未就绪。client 模式须同步更新可信插件和服务配置,缺少新版状态 RPC 将不能通过 warmup。禁用或移除服务并重启运行时即可回退,无需数据迁移。
|
||||
|
||||
本次定向验证:`bun run check`、`bun test tests/runtime/mcpConfig.test.ts tests/opencode/mcpPolicy.test.ts tests/routes/mcpRoutes.test.ts tests/runtime/opencode.test.ts tests/frontendAction/callIdPlugin.test.ts`。可选的本地原生联调为 `bun run tests/integration/mcp-smoke.ts`:使用临时 XDG 目录和样例 HTTP/stdio 服务,结束后清理自己的进程与数据,不请求模型。
|
||||
|
||||
Reference in New Issue
Block a user