Anybox 当前插件系统设计结构说明
本文档根据当前仓库代码整理,说明插件包的文件结构、插件清单格式、agent 侧插件管理逻辑、desktop 侧 IPC/UI 连接方式,以及插件在安装后如何进入 MCP、技能和项目会话运行链路。
1. 总体定位
当前插件系统的核心并不在 Electron renderer 内,而是在 packages/anyboxagent 中实现。插件被设计成一类“能力包”,一个插件包可以声明三类能力:
- MCP server:插件安装后会生成一个或多个全局 MCP server 配置,供项目会话按选择加载。
- Skill:插件可以携带
SKILL.md工作流说明,安装并在项目中选中插件后,这些技能会进入技能发现范围。 - App connector:插件可以声明需要 API key 的远程 MCP 连接器,密钥由认证存储管理,运行时再解析到远程请求头或授权字段。
2. 插件包文件结构
插件包的约定入口是 .anybox-plugin/plugin.json。运行时只扫描已下载安装到本机数据目录的插件包:
<agent-data>/plugins/installed/<plugin-id>/<version>/.anybox-plugin/plugin.json
系统也支持非版本化目录:
<agent-data>/plugins/installed/<plugin-id>/.anybox-plugin/plugin.json
版本化目录和非版本化目录都会被扫描。同一个搜索根内如果出现多个同名插件,系统会按 manifest 的 version 选择较新的版本。
推荐目录形态
<plugin-id>/
<version>/
.anybox-plugin/
plugin.json
skills/
<skill-directory>/
SKILL.md
references/
scripts/
assets/
assets/
app-icon.png
composer-icon.svg
server.js
package.json
| 路径 | 作用 |
|---|---|
.anybox-plugin/plugin.json |
插件清单。声明插件元信息、MCP server、技能目录、App connector、权限说明和运行时模板。 |
skills/<skill>/SKILL.md |
插件内置技能。系统会读取 frontmatter 中的 name、description,生成 plugin:<plugin-id>:<skill-directory> 形式的技能 ID。 |
skills/<skill>/references |
技能附加资料。不会被自动全量加载,只有技能说明要求读取时才通过技能资源工具访问。 |
assets |
界面图标、截图或技能资源。manifest 的 interface.logo、composerIcon 可引用这里的资源。 |
server.js 或其他运行文件 |
stdio MCP 插件可把命令、参数、环境变量写在 manifest 的 runtime 中,由安装逻辑生成 MCP 配置。 |
内置插件策略
plugins/installed 数据目录后,agent 才会扫描和启用。
3. plugin.json 设计结构
manifest 由 Zod schema 校验,文件必须是严格 JSON。核心字段如下:
| 字段 | 类型 | 用途 |
|---|---|---|
name |
string | 插件 ID 的来源。系统会 trim 并转小写作为 pluginID。 |
version |
string | 版本选择和安装记录使用。版本化包中同名插件按此字段比较。 |
description |
string | 默认描述。若 interface.shortDescription 存在,目录展示优先使用后者。 |
author |
string 或 object | 发布者信息。object 支持 name、email、url。 |
homepage、repository、license、keywords |
可选 | 用于目录展示、文档链接和元信息。 |
interface |
object | 桌面插件页展示信息,包括名称、短描述、长描述、分类、图标、品牌色、默认提示等。 |
mcpServers |
array | 声明一个或多个 MCP server 模板。安装后转换为全局 MCP server 配置。 |
skills |
string 或 string[] | 技能根目录声明。不写时默认扫描 skills。 |
apps |
array | 声明 App connector。安装后生成远程 MCP server 绑定,API key 单独保存。 |
commands、agents |
string 或 string[] | 已纳入 schema,但当前核心安装链路主要消费 MCP、skills、apps。 |
interface 字段
interface 用于桌面端目录展示,不直接决定运行时行为。常用字段包括:
displayName:插件页展示名称。shortDescription、longDescription:列表和详情描述。developerName:发布者展示名称。category:目录分类,系统归一化到Code、Browser、Git、Database、Docs、Automation、Design。capabilities、websiteURL、privacyPolicyURL、termsOfServiceURL:供界面展示或后续扩展使用。composerIcon、logo、screenshots、brandColor:视觉素材字段。
mcpServers 字段
每个 MCP server 声明会被归一化为 PluginMcpServerCatalogEntry:
{
"id": "notes",
"name": "Manifest Notes",
"description": "Optional detail",
"risk": "low",
"permissions": ["Starts a stdio MCP server"],
"tools": [
{
"name": "list_notes",
"title": "List Notes",
"description": "List notes.",
"readOnly": true
}
],
"configFields": [
{
"key": "ROOT_PATH",
"label": "Root path",
"type": "path",
"required": true,
"defaultValue": "~"
}
],
"runtime": {
"transport": "stdio",
"command": "node",
"args": ["server.js"],
"timeoutMs": 30000
},
"installReview": ["Review text shown before install."]
}
id 可省略。省略时系统使用 default,生成的 MCP server ID 为 plugin.<plugin-id>;如果有显式 ID,例如 notes,则生成 plugin.<plugin-id>.notes。
runtime 字段
stdio runtime
transport: "stdio"command:启动命令。args:命令参数,可使用${CONFIG_KEY}占位符。env:进程环境变量,也可使用占位符。cwd、timeoutMs、toolPolicies:可选运行配置。
remote runtime
transport: "remote"serverUrl或connectorId至少一个可解析。authorization、headers:远程请求认证信息。allowedTools、requireApproval:控制工具暴露和审批策略。provider当前 schema 支持openai。
apps 字段
App connector 用于“需要用户保存 API key 才能连接”的远程 MCP。它声明 credential 字段,安装插件时生成一个远程 MCP server,但不会把 API key 写入 MCP 配置。
{
"appID": "docs",
"name": "Docs API",
"credential": {
"key": "DOCS_API_KEY",
"label": "Docs API key",
"type": "password",
"required": true,
"secret": true
},
"runtime": {
"transport": "remote",
"serverUrl": "https://docs.example.test/mcp",
"headers": {
"x-api-key": "${DOCS_API_KEY}"
},
"allowedTools": {
"readOnly": true
},
"requireApproval": "always"
}
}
对应生成的 connector ID 为 plugin-app:<plugin-id>:<appID>,MCP server ID 为 plugin.<plugin-id>.app.<appID>。
4. 插件系统在项目中的实现
4.1 agent 侧是插件系统的主体
packages/anyboxagent/src/plugin/plugin.ts 是插件系统的主体文件,承担以下职责:
- 定义 manifest、catalog、installed record、connector status 等 Zod schema。
- 扫描插件包目录,读取并校验
.anybox-plugin/plugin.json。 - 把原始 manifest 归一化成 UI 和 API 可消费的
PluginCatalogItem。 - 安装、更新、删除插件,并同步生成或删除 MCP server 配置。
- 保存和删除 App connector API key,并在远程 MCP 连接时解析真实认证信息。
- 列出已安装插件技能根目录,供技能系统发现插件技能。
4.2 插件目录发现
插件扫描入口只使用下载安装到本机数据目录的插件包搜索根:
ANYBOX_PLUGIN_INSTALL_DIR:测试或显式配置时使用的插件安装目录。<agent-data>/plugins/installed:默认插件安装目录。
搜索根下会扫描一级插件目录,并同时检查非版本化 manifest 与子目录版本化 manifest。同名插件按 manifest 的 version 选择最新版本。
4.3 目录归一化
normalizeCatalogItem 会把 manifest 转换成统一的目录项:
id:由manifest.name归一化而来。name:优先使用interface.displayName。publisher:优先使用interface.developerName,否则使用 author。category:把Coding、Engineering映射为Code,把Documentation、Productivity映射为Docs。risk:从 MCP server、App connector、skills 推导最高风险,skills-only 插件按 low 参与计算。permissions、tools、configFields:从所有 MCP server 和 App connector 汇总。skills:扫描技能目录并生成技能预览。
4.4 安装记录
已安装插件存储在 SQLite 表 installed_plugins 中,主键是 pluginID。记录结构包括:
| 字段 | 含义 |
|---|---|
pluginID、version |
安装的插件 ID 与当前 catalog 版本。 |
enabled |
插件整体启用状态。同步到所有由插件生成的 MCP server。 |
mcpServerID、mcpServerIDs |
兼容旧字段和当前多 server 列表。由 manifest 的 MCP server 与 App connector 生成。 |
skillIDs |
安装时快照出的插件技能 ID,例如 plugin:my-plugin:review。 |
connectorIDs |
App connector 的认证存储 ID,例如 plugin-app:manifest-lab:docs。 |
config |
插件配置值。用于替换 runtime 中的 ${CONFIG_KEY} 占位符。 |
installedAt、updatedAt |
安装与更新时间戳。 |
lastDiagnostic、lastConnectorDiagnostics |
最近一次 MCP 诊断结果。 |
4.5 安装流程
- 前端调用 desktop IPC
desktop:install-plugin。 - 主进程转发到 agent API:
PUT /api/plugins/installed/:pluginID。 - agent 调用
Plugin.install(pluginID, input)。 - 系统查找 catalog 插件;如果插件不存在返回
PLUGIN_NOT_FOUND,如果风险为critical则拒绝安装。 - 系统校验和归一化配置:必填字段必须有值;没有显式值时使用
defaultValue;其他额外配置会保留。 - 生成
mcpServerIDs、skillIDs、connectorIDs。 - 写入
installed_plugins表。 - 调用
Config.setMcpServer(GLOBAL_CONFIG_ID, serverID, runtimeBinding),把插件能力写成全局 MCP server 配置。
4.6 MCP runtime 绑定
插件安装后不会直接运行 MCP server,而是生成全局 MCP 配置。会话真正需要工具时,MCP manager 通过 Config.resolveProjectMcpServers(projectID) 找到当前项目可用 server,并按 server 配置创建 transport。
stdio runtime 会生成 command、args、env、cwd 等字段。生成时会使用安装记录中的 config 替换 ${CONFIG_KEY} 占位符。
remote runtime 会生成 serverUrl、authorization、headers、allowedTools、requireApproval 等字段。普通 remote MCP 可以直接写 serverUrl;App connector remote MCP 则先写入 connectorId,实际认证信息运行时再解析。
4.7 App connector 密钥处理
App connector 的 API key 不写入全局 MCP 配置。保存 API key 时,agent 调用认证模块写入 provider credential,connector ID 形如 plugin-app:<plugin-id>:<appID>。
MCP client 创建 remote transport 时,如果发现 server 配置里有 connectorId,会动态导入插件模块并调用 resolveConnectorRemoteServer(connectorId)。该函数会:
- 解析 connector ID,找到插件和 app 声明。
- 确认插件已安装且启用。
- 从认证存储读取激活的 API key。
- 把 API key 合并到临时配置对象中。
- 替换 app runtime 的
serverUrl、authorization、headers占位符。
这样全局 MCP 配置只包含 connectorId,不会持久化真实密钥;真实密钥只在建立远程 MCP transport 时进入请求配置。
5. Desktop 侧连接方式
5.1 主进程 IPC
Electron 主进程在 packages/desktop/src/main/ipc.ts 注册插件相关 IPC。它们本质上是 agent API 的薄封装:
| Desktop IPC | Agent API | 作用 |
|---|---|---|
desktop:get-plugin-catalog |
GET /api/plugins/catalog |
读取插件目录。 |
desktop:get-installed-plugins |
GET /api/plugins/installed |
读取已安装插件。 |
desktop:install-plugin |
PUT /api/plugins/installed/:pluginID |
安装插件并写入 MCP 绑定。 |
desktop:update-installed-plugin |
PATCH /api/plugins/installed/:pluginID |
保存配置或启停插件。 |
desktop:delete-installed-plugin |
DELETE /api/plugins/installed/:pluginID |
删除安装记录、MCP 绑定和 connector credential。 |
desktop:get-installed-plugin-diagnostic |
GET /api/plugins/installed/:pluginID/diagnostic |
诊断插件主 MCP server。 |
desktop:get-installed-plugin-connectors |
GET /api/plugins/installed/:pluginID/connectors |
读取 App connector 连接状态。 |
desktop:save-installed-plugin-connector-api-key |
PUT /api/plugins/installed/:pluginID/connectors/:appID/api-key |
保存 App connector API key。 |
5.2 Renderer 插件管理页
Renderer 的状态管理主要在 packages/desktop/src/renderer/src/app/use-settings-page.ts,展示组件在 packages/desktop/src/renderer/src/app/plugins/PluginsPage.tsx。
loadPlugins同时读取 catalog 和 installed 列表,并为已安装插件加载 connector 状态。installPlugin使用当前 draft config 安装插件,然后刷新插件列表和 MCP 能力。updateInstalledPlugin保存配置或启停插件。deleteInstalledPlugin删除插件并刷新相关诊断与 connector 状态。saveInstalledPluginConnectorApiKey保存或清空 app connector API key。
PluginsPage 负责目录过滤、详情展示、风险标签、工具预览、MCP bindings、安装审查、配置表单和 connector 表单。界面层不会自己解释 manifest,而是消费 agent 返回的 PluginCatalogItem 和 InstalledPlugin。
6. 项目级启用与会话运行
插件安装是全局行为,项目级选择决定某个项目会话中哪些插件 MCP server 和插件技能可用。
6.1 项目插件选择
agent 项目 API 提供:
GET /api/projects/:id/plugins:返回所有已启用的已安装插件。GET /api/projects/:id/plugins/selection:返回当前项目选中的插件 ID,且会过滤掉未安装或未启用的插件。PUT /api/projects/:id/plugins/selection:保存项目选中的插件 ID。
desktop renderer 中的 use-project-composer.ts 会读取这些接口,把插件显示为 composer 顶部菜单里的可选项,并在用户切换时调用 updateProjectPluginSelection。
6.2 MCP server 解析
项目 MCP server 解析由 Config.resolveProjectMcpServers(projectID) 完成。它会读取项目配置中的 selected_plugins,把每个插件 ID 映射为 plugin.<pluginID> 前缀,然后从全局 MCP server 列表中挑出匹配的 server。
如果项目显式设置了 selected_mcp_servers,返回结果会包含显式选择的 MCP server 加上选中插件生成的 MCP server;如果没有显式 MCP 选择,则返回项目级 MCP server,并补充选中插件生成的全局 MCP server。
6.3 技能发现
技能系统默认扫描项目技能 .anybox/skills 和用户技能 ~/.anybox/skills。插件技能由 Plugin.listInstalledPluginSkillRoots(pluginIDs) 提供根目录,只有已安装、已启用,并且在当前项目选中的插件会进入技能扫描范围。
会话构建 prompt 时,会通过 Skill.resolveTurnSkillIDs 结合项目选中的插件 ID 过滤可用技能,再由 SystemPrompt.skills 生成技能目录提示。技能内容本身仍然遵守渐进加载:只有模型明确调用 load-skill 时才读取完整 SKILL.md。
7. 构建与打包
Desktop 构建脚本 packages/desktop/scripts/prepare-agent-runtime.mjs 只打包 agent server、Bun、node-pty 和 workspace dependencies,不复制任何插件包。
校验脚本 packages/desktop/scripts/verify-agent-runtime.mjs 会拒绝包含 plugins/builtin 或 plugins/registry/plugin-registry.json 的 runtime。
8. 安全与约束
- 风险等级:插件和 server 支持
low、medium、high、critical。安装逻辑拒绝critical风险插件,UI 也禁止安装。 - 路径越界防护:插件技能目录解析使用 package root 相对路径校验,阻止 manifest 把技能目录指向包外路径。
- 配置校验:安装和更新时会校验必填配置字段,并用默认值补齐。
- 密钥处理:普通 MCP config field 仍会存在安装记录中;App connector 的 API key 则通过认证存储保存,不写入全局 MCP server 配置。
- 权限说明:manifest 中的
permissions和installReview会展示在插件详情页,帮助安装前审查。 - 运行时审批:MCP 工具仍受 MCP server 配置中的
toolPolicies、allowedTools、requireApproval约束。
9. 从插件到会话可用能力的完整链路
- 插件作者在
.anybox-plugin/plugin.json声明元信息、MCP server、skills 或 apps。 - agent catalog API 拉取远程插件元数据,用户安装时下载插件包到本机
plugins/installed目录。 - agent 扫描已下载插件 manifest,归一化为
PluginCatalogItem。 - desktop 插件页展示 catalog,用户选择安装。
- agent 安装插件,写入
installed_plugins,并生成全局 MCP server 配置。 - 用户在某个项目的 composer 菜单里选择插件,项目配置写入
selected_plugins。 - MCP manager 解析项目 MCP server 时,把选中插件生成的全局 MCP server 注入当前项目可用 server 列表。
- 技能系统根据项目选中的插件 ID 扫描插件技能根目录,把插件技能放入当前会话可发现技能列表。
- 会话运行时按 MCP transport 启动 stdio server 或连接 remote server;App connector 在连接时动态解析 API key。
10. 主要源码位置索引
| 文件 | 职责 |
|---|---|
packages/anyboxagent/src/plugin/plugin.ts |
插件 schema、manifest 扫描、catalog 归一化、安装/更新/删除、MCP 绑定、connector 密钥解析、插件技能根目录。 |
packages/anyboxagent/src/server/routes/settings.ts |
插件设置 API 路由:catalog、installed、diagnostic、connectors。 |
packages/anyboxagent/src/server/usecases/settings.ts |
设置 API use case,负责把 PluginError 转成 API error。 |
packages/anyboxagent/src/server/routes/projects.ts |
项目插件选择 API 路由。 |
packages/anyboxagent/src/server/usecases/projects.ts |
项目插件列表、选择、技能和 MCP selection 关联逻辑。 |
packages/anyboxagent/src/config/config.ts |
全局/项目配置,保存 selected_plugins,解析项目 MCP server。 |
packages/anyboxagent/src/skill/skill.ts |
插件技能发现、项目技能过滤、prompt 技能目录生成。 |
packages/anyboxagent/src/mcp/client.ts |
创建 stdio 或 remote MCP transport,remote connector 运行时解析。 |
packages/anyboxagent/src/mcp/manager.ts |
按项目解析 active MCP servers,发现工具并管理 MCP client 生命周期。 |
packages/desktop/src/main/ipc.ts |
desktop IPC 到 agent plugin/project API 的转发层。 |
packages/desktop/src/renderer/src/app/use-settings-page.ts |
插件设置页状态管理和操作函数。 |
packages/desktop/src/renderer/src/app/plugins/PluginsPage.tsx |
插件目录和详情 UI。 |
packages/desktop/src/renderer/src/app/use-project-composer.ts |
项目 composer 中插件选项加载和切换。 |
packages/desktop/scripts/prepare-agent-runtime.mjs |
desktop 构建 managed agent runtime,不复制插件包。 |