Skip to content

Extension Points

这个页面说明如何安全地扩展系统,以及需要遵守的边界约束。

适用场景:你要新增工具、修改传输层、扩展 CLI 命令表面,或修改配置行为。


可扩展区域

1. 新增工具类别(Tool Category)

如果你想暴露一组全新的 SiYuan API 能力给 MCP 客户端,需要按以下步骤操作:

步骤清单

  1. API 封装src/api/

    • src/api/ 下新建或扩展对应领域的文件
    • 遵循纯函数风格:export async function newAction(client: SiYuanClient, ...) { ... }
    • src/types/api.d.ts 中补充请求/响应类型
  2. 配置定义src/core/config.ts

    • ToolCategory 联合类型中新增 category 名
    • ACTIONS_BY_CATEGORY 中定义该 category 的 action 列表
    • buildDefaultToolConfig() 中设置默认值
    • (可选)在 ACTION_TIERS 中标注 basic / advanced
    • (可选)若有高危 action,加入 DANGEROUS_ACTIONS
  3. 工具实现src/tools/

    • 新建 src/tools/{category}/index.ts + src/tools/{category}/handlers.ts
    • 工具层共享基础设施放在 src/tools/internal/;跨工具 helper 放在 src/tools/internal/helpers/
    • 使用 defineTool() 工厂定义工具:
      typescript
      export const { listTools: listXxxTools, callTool: callXxxTool } = defineTool({
          category: 'xxx',
          description: '...',
          variants: [...],
      });
    • 每个 variant 包含:action(动作名)、description(描述)、schema(Zod schema)、handler(业务逻辑)
    • handler 中需要权限检查时,使用 tools/internal/context.ts 中的 ensurePermissionForDocumentId / ensurePermissionForNotebook
  4. 注册表注册src/core/tool-registry.ts

    • TOOL_REGISTRY 中新增条目:
      typescript
      xxx: { category: 'xxx', listTools: listXxxTools, callTool: callXxxTool }
  5. 帮助文案src/core/help.ts

    • 添加该 category 的 guidance 文本
    • 为每个 action 添加 hint
  6. Resource 注册src/core/resources.ts,可选)

    • 若需要动态 help 资源,在 readHelpResource() 中添加路由
  7. 设置面板src/ui/setting/mcp-config.svelte 及子面板)

    • ToolCategoriesPanel 中新增 category 的 checkbox
    • 添加对应的 i18n 文本
  8. 测试

    • tests/unit/tools/{category}.test.ts:覆盖每个 action 的 schema 和 handler
    • tests/integration/server.test.ts:确保新 tool 出现在 listTools()
    • tests/unit/cli/flag-mapper.test.ts:若 CLI 暴露新 flag,验证映射
  9. 文档

    • docs/reference/tools/{category}.mddocs/zh/reference/tools/{category}.md
    • 更新 API_MCP_MAPPING.md

依赖关系

api/{category}.ts  →  types/api.d.ts

tools/{category}/index.ts → tools/internal/define-tool.ts → tools/internal/shared.ts → config.ts + help.ts + types.ts

tool-registry.ts

resources.ts (可选)

2. 在现有工具类别中新增 Action

如果只是为已有 category 增加新 action,步骤大幅简化:

  1. API 封装:在对应 src/api/{category}.ts 中添加函数
  2. 配置定义:在 src/core/config.tsACTIONS_BY_CATEGORY[category] 中新增 action 名
  3. 工具实现:在对应 src/tools/{category}/index.tsvariants 数组中新增 variant
  4. 帮助文案:在 src/core/help.ts 中添加 action hint
  5. 测试:在 tests/unit/tools/{category}.test.ts 中覆盖新 action
  6. 文档:更新对应参考页和 API_MCP_MAPPING.md

注意:tool description 和 config action 列表必须保持一致。如果 action 在 config 中列出但未在 variants 中实现,或反之,都会导致运行时错误或不一致的用户体验。


3. 新增帮助资源(MCP Resource)

MCP Resources 是静态或动态的帮助文档,AI 客户端可通过 ReadResourceRequest 获取。

新增静态资源

src/core/resources.ts 中:

  1. listHelpResources() 中新增资源元数据
  2. readHelpResource() 中新增 URI 匹配分支
  3. src/core/help.ts 中定义资源内容文本

新增动态资源模板

动态资源模板遵循 siyuan://help/action/{tool}/{action} 模式。如需新增其他模板:

  1. listHelpResourceTemplates() 中新增模板 URI
  2. readHelpResource() 中解析新模板的参数并路由到对应生成逻辑

4. 扩展 CLI 渲染

CLI 的结果渲染在 src/cli/render.ts 中。如需支持新的 payload 类型:

  1. renderSuccessPayload() 的 type-guard 分支中新增识别逻辑
  2. 实现对应的渲染函数(参考现有的 renderArrayPayload() / renderPaginatedPayload() 等)
  3. 确保 --json 模式下该 payload 能被 JSON.stringify 正确处理

注意:新增渲染逻辑时,应同时更新 src/shared/invocation-format.ts,确保 MCP 和 CLI 模式下的帮助文本保持一致。


5. 扩展设置面板 UI

设置面板使用 Svelte 组件,与 SiYuan 原生 UI(b3-tab-barb3-list)融合。

新增配置项

  1. src/ui/setting/tool-config.ts 或相关 schema 文件中定义新字段
  2. src/ui/setting/tool-config-storage.ts 中添加 loadXxx() / saveXxx() 函数
  3. src/ui/setting/mcp-config.svelteonChanged 分发器中添加 key 前缀路由
  4. 在对应子面板组件中添加 UI 控件
  5. src/index.tsonload() 中加载新配置

新增子面板

  1. src/ui/setting/mcp-config/ 下新建 Svelte 组件
  2. src/ui/setting/mcp-config.svelte 的 tab-bar 和 content 区域中注册新面板
  3. 添加 i18n 文本到 dev/i18n/public/i18n/

6. 扩展传输层

当前支持 stdio 和 HTTP/S。如需新增传输方式:

  1. src/core/ 下新建传输实现文件(如 websocket-transport.ts
  2. 实现 MCP SDK 的 Transport 接口
  3. src/core/server.tsstartMcpServer() 中新增 transport mode 分支
  4. 在设置面板 HttpServerPanel(或新建面板)中添加配置 UI
  5. 更新文档说明新传输方式的使用方法

边界约束

安全边界

约束说明违反后果
必须通过 SiYuan API 访问数据所有数据读写(文件、配置、权限)都经过 SiYuanClient违反会导致远程场景不安全,插件审核被拒
笔记本权限必须继续生效任何 notebook-scoped 的 mutation 操作前必须调用 ensurePermissionForDocumentId / ensurePermissionForNotebook违反会导致权限模型形同虚设
高危操作必须标记新增 destructive action 必须加入 DANGEROUS_ACTIONS违反会导致 AI 意外执行危险操作
HTTP 非 loopback 必须启用 token若 HTTP server 绑定到非 127.0.0.1,必须有 token 鉴权违反会导致未授权远程访问
CLI 不做二次确认CLI 的危险动作不弹窗确认(用户主动输入即确认)不要试图在 CLI 中添加交互式确认,会破坏脚本化使用

代码边界

约束说明
不要修改 TOOL_REGISTRY 的静态结构保持 Record<ToolCategory, ToolModule> 的编译期确定性,不要引入动态扫描或反射
不要破坏 Zod Schema 的一致性src/core/types.ts 中的 schema 必须与 config.ts 中的 action 列表和 tools/{category}/index.ts 中的 variant schema 保持一致
不要引入全局状态SiYuanClientPermissionManager 等应作为参数传递,不要保存在模块级变量中(CLI 和插件可能同时存在多个实例)
保持 CJS 输出格式Vite 配置中所有产物都是 CommonJS,不要引入 ESM-only 依赖
Node 内置模块保持 externalserver/cli 的 Rollup external 中保留 Node 内置模块,不要打包进 bundle

文档边界

约束说明
Tool docs 必须与 config action 列表对齐`docs/zh
双语同步所有文档变更必须同时更新 zh/en/ 版本
API 映射文档必须同步更新新增 action 必须更新 API_MCP_MAPPING.mdAPI_COMPLETE_MAPPING.md

测试策略

新增工具/Action 的测试要求

测试类型必做验证内容
Action Schema 暴露新 action 出现在 inputSchema.properties.action.enum
Handler 逻辑mock SiYuanClientPermissionManager,验证 handler 行为
Zod 校验有效/无效参数分别测试
权限检查✓(若涉及 notebook-scoped mutation)mock 不同权限级别,验证拦截行为
Help 输出action="help" 返回正确的帮助内容
集成测试新 tool 出现在 listTools() 结果中;端到端调用返回预期结果
Schema 快照建议tests/unit/tools/help-output.snapshot.test.ts 锁定 help 输出
CLI Flag 映射建议(若 CLI 暴露新 flag)验证 kebab↔camel 映射和类型强转

测试运行命令

bash
pnpm test              # 运行 unit + integration 测试
pnpm test:watch        # watch 模式
pnpm test:coverage     # 覆盖率报告
pnpm test:smoke        # 冒烟测试(需要真实 SiYuan 实例)

发布 checklist

当你完成扩展开发后,按以下顺序验证:

  • [ ] pnpm build 成功,无 TypeScript 错误
  • [ ] pnpm build:cli 成功
  • [ ] pnpm test 全部通过
  • [ ] pnpm test:smoke 通过(如适用)
  • [ ] 文档已更新(zh + en)
  • [ ] API_MCP_MAPPING.md 已更新
  • [ ] 设置面板 UI 已更新(如适用)
  • [ ] i18n 文本已补充(如适用)
  • [ ] CHANGELOG.md 已记录

Released under the MIT License.