From aedb1c1267a102e57c999cf0ea17ff38b3a80963 Mon Sep 17 00:00:00 2001 From: KiriAky 107 Date: Tue, 1 Sep 2026 11:32:47 +0800 Subject: [PATCH] =?UTF-8?q?docs(extension):=20=E8=A1=A5=E5=85=85=E9=98=B6?= =?UTF-8?q?=E6=AE=B5C=20MCP=E5=BC=80=E5=8F=91=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- backend/README.md | 2 +- docs/README.md | 1 + .../AI笔记软件技术栈说明-团队版-v2.3.md | 16 +- docs/architecture/第二阶段团队分工表.md | 4 +- docs/contracts/后端接口契约-开发版.md | 7 +- docs/contracts/第二阶段接口契约-开发版.md | 32 ++- .../AI-Core与Agent-Core开发说明.md | 19 +- .../Knowledge与Retrieval-Core开发说明.md | 2 +- .../MCP-Bridge与Plugin-Host开发说明.md | 262 ++++++++++++++++++ docs/development/前端壳子与接口层开发说明.md | 4 +- .../模型提供商与模型发现开发说明.md | 2 +- .../后端全面审阅问题与修复复盘.md | 2 +- 13 files changed, 328 insertions(+), 28 deletions(-) create mode 100644 docs/development/MCP-Bridge与Plugin-Host开发说明.md diff --git a/README.md b/README.md index 7bfa242..bfc698e 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ cd frontend pnpm test ``` -当前回归基线为后端 81 项测试、前端 27 项测试,且生产构建通过。测试数量会随功能增长,以本地实际输出和 CI 为准。 +当前回归基线为后端 87 项测试、前端 27 项测试,且生产构建通过。测试数量会随功能增长,以本地实际输出和 CI 为准。 构建产物位于 `frontend/dist`,该目录不提交到 Git。 @@ -132,6 +132,7 @@ pnpm test | [后端接口契约](docs/contracts/后端接口契约-开发版.md) | HTTP/SSE 接口、错误和当前实现状态 | | [第二阶段接口契约](docs/contracts/第二阶段接口契约-开发版.md) | 第二阶段公共 DTO、计划接口、SSE、错误码与联调顺序 | | [AI Core 与 Agent Core](docs/development/AI-Core与Agent-Core开发说明.md) | Provider、Agent、Tool、Permission 与 Extension Core | +| [MCP Bridge 与 Plugin Host](docs/development/MCP-Bridge与Plugin-Host开发说明.md) | stdio MCP、隔离进程、Tool 映射、状态与错误边界 | | [Git 使用细则](docs/guides/Git使用细则-团队开发版.md) | 分支、提交、PR、Review 与合并流程 | | [CI/CD 细则](docs/guides/CI-CD细则-团队开发版.md) | Gitea 流水线、质量门禁、产物、发布与回滚规则 | | [Agent Trace 复盘](docs/retrospectives/Agent-Core第二阶段问题与修复复盘.md) | Agent 持久化、SSE 恢复、事件契约与脱敏问题复盘 | diff --git a/backend/README.md b/backend/README.md index c211fc1..3c8429e 100644 --- a/backend/README.md +++ b/backend/README.md @@ -23,7 +23,7 @@ uv run uvicorn app.main:app --reload --host 127.0.0.1 --port 8000 uv run pytest ``` -当前基线为 81 项测试通过。Provider API Key 可通过前端设置页写入,也可用 `OPENAI_API_KEY`、`DEEPSEEK_API_KEY` 或 `AINOTE_CREDENTIAL_` 注入;不要把真实密钥写入仓库。 +当前基线为 87 项测试通过。Provider API Key 可通过前端设置页写入,也可用 `OPENAI_API_KEY`、`DEEPSEEK_API_KEY` 或 `AINOTE_CREDENTIAL_` 注入;不要把真实密钥写入仓库。 团队接口清单见 `../docs/contracts/后端接口契约-开发版.md`,机器可读契约以运行时的 `/openapi.json` 为准。 diff --git a/docs/README.md b/docs/README.md index 5857184..00e38a5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -31,6 +31,7 @@ - [AI Core 与 Agent Core 开发说明](development/AI-Core与Agent-Core开发说明.md) - [Knowledge 与 Retrieval Core 开发说明](development/Knowledge与Retrieval-Core开发说明.md) - [模型提供商与模型发现开发说明](development/模型提供商与模型发现开发说明.md) +- [MCP Bridge 与 Plugin Host 开发说明](development/MCP-Bridge与Plugin-Host开发说明.md) - [前端壳子与接口层开发说明](development/前端壳子与接口层开发说明.md) - [前端写作体验优化开发说明](development/前端写作体验优化开发说明.md) - [前端视觉与轻量动效优化开发说明](development/前端视觉与轻量动效优化开发说明.md) diff --git a/docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md b/docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md index a94e5a1..622abdc 100644 --- a/docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md +++ b/docs/architecture/AI笔记软件技术栈说明-团队版-v2.3.md @@ -5,7 +5,7 @@ > 适用范围:桌面客户端、本地知识库、RAG、Agent、Skill、多模型接入、多模态处理与可选云同步 > 目标读者:前端、Rust 桌面端、Python AI Core、算法、测试与后续接手项目的开发成员 -> 实施状态更新:2026-09-01。本文同时包含目标架构、当前实现和第二阶段接口基线。第一阶段已完成 Vue Web 联调前端、FastAPI、Knowledge/Retrieval、Agent/Tool/Permission、Skill/Plugin 声明式运行时、Mock/OpenAI-Compatible/Ollama Provider、DeepSeek/OpenAI 预设、模型发现及开发阶段 Fernet 凭据存储。Web Workspace 已通过 FastAPI 接入后端配置的真实单 Vault,第二阶段 Agent Trace 持久化、分页快照和可恢复 SSE 已完成。后续继续接入真实音频处理、MCP、Plugin Command/Settings、Provider 协议增强、Benchmark、文档导出、主题包、Trace 可视化、Mermaid 和函数图像。Tauri/Rust Host、Stronghold、原生多 Vault 文件系统和 Sync Server 仍未实现。 +> 实施状态更新:2026-09-01。本文同时包含目标架构、当前实现和第二阶段接口基线。第一阶段已完成 Vue Web 联调前端、FastAPI、Knowledge/Retrieval、Agent/Tool/Permission、Skill/Plugin 声明式运行时、Mock/OpenAI-Compatible/Ollama Provider、DeepSeek/OpenAI 预设、模型发现及开发阶段 Fernet 凭据存储。Web Workspace 已通过 FastAPI 接入后端配置的真实单 Vault;第二阶段 Agent Trace 持久化、分页快照、可恢复 SSE、stdio MCP Bridge 与隔离 Plugin Host 已完成。后续继续接入真实音频处理、Plugin Command/Settings、Provider 协议增强、Benchmark、文档导出、主题包、Trace 可视化、Mermaid 和函数图像。Tauri/Rust Host、Stronghold、原生多 Vault 文件系统和 Sync Server 仍未实现。 --- @@ -1044,6 +1044,8 @@ Plugin Host 负责: MCP Bridge 用于接入具有 MCP Server 接口的插件或外部工具服务。 +当前已实现本地 stdio 首版:Plugin Runtime 在授权后的启用阶段启动独立 Server 进程,完成 `initialize`、capability negotiation、分页 `tools/list`、`tools/call`、取消、超时、异常退出和 Host Restart。实现接受 `2025-11-25`、`2025-06-18`、`2025-03-26` 与 `2024-11-05` 协议版本;Streamable HTTP、Resource、Prompt、Sampling 与操作系统级沙箱仍属于后续范围。 + MCP Tool 进入系统后的调用路径为: ```text @@ -1062,7 +1064,7 @@ Tool Registry 仍使用项目自己的 `ToolDefinition` 和 `ToolResult`。MCP B MCP 能力首先用于 Tool 和 Resource 类扩展。需要复杂 UI 的插件通过 Frontend Extension Slot 单独处理。 -第二阶段 MCP Bridge 至少覆盖以下协议边界: +当前 stdio MCP Bridge 已覆盖以下协议边界: ```text Server Process / Connection Lifecycle @@ -1074,7 +1076,7 @@ tools/call 与 ToolResult 映射 健康检查与 Tool 注销 ``` -首个宿主实现优先支持本地 `stdio` 传输;其他传输在兼容性测试后增加。外部 Server 的 Tool 名称进入项目注册表前添加 Plugin 命名空间,并校验 JSON Schema、权限和重复 ID。MCP 内容不得绕过项目自己的 Permission、超时、日志净化和结果大小限制。 +首个宿主实现支持本地 `stdio` 传输;其他传输在兼容性测试后增加。外部 Server 的 Tool 名称进入项目注册表前添加 Plugin 命名空间,并校验 JSON Schema、权限、重复 ID 及其与 Manifest Contribution 的一致性。MCP 调用复用项目自己的 Permission、超时、Agent Trace、日志净化和结果大小限制;子进程环境按白名单裁剪,不传入 Provider Key、Vault 或数据库路径。 ### 12.6 Frontend Extension Slot @@ -2321,7 +2323,7 @@ Markdown Workspace 第一阶段 Plugin Runtime 已完成安装、启用、停用、权限和声明式 Tool 注册,建立 Skill 调用 Plugin Tool 的基础链路。Command、Settings 和 MCP 执行不计入第一阶段完成项。 -截至 2026-09-01,上述第一阶段后端链路和 Web 联调前端均已完成,第二阶段前置的 Workspace 去 Mock 联调及 Agent Trace 持久化/恢复接口也已完成。当前验证基线为后端 81 项测试、前端 27 项测试及生产构建通过。向量链路当前使用 `HashEmbeddingProvider` 验证工程正确性,真实 Embedding 召回质量不属于该测试结论。 +截至 2026-09-01,上述第一阶段后端链路和 Web 联调前端均已完成;第二阶段前置的 Workspace 去 Mock 联调、Agent Trace 持久化/恢复接口以及 stdio MCP Bridge / Plugin Host 也已完成。当前验证基线为后端 87 项测试、前端 27 项测试及生产构建通过。向量链路当前使用 `HashEmbeddingProvider` 验证工程正确性,真实 Embedding 召回质量不属于该测试结论。 第二阶段在既有 Contract 上接入: @@ -2331,7 +2333,7 @@ Multimodal └── pyannote.audio Extension / Model -├── MCP Bridge +├── MCP Bridge(stdio 首版已实现) ├── Plugin Command Contribution ├── Plugin Settings Contribution └── Provider Streaming / Tool Calling / Error Mapping 增强 @@ -2353,7 +2355,7 @@ Frontend Extension └── Plugin Settings UI ``` -上述列表描述第二阶段技术范围,不表示能力已经实现。每项功能必须继续经过现有 Service、Contract、Permission 和 Adapter 边界,不因 Demo 需要在 Vue 组件、Router 或 Agent Runtime 中直接绑定第三方协议。 +上述列表描述第二阶段技术范围,其中 stdio MCP Bridge 已实现,其余能力以各自开发说明的状态为准。每项功能必须继续经过现有 Service、Contract、Permission 和 Adapter 边界,不因 Demo 需要在 Vue 组件、Router 或 Agent Runtime 中直接绑定第三方协议。 第三阶段处理: @@ -2409,7 +2411,7 @@ Sync Server 按独立服务开发和部署,不进入桌面客户端核心启 Python AI Core 未来作为 Tauri Sidecar 运行,当前由开发命令独立启动,FastAPI 提供本地接口。Knowledge Core 管理笔记结构;Retrieval Core 当前通过 FTS5、`HashEmbeddingProvider`、sqlite-vec、RRF 和轻量 Reranker 跑通混合检索,真实 Embedding 与正式 Benchmark 在第二阶段接入;Agent Runtime 使用 Tool Registry 操作知识库和任务,并将扩展 Agent Trace Contract 供可视化和 Benchmark 共用;Skill Runtime 将提示词、工具、权限和检索参数组装为可复用 Agent 配置。 -当前 Plugin Runtime 支持 Manifest、生命周期和声明式白名单 Tool Contribution;第二阶段通过 MCP Bridge 接入隔离 Tool,并增加 Command 与 Settings Contribution。Provider Adapter 当前实现 Mock、OpenAI Chat/OpenAI-Compatible 与 Ollama,第二阶段按统一行为测试完善 OpenAI Responses、Anthropic Messages 等协议。多模态目标方案使用 faster-whisper、pyannote.audio 和可选 emotion2vec;当前只读取 Host 预生成 transcript。 +当前 Plugin Runtime 支持 Manifest、生命周期和声明式白名单 Tool Contribution,并已通过 stdio MCP Bridge 接入独立进程 Tool、Host 状态与重启接口;Command 与 Settings Contribution 尚待后续阶段实现。Provider Adapter 当前实现 Mock、OpenAI Chat/OpenAI-Compatible 与 Ollama,第二阶段按统一行为测试完善 OpenAI Responses、Anthropic Messages 等协议。多模态目标方案使用 faster-whisper、pyannote.audio 和可选 emotion2vec;当前只读取 Host 预生成 transcript。 第二阶段内容输出以 Document AST、Exporter Adapter、Mermaid Renderer 和 Function Plot Renderer 为共同边界,支持 HTML、PDF、DOCX 与静态图导出。Theme Package 使用 Manifest、Design Token 和受限 CSS 实现本地导入;联网主题市场不属于本阶段核心依赖。API Key 在 Web 联调期由 Fernet 开发存储加密保存,桌面版迁移到 Tauri Stronghold。多设备同步的目标方案为独立、可自托管的 Sync Server,目前尚未实现;本地核心功能不依赖 Sync Server。 diff --git a/docs/architecture/第二阶段团队分工表.md b/docs/architecture/第二阶段团队分工表.md index 6157b55..7fafabf 100644 --- a/docs/architecture/第二阶段团队分工表.md +++ b/docs/architecture/第二阶段团队分工表.md @@ -746,8 +746,8 @@ Markdown - [ ] faster-whisper 能完成真实音频转写; - [ ] pyannote.audio 能生成说话人分段; - [ ] 两者能组合生成带时间戳和 Speaker 的 Transcript; -- [ ] MCP Server 能通过 MCP Bridge 注册 Tool; -- [ ] Agent 能调用 MCP Tool; +- [x] MCP Server 能通过 MCP Bridge 注册 Tool; +- [x] Agent 能调用 MCP Tool; - [ ] Plugin Command Contribution 后端可注册; - [ ] Plugin Settings Contribution 后端可解析; - [ ] Provider Adapter 的 Streaming / Tool Calling / Error Mapping 稳定; diff --git a/docs/contracts/后端接口契约-开发版.md b/docs/contracts/后端接口契约-开发版.md index bc44e48..e639636 100644 --- a/docs/contracts/后端接口契约-开发版.md +++ b/docs/contracts/后端接口契约-开发版.md @@ -1,6 +1,6 @@ # 后端接口契约(开发版) -> 更新日期:2026-08-31。本文档记录当前前后端联调使用的已实现接口;机器可读字段、校验规则和响应模型以 FastAPI 运行时生成的 OpenAPI 为准。第二阶段尚未实现的规划接口见 `第二阶段接口契约-开发版.md`,不要将规划路径视为当前服务能力。 +> 更新日期:2026-09-01。本文档记录当前前后端联调使用的已实现接口;机器可读字段、校验规则和响应模型以 FastAPI 运行时生成的 OpenAPI 为准。第二阶段尚未实现的规划接口见 `第二阶段接口契约-开发版.md`,不要将规划路径视为当前服务能力。 ## 契约入口 @@ -76,6 +76,8 @@ Web 联调阶段只暴露后端通过 `APP_VAULT_PATH` 配置的单一 Vault, | POST | `/api/plugins/{plugin_id}/enable` | 启用 Plugin | | POST | `/api/plugins/{plugin_id}/disable` | 停用 Plugin | | PUT | `/api/plugins/{plugin_id}/permissions` | 设置 Plugin 已授权权限 | +| GET | `/api/plugins/{plugin_id}/host` | 获取隔离 MCP Host 状态、工具数和协商信息 | +| POST | `/api/plugins/{plugin_id}/host/restart` | 重启 MCP Host 并重新发现、校验和注册 Tool | | DELETE | `/api/plugins/{plugin_id}` | 卸载 Plugin | ### Provider @@ -174,7 +176,7 @@ RunCancelled ## 当前实现状态 -更新至 2026-09-01:后端 81 项回归测试通过。 +更新至 2026-09-01:后端 87 项回归测试通过。 - Chat、Agent Run、Agent Events、Tool 列表、Provider 配置生命周期、模型列表和连接测试已经接入 AI Core。 - Agent Run/Event 已持久化到 SQLite;SSE 帧携带 sequence `id`,断线后可以回放缺失事件。Trace API 与 Benchmark 共用同一事件事实,并在入库前执行 Secret 脱敏和结果限长。 @@ -183,6 +185,7 @@ RunCancelled - Workspace 已接入后端配置的真实 Vault;文件树、笔记读写、文件/目录新建、重命名和删除不再使用前端 Mock Fallback。 - Note Move 保留 `note_id`;Citation 的字符偏移统一使用 UTF-16 code unit,供浏览器编辑器直接定位。 - Plugin 启用前必须通过权限接口记录授权,未知权限默认拒绝。 +- 本地 stdio MCP Server 已通过独立子进程接入 Plugin Runtime;Agent 只消费内部 Tool Contract。Host 支持 initialize、分页发现、调用、超时取消、状态查询、重启和异常退出后的 Tool 注销。 - Attachment Tool 读取 Host 管理的 `attachments` 目录;音频接口读取 Host 生成的转写文本,真实本地语音模型在第二阶段接入。 - 接入业务模块时保持当前路径和 Contract,不在 Router 中直接实现数据库、Provider 或 Agent 逻辑。 diff --git a/docs/contracts/第二阶段接口契约-开发版.md b/docs/contracts/第二阶段接口契约-开发版.md index 58f3da2..7428e42 100644 --- a/docs/contracts/第二阶段接口契约-开发版.md +++ b/docs/contracts/第二阶段接口契约-开发版.md @@ -2,7 +2,7 @@ > 文档状态:接口冻结草案 > -> 更新日期:2026-08-31 +> 更新日期:2026-09-01 > > 依据:`../architecture/第二阶段团队分工表.md`、`../architecture/AI笔记软件技术栈说明-团队版-v2.3.md`、`后端接口契约-开发版.md` @@ -45,8 +45,8 @@ | Transcription | POST | `/api/media/transcriptions/{job_id}/notes` | 计划新增 | 将 Transcript 写入 Knowledge Core | | Agent Trace | GET | `/api/agent/runs/{run_id}/events` | 已实现 | 支持游标恢复并增加模型与权限事件 | | Agent Trace | GET | `/api/agent/runs/{run_id}/trace` | 已实现 | 分页读取可回放 Trace 快照 | -| Plugin Host | GET | `/api/plugins/{plugin_id}/host` | 计划新增 | 获取 MCP Host 健康状态 | -| Plugin Host | POST | `/api/plugins/{plugin_id}/host/restart` | 计划新增 | 重启异常 Host 并重新发现 Tool | +| Plugin Host | GET | `/api/plugins/{plugin_id}/host` | 已实现 | 获取 MCP Host 健康状态 | +| Plugin Host | POST | `/api/plugins/{plugin_id}/host/restart` | 已实现 | 重启异常 Host 并重新发现 Tool | | Plugin Command | GET | `/api/plugin-contributions/commands` | 计划新增 | 获取前端可展示的 Command | | Plugin Command | POST | `/api/plugin-contributions/commands/{command_id}/execute` | 计划新增 | 受控执行 Command | | Plugin Settings | GET | `/api/plugins/{plugin_id}/settings` | 计划新增 | 获取 Schema 与非敏感配置 | @@ -427,7 +427,29 @@ class McpBridge(Protocol): async def stop(self, plugin_id: str) -> None: ... ``` -首个实现支持本地 `stdio`。Host 负责 initialize、capability negotiation、进程生命周期、超时、取消、stderr 隔离和异常退出后的 Tool 注销。 +首个实现已支持本地 `stdio`,按 MCP `2025-11-25` 发起 initialize,并兼容 `2025-06-18`、`2025-03-26` 和 `2024-11-05` 协商结果。Host 负责 capability negotiation、分页 `tools/list`、进程生命周期、超时取消、stderr 隔离和异常退出后的 Tool 注销。stdio 消息使用 UTF-8 单行 JSON-RPC;当前不实现 Streamable HTTP。 + +MCP Plugin 的 `backend` 增加: + +```yaml +backend: + type: mcp + transport: stdio + command: python + args: [server.py] + startup_timeout_seconds: 5 + tool_timeout_seconds: 30 +``` + +命令通过参数数组直接启动,不经过 Shell。带路径的 executable 必须位于 Plugin 包内;PATH 中的命令可以按名称引用。子进程只继承运行所需的系统环境变量,不继承 `OPENAI_API_KEY`、`APP_DB_PATH`、Vault 路径等宿主状态。Secret 注入留给阶段 D 的专用引用接口。 + +远端 Tool 的可选项目权限放在 MCP `_meta`: + +```json +{ "_meta": { "notesagent/permission": "notes.read" } } +``` + +该权限必须属于项目已知权限并同时出现在 Plugin Manifest 中。发现结果必须与 `contributes.tools` 的命名空间 ID 完全一致;校验全部成功后才一次性发布到 Tool Registry。 当前 Web 开发接口 `POST /api/plugins/install` 使用 `package_path`。桌面 Host 接入后,`ExtensionInstallRequest` 增加 `package_id`,由文件选择器产生临时包句柄;`package_path` 只在明确的 development 环境保留并标记 deprecated,生产构建拒绝任意前端路径。 @@ -460,6 +482,8 @@ error `POST /api/plugins/{plugin_id}/host/restart` 返回 `202 OperationResponse`。重启期间先注销旧 Tool,发现和校验全部成功后再一次性发布新 Tool 集合,避免半注册状态。 +当前实现还返回协商后的 `protocol_version`、`server_name` 和 `server_version`。单条协议消息上限为 2 MiB,单次 Tool Result 上限为 256 KiB;超限分别按 Host/Result 错误处理。Server 异常退出或发送无效 stdout 消息时,Host 进入 `unhealthy`,Plugin 进入 `error`,相关 Tool 立即注销。 + ### 7.3 Command Contribution 列表 `GET /api/plugin-contributions/commands?location=command_palette` diff --git a/docs/development/AI-Core与Agent-Core开发说明.md b/docs/development/AI-Core与Agent-Core开发说明.md index a3b9731..e3cf687 100644 --- a/docs/development/AI-Core与Agent-Core开发说明.md +++ b/docs/development/AI-Core与Agent-Core开发说明.md @@ -2,7 +2,7 @@ > 本文档用于团队开发和模块联调,记录当前已经落地的核心边界与使用方式。 -> 更新日期:2026-09-01。第一阶段 AI Core、Agent Core、Extension Core 和 Model Core 主链路已经完成;第二阶段 Agent Trace 持久化和可恢复 SSE 已落地,后端当前回归基线为 81 项测试通过。 +> 更新日期:2026-09-01。第一阶段 AI Core、Agent Core、Extension Core 和 Model Core 主链路已经完成;第二阶段 Agent Trace 持久化、可恢复 SSE、stdio MCP Bridge 与隔离 Plugin Host 已落地,后端当前回归基线为 87 项测试通过。 ## 当前实现 @@ -33,12 +33,14 @@ backend/app/ │ ├── permissions.py 权限策略、确认请求和会话授权 │ └── builtin_tools.py 无副作用的内置开发 Tool ├── extensions/ -│ └── runtime.py Skill/Plugin Manifest、生命周期、依赖与 Tool Contribution +│ ├── runtime.py Skill/Plugin Manifest、生命周期、依赖与 Tool Contribution +│ └── mcp.py stdio JSON-RPC、MCP 生命周期、发现、调用与 Host 隔离 └── container.py AI Core 依赖组装 backend/extensions/ ├── skills/knowledge-assistant/ 内置知识库 Skill -└── plugins/text-tools/ 内置示例 Plugin +├── plugins/text-tools/ 内置声明式 Plugin +└── fixtures/mcp-echo/ 离线 MCP Server 联调 Fixture ``` Router 只负责 HTTP/SSE 与错误转换,不实现 Agent、Tool 或 Provider 业务逻辑。 @@ -57,6 +59,7 @@ Router 只负责 HTTP/SSE 与错误转换,不实现 Agent、Tool 或 Provider - SQLite Trace、分页快照与可恢复 SSE; - Skill Manifest、Prompt、Tool/Permission/模型能力解析; - Plugin Manifest、生命周期和 Tool Contribution; +- stdio MCP Bridge、隔离进程生命周期、Tool 映射与 Host 健康状态; - Skill 调用内置 Tool 与 Plugin Tool; - 公共 Contract 和 API 接入。 @@ -65,7 +68,7 @@ Router 只负责 HTTP/SSE 与错误转换,不实现 Agent、Tool 或 Provider - Note、NoteBlock、Markdown Parser:由 Knowledge Core 提供; - FTS5、Vector、RRF、Reranker、Citation:由 Retrieval Core 提供; - 文件系统和 API Key 明文读取:由 Rust Host 提供; -- MCP Plugin Host、Frontend Extension Slot:按技术基线放在第二阶段实现。 +- Frontend Extension Slot 与 Plugin Command/Settings:按第二阶段后续阶段实现。 ## Provider @@ -302,7 +305,7 @@ DELETE /api/skills/{skill_id} ### Plugin Runtime -第一阶段 Plugin Runtime 完成 Manifest 校验、安装、启用、停用、卸载和 Tool Contribution。第三方代码不会直接 import 到 AI Core;当前 Declarative Plugin Host 只执行宿主实现的白名单 handler,MCP Host 留到第二阶段。 +第一阶段 Plugin Runtime 完成 Manifest 校验、安装、启用、停用、卸载和声明式 Tool Contribution。阶段 C 增加 stdio MCP Bridge:第三方代码不会直接 import 到 AI Core,而由独立子进程运行,通过换行分隔 JSON-RPC 完成 initialize、Tool 发现和调用。 启用 Plugin 时将 Tool 注册到统一 Tool Registry,并标记 `source=plugin`;停用或异常时注销 Tool。启用中的 Skill 依赖某 Plugin Tool 时,Plugin 不能直接卸载。 @@ -315,11 +318,15 @@ GET /api/plugins/{plugin_id} POST /api/plugins/{plugin_id}/enable POST /api/plugins/{plugin_id}/disable PUT /api/plugins/{plugin_id}/permissions +GET /api/plugins/{plugin_id}/host +POST /api/plugins/{plugin_id}/host/restart DELETE /api/plugins/{plugin_id} ``` Plugin Manifest 中的权限只是声明,不代表已经授权。带权限的 Plugin 安装后进入 `permission_required`,Host 必须通过权限接口记录用户授权,之后才能启用。JSON Schema 在安装阶段校验,Tool 调用时再次校验实际参数。 +MCP Tool 进入 Registry 前统一增加 `.` 命名空间。Server 声明的 `notesagent/permission` 必须属于已知权限并出现在 Plugin Manifest;发现集合还必须与 Manifest Contribution 完全一致。启用失败会回滚全部 Tool 并关闭子进程,异常退出会把 Plugin 标记为 `error` 并立即注销对应 Tool。详细实现和 Fixture 操作见 [MCP Bridge 与 Plugin Host 开发说明](MCP-Bridge与Plugin-Host开发说明.md)。 + 内置示例 `text-tools` 注册 `text.uppercase`。内置 `knowledge-assistant` Skill 同时声明 `notes.search` 和 `text.uppercase`,用于验证完整链路: ```text @@ -342,4 +349,4 @@ Skill Manifest - Task 已持久化到 SQLite;Attachment Tool 读取 Host 管理目录中的 UTF-8 文件。 - `audio.transcribe` 当前消费 Host 预生成的 transcript;faster-whisper 与说话人分离仍按技术基线在第二阶段接入。 - Extension 安装记录暂存内存;后续接入持久化 Registry 与版本升级流程。 -- 当前 Plugin Host 只支持内置声明式白名单 handler;MCP Bridge、独立进程健康检查与 UI Contribution 在第二阶段实现。 +- 当前 Plugin Host 支持内置声明式 handler 和本地 stdio MCP Server;Streamable HTTP、OS 级沙箱、Plugin Command/Settings 与 UI Contribution 留在后续阶段。 diff --git a/docs/development/Knowledge与Retrieval-Core开发说明.md b/docs/development/Knowledge与Retrieval-Core开发说明.md index c109a9e..2fcd38c 100644 --- a/docs/development/Knowledge与Retrieval-Core开发说明.md +++ b/docs/development/Knowledge与Retrieval-Core开发说明.md @@ -3,7 +3,7 @@ > 本文档用于团队开发和模块联调,记录 Knowledge Core / Retrieval Core 已经落地的 > 模块边界、数据模型、接口与使用方式,对应分工表中的杨星萱。 -> 更新日期:2026-09-01。第一阶段 Knowledge/Retrieval 主链路已经完成,并已接入 Agent Tool Registry;完整后端回归基线为 81 项测试通过。 +> 更新日期:2026-09-01。第一阶段 Knowledge/Retrieval 主链路已经完成,并已接入 Agent Tool Registry;完整后端回归基线为 87 项测试通过。 ## 当前实现 diff --git a/docs/development/MCP-Bridge与Plugin-Host开发说明.md b/docs/development/MCP-Bridge与Plugin-Host开发说明.md new file mode 100644 index 0000000..61bb74b --- /dev/null +++ b/docs/development/MCP-Bridge与Plugin-Host开发说明.md @@ -0,0 +1,262 @@ +# MCP Bridge 与 Plugin Host 开发说明 + +> 更新日期:2026-09-01。本文记录第二阶段阶段 C 已实现的本地 stdio MCP Bridge、隔离 Plugin Host、Tool Contract 转换和离线测试方式。Plugin Command 与 Settings 属于阶段 D,不在本文实现范围内。 + +## 1. 目标与实现状态 + +阶段 C 的目标是让外部 MCP Server 进入既有 Plugin、Tool、Permission、Agent 和 Trace 链路,同时避免 Agent Runtime、前端或 Benchmark 直接依赖 MCP 原始消息。 + +当前链路: + +```text +Plugin Manifest +→ Plugin Runtime +→ 独立 stdio MCP Server 进程 +→ initialize / capability negotiation +→ tools/list 分页发现与校验 +→ NotesAgent ToolDefinition +→ Tool Registry / Permission Manager +→ Agent Runtime / Agent Trace +``` + +已经实现: + +- 本地 stdio 子进程启动、关闭和异常退出检测; +- UTF-8、换行分隔的 JSON-RPC 2.0 消息; +- initialize、协议版本与 tools capability 协商; +- `notifications/initialized`; +- 分页 `tools/list`; +- `tools/call`、业务错误与 JSON-RPC 错误转换; +- 超时和 `notifications/cancelled`; +- Tool 命名空间、JSON Schema、权限和 Manifest 集合校验; +- Host 状态查询、重启和异常后的 Tool 自动注销; +- stderr 隔离、环境变量裁剪、消息及结果大小限制; +- 无网络、无密钥的确定性 MCP Fixture。 + +实现依据为 MCP 官方 [Lifecycle 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle)、[Transports 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports) 和 [Tools 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)。 + +## 2. 代码位置 + +```text +backend/app/extensions/mcp.py + stdio 进程、JSON-RPC、MCP 生命周期、发现、调用和 Host 状态 + +backend/app/extensions/runtime.py + Plugin Manifest、权限、MCP Tool 批量注册/回滚和生命周期集成 + +backend/app/agent/tools.py + 内部 Tool 参数校验、结构化执行错误和线程安全 Registry + +backend/extensions/fixtures/mcp-echo/ + 确定性 stdio MCP Server 与 Plugin Manifest +``` + +## 3. Plugin Manifest + +MCP Plugin 的后端配置示例: + +```yaml +id: example-mcp +name: Example MCP +version: 1.0.0 +permissions: + - notes.read +contributes: + tools: + - example-mcp.search +backend: + type: mcp + transport: stdio + command: python + args: [server.py] + startup_timeout_seconds: 5 + tool_timeout_seconds: 30 +``` + +约束: + +- 阶段 C 只接受 `type: mcp` 与 `transport: stdio`; +- 命令和参数通过数组直接传给 `subprocess.Popen`,不经过 Shell; +- PATH 中的 executable 使用名称,例如 `python`、`node`; +- manifest 中带目录的 executable 必须解析到 Plugin 包内部; +- `contributes.tools` 使用 `.`; +- 安装阶段只读 Manifest,不启动第三方进程; +- 完成用户授权后,`enable` 才启动 Host。 + +## 4. 生命周期 + +### 4.1 启动 + +启用 MCP Plugin 时依次执行: + +1. 检查 Plugin 声明权限是否全部获得授权; +2. 检查 Manifest 声明的 Tool ID 是否与现有 Registry 冲突; +3. 启动独立 stdio Server; +4. 发送 `initialize`; +5. 校验协商版本和 `tools` capability; +6. 发送 `notifications/initialized`; +7. 分页读取 `tools/list`; +8. 校验全部 Tool; +9. 确认发现集合与 Manifest 完全一致; +10. 将完整集合注册到 Tool Registry; +11. Plugin 和 Host 进入 `ready`。 + +任何步骤失败都会注销本轮已注册 Tool、关闭子进程并把 Plugin 标记为 `error`,不会留下半启用状态。 + +### 4.2 停止与异常退出 + +停用、卸载或应用关闭时,先注销 Tool,再关闭 stdin,等待 Server 正常退出。超时后依次 terminate 和 kill。 + +Server 异常退出、stdout 出现非 JSON-RPC 内容或发送超大协议消息时: + +- 未完成请求返回 `PLUGIN_HOST_UNAVAILABLE`; +- Host 进入 `unhealthy`; +- Plugin 进入 `error`; +- 对应 Tool 从 Registry 中立即注销; +- 用户可以调用 Host Restart 接口重新协商和发现。 + +Server 发送 `notifications/tools/list_changed` 时不会直接信任新集合。当前实现先把 Host 标记为不健康并注销旧 Tool,要求通过 Restart 重新执行完整发现与校验。 + +## 5. Tool Contract 转换 + +MCP Tool: + +```json +{ + "name": "search", + "description": "Search notes", + "inputSchema": { "type": "object", "properties": {} }, + "_meta": { "notesagent/permission": "notes.read" } +} +``` + +进入系统后转换为: + +```json +{ + "name": "example-mcp.search", + "description": "Search notes", + "parameters": { "type": "object", "properties": {} }, + "permission": "notes.read", + "source": "plugin" +} +``` + +转换规则: + +- 远端名称必须能转换为合法且稳定的项目 Tool ID; +- `inputSchema` 必须是有效的 object JSON Schema; +- `_meta.notesagent/permission` 必须属于项目已知权限; +- Tool 权限必须同时出现在 Plugin Manifest 中; +- Agent 仍通过 Tool Registry 执行参数校验、Permission、超时和 Trace; +- MCP `structuredContent` 存在时映射为内部 output;否则保留为受控 `content` 数组; +- MCP `isError: true` 映射为 `MCP_TOOL_CALL_FAILED`; +- 结果超过 256 KiB 映射为 `MCP_TOOL_RESULT_TOO_LARGE`。 + +## 6. 隔离与安全边界 + +当前隔离是“独立进程 + 协议边界”,不是完整的操作系统沙箱。 + +已经执行的保护: + +- 第三方模块不 import 到 AI Core; +- 子进程 `cwd` 固定为 Plugin 包目录; +- 不使用 Shell 拼接命令; +- 不把 Provider API Key、`APP_DB_PATH`、Vault 路径和其他宿主环境变量传入子进程; +- stderr 与 JSON-RPC stdout 分离,stderr 不进入 API 和 Agent Trace; +- stdout 只能发送合法 MCP JSON-RPC; +- 单条协议消息上限 2 MiB; +- 单次 Tool Result 上限 256 KiB; +- MCP Tool 不绕过 Permission Manager 和 Agent Tool Timeout。 + +当前尚未提供容器、受限系统账户、seccomp、Windows AppContainer 或 macOS Sandbox,因此 Plugin 进程仍具有当前操作系统用户授予的一般文件访问能力。正式社区插件分发前必须继续增加包签名、来源验证和平台级沙箱;不得把当前进程隔离描述为完全安全执行任意不可信代码。 + +## 7. Host API + +```http +GET /api/plugins/{plugin_id}/host +POST /api/plugins/{plugin_id}/host/restart +``` + +状态响应包含: + +```text +plugin_id +backend_type / transport +status +tools_count +started_at / last_seen_at +protocol_version +server_name / server_version +error +``` + +状态值: + +```text +stopped +starting +ready +unhealthy +error +``` + +Restart 返回 `202 OperationResponse`。接口返回前已完成本地 Host 重启和 Tool 重新发现;`message` 中给出最终 Host 状态。 + +## 8. 离线 Fixture + +Fixture 位于: + +```text +backend/extensions/fixtures/mcp-echo +``` + +它提供: + +- `mcp-fixture.echo`:返回 structuredContent; +- `mcp-fixture.fail`:返回 `isError: true`; +- `mcp-fixture.sleep`:验证超时和取消; +- `mcp-fixture.large`:验证结果大小上限; +- `mcp-fixture.environment`:验证宿主 Secret/路径没有进入子进程; +- `mcp-fixture.exit`:验证异常退出、Tool 注销和 Restart。 + +Fixture 的 `tools/list` 使用两页响应,用于覆盖分页发现。测试还会启动缺少 tools capability 和返回无效 Schema 的变体。 + +## 9. 验证 + +```powershell +cd backend +uv run python -m compileall -q app +uv run pytest + +cd ../frontend +pnpm test +pnpm type-check +pnpm build +``` + +阶段 C 新增测试覆盖: + +- initialize、版本和 capability negotiation; +- 分页 `tools/list` 与命名空间映射; +- Permission、JSON Schema 与 Contribution 集合; +- Tool 成功、业务错误、结果过大和超时; +- Agent Runtime 调用 MCP Tool 并写入正式 Trace; +- Secret/Vault 环境隔离; +- Server 异常退出、Tool 注销和 Host Restart; +- 缺少 capability 与无效 MCP Schema; +- OpenAPI 发布 Host 状态和重启路径。 + +## 10. 当前边界与后续阶段 + +阶段 C 不包含: + +- Streamable HTTP MCP transport; +- Resources、Prompts、Sampling、Elicitation 和 MCP Tasks; +- Plugin Command 与 Settings Contribution; +- Secret Reference 注入; +- Plugin Registry 持久化、签名与社区来源校验; +- 操作系统级沙箱; +- Tool 列表热更新的无中断替换。 + +阶段 D 将在当前 Plugin Runtime 上继续增加 Command、Settings、Secret Contract 和命名空间 Storage,不修改 Agent 使用内部 Tool Contract 的原则。 diff --git a/docs/development/前端壳子与接口层开发说明.md b/docs/development/前端壳子与接口层开发说明.md index 83a76c6..de7fc1a 100644 --- a/docs/development/前端壳子与接口层开发说明.md +++ b/docs/development/前端壳子与接口层开发说明.md @@ -187,12 +187,12 @@ pnpm build ```text pnpm build passed pnpm test 27 passed -uv run pytest 81 passed +uv run pytest 87 passed preview smoke HTTP 200 git diff --check passed ``` -当前前端使用 Vitest 执行 Store、Workspace API Adapter、SSE 恢复游标、文件树、编辑器组件、智能体标签、轻量动效约束、Markdown 对比度 Token、scoped CSS 选择器约束和 Shiki GitHub 双主题测试;`pnpm build` 同时执行 `vue-tsc -b` 与 Vite 生产构建。后端测试出现过 `.pytest_cache` 无法写入的 Windows 权限警告,不影响 81 项测试结果,也不涉及产品代码。 +当前前端使用 Vitest 执行 Store、Workspace API Adapter、SSE 恢复游标、文件树、编辑器组件、智能体标签、轻量动效约束、Markdown 对比度 Token、scoped CSS 选择器约束和 Shiki GitHub 双主题测试;`pnpm build` 同时执行 `vue-tsc -b` 与 Vite 生产构建。后端测试出现过 `.pytest_cache` 无法写入的 Windows 权限警告,不影响 87 项测试结果,也不涉及产品代码。 Vite 当前会提示 Chat 与 Workspace 的部分异步 Chunk 超过 500 kB,这是 Milkdown、CodeMirror、KaTeX 和 Shiki 等编辑/渲染依赖带来的性能优化项,不影响构建成功或功能正确性;进入桌面打包前应通过手动分包或更细粒度动态加载继续优化。 diff --git a/docs/development/模型提供商与模型发现开发说明.md b/docs/development/模型提供商与模型发现开发说明.md index 5a6fa20..0d72d9a 100644 --- a/docs/development/模型提供商与模型发现开发说明.md +++ b/docs/development/模型提供商与模型发现开发说明.md @@ -104,4 +104,4 @@ pnpm build 自动化验证覆盖 Provider 预设、OpenAI-Compatible `/models` 请求与鉴权头、模型映射、前端自动刷新、排序去重及按 Provider 隔离错误。生产构建同时执行 Vue 和 TypeScript 类型检查。 -当前完整回归基线:后端 81 项测试、前端 27 项测试通过,前端类型检查和生产构建通过。Provider 配置目前仍保存在内存 Registry,AI Core 重启后需要重新创建;凭据密文会保留。OpenAI Responses 与 Anthropic Messages Adapter 尚未实现,设置页正式预设不会使用这两种协议。 +当前完整回归基线:后端 87 项测试、前端 27 项测试通过,前端类型检查和生产构建通过。Provider 配置目前仍保存在内存 Registry,AI Core 重启后需要重新创建;凭据密文会保留。OpenAI Responses 与 Anthropic Messages Adapter 尚未实现,设置页正式预设不会使用这两种协议。 diff --git a/docs/retrospectives/后端全面审阅问题与修复复盘.md b/docs/retrospectives/后端全面审阅问题与修复复盘.md index fc08ea6..401fa16 100644 --- a/docs/retrospectives/后端全面审阅问题与修复复盘.md +++ b/docs/retrospectives/后端全面审阅问题与修复复盘.md @@ -4,7 +4,7 @@ > 审阅范围:FastAPI、Knowledge / Retrieval Core、Agent Core、Extension Core、Provider Adapter、公共接口和后端开发文档。 > 文档用途:记录问题形成原因、实际影响、修复判断和落地方案,供后续开发文档、比赛材料与技术博客使用。 -> 2026-09-01 状态补充:本文记录的缺陷均保持修复。此后又加入 Provider 预设、模型发现、DeepSeek/OpenAI 凭据解析、Fernet 加密存储和 Agent Trace 持久化,当前完整后端回归基线为 81 项测试通过。 +> 2026-09-01 状态补充:本文记录的缺陷均保持修复。此后又加入 Provider 预设、模型发现、DeepSeek/OpenAI 凭据解析、Fernet 加密存储、Agent Trace 持久化和 stdio MCP Plugin Host,当前完整后端回归基线为 87 项测试通过。 ## 1. 审阅结论