Skip to content

Plugin 开发生命周期

Plugin 适用场景

建议优先使用 Workflow 进行流程编排。Plugin 的开发成本相对较高,仅在出现以下需求时推荐开发 Plugin:

  • 需要对外暴露 MCP 标准接口 (Tool Schema)
  • 需要桥接外部系统或 Native 本地二进制套件
  • 动态注册或生成子级能力 (Domains / Workflows / Metrics)
  • 需要极其严格的运行时权限隔离与白名单控制

基础插件示例

所有插件的初始化基于声明式的 fluent builder 模式链式调用。 参考代码库 jshook_plugin_template 下的 manifest.ts

ts
import { createExtension, jsonResponse } from '@jshookmcp/extension-sdk/plugin';

export default createExtension('io.github.example.my-first-plugin', '1.0.0')
  .compatibleCore('^0.1.0')
  .allowTool(['page_click', 'network_get_requests'])
  .metric(['my_plugin.loaded'])
  .tool(
    'my_custom_tool',
    'Execute DOM mutation and fetch traces.',
    { selector: { type: 'string', description: 'Mutation payload selector' } },
    async (args, ctx) => {
      const clickRes = await ctx.invokeTool('page_click', { selector: String(args.selector) });
      return jsonResponse({ success: true, result: clickRes });
    }
  )
  .onLoad((ctx) => {
    ctx.setRuntimeData('init_stamp', Date.now());
  })
  .onActivate(async (ctx) => {
    ctx.registerMetric('my_plugin.loaded');
  });

插件目录中的 meta.yaml 负责对外展示元数据,manifest.ts 只保留运行时声明:

yaml
name: My First Plugin
description: Execute DOM mutation and fetch traces.
author: your-team
source_repo: https://github.com/your-org/my-first-plugin

说明:

  • createExtension:创建插件实例,需提供具备唯一性的 ID 与版本号。
  • .allowTool([...]):声明允许调用的工具白名单,越权调用将抛出异常。
  • .tool(name, ...):向外部 MCP 客户端注册一个新的工具端点。
  • ctx.invokeTool(...):在插件沙箱内安全调用其他系统内置工具。

插件开发流程

1. 准备开发环境

  • 使用基础模板库: https://github.com/vmoranv/jshook_plugin_template
  • 初始化主进程环境变量: export MCP_PLUGIN_ROOTS=<path-to-cloned-jshook_plugin_template>
  • PowerShell: $env:MCP_PLUGIN_ROOTS = "<path-to-cloned-jshook_plugin_template>"

2. 构建与校验

bash
pnpm install
pnpm run build
pnpm run check

工程约定:本地开发建议使用 TypeScript 编写。源代码通过 manifest.ts 暴露入口,主程序将自动加载编译后的 dist/manifest.js 并执行逻辑。

3. 修改标识符

部署前,请替换模板工程中以下全局标识:

  • 插件 ID (PLUGIN_ID):推荐使用 x.y.z 反向域名格式,如 io.github.example.my-plugin
  • meta.yaml 中的 name / description / author / source_repo

4. 权限白名单配置

出于核心安全机制考量,所有可能产生影响的操作必须显式声明白名单权限:

  • toolExecution.allowTools:限制子模块通过 ctx.invokeTool() 可调用的工具集合。
  • network.allowHosts:管控允许发起的网络套接字请求的目标地址。
  • process.allowCommands:限制允许派生的外部系统命令名称。
  • filesystem.readRoots / filesystem.writeRoots:限制文件系统的安全读写路径。

注意事项

  • 请始终采用最小可用原则分配权限。
  • 严禁在生产环境验证阶段使用通配符 *

API 解析

核心构建方法

  • .compatibleCore(range) — 声明插件所依赖的核心引擎版本范围。
  • .allowTool(tools) — 声明允许插件运行时调用的内置工具白名单。
  • .allowHost(hosts) — 配置网络请求白名单。
  • .allowCommand(cmds) — 配置系统命令执行白名单。
  • .profile(profiles) — 声明适用的工具层级,如 ['workflow', 'full']

生命周期方法

引擎提供的核心回调生命周期如下:

  1. onLoad(ctx): 读取本地目录下的配置文件并进行依赖缓存准备。
  2. onValidate(ctx): 执行运行前的前置条件检测(如校验必要 Token、检测外置端口存活、审核连通性)。
  3. onActivate(ctx) / onDeactivate(ctx): 负责业务运行期的资源申请、内存清理与长连接中止。

PluginLifecycleContext

  • ctx.invokeTool(name, args?): 调用内置工具。调用须受 allowTool 声明的白名单限制,且受当前 MCP_TOOL_PROFILE 环境配置管控约束。
  • ctx.getConfig(path, fallback): 从主进程映射读取此插件相关的只读配置缓存。
  • ctx.setRuntimeData(key, value) / ctx.getRuntimeData(key): 管理本插件运行时的内存状态(如缓存数据、认证失效时间等)。

工具函数库

@jshookmcp/extension-sdk 内置了以下常用辅助函数:

  • jsonResponse(payload) / errorResponse(tool, error, extra?): 生成标准 MCP 工具响应。
  • checkExternalCommand(...) / runProcess(...): 用于桥接本地 CLI 并做基础超时与输出封装。

验证与发布

插件加载后的建议验证步骤:

  1. 客户端发送 reload_extensions
  2. 运行 list_extensions 确认您的插件和工具已加载
  3. 直接调用扩展工具,或使用 search_tools / describe_tool 做探测
  4. 如果代码有改动,必须重新执行 pnpm run build 以刷新 JS 包依赖

reload_extensions 现在会把当前 profile 可见的扩展工具直接注册到 MCP 工具列表中,不需要再额外执行一次 activate_tools。只有当工具不在当前 profile、或者客户端没有刷新工具列表时,才需要借助 activate_tools / call_tool

list_extensions / reload_extensionstools 数组会直接返回每个扩展工具的:

  • profiles:声明的 profile 范围
  • visibleInCurrentProfile:当前会话 profile 下是否可见
  • active:当前是否已注册到工具列表
  • activationSource:激活来源(reload / activate_tools / activate_domain

Released under AGPL-3.0-only