Skip to content

MCDK-ASSISTANT 插件与资料扩展

MCDK-ASSISTANT 提供插件系统,可通过 Python 插件注册自定义 MCP Tool,也可以把自己的 Markdown / 文本文档作为资料库接入搜索。常见用途是把团队内部规范、项目笔记、私有 SDK 说明或某个 MOD 的工程约定做成可检索资料,让 Agent 在生成代码前先查到本项目自己的上下文。

Python 运行时

MCDK-ASSISTANT 使用 PocketPy 作为脚本引擎后端,而不是嵌入 CPython。PocketPy 更轻量,适合嵌入到本地 MCP Server 中,但它与完整 CPython 生态并不完全等价。

运行时差异

插件代码不要假设可以使用 CPython 的完整标准库、pip 包、虚拟环境或 C 扩展。请优先使用 MCDK-ASSISTANT 注入的 mcdk_assistant API,以及运行时已补齐的常用 os / os.path 风格文件接口。

插件里的 print()sys.stdout.write()sys.stderr.write() 会被宿主转发到日志侧。在 stdio MCP 模式下,这些输出不会污染 stdout 上的 JSON-RPC 协议流;Tool 的正式结果只取函数 return 值。

插件目录

运行时会扫描可执行文件同级的 plugins/ 目录。每个插件一个子目录,最小结构如下:

text
plugins/
  HelloPlugin/
    manifest.json
    main.py

manifest.json 负责描述插件元信息和入口脚本:

json
{
  "id": "hello_plugin",
  "name": "Hello Plugin",
  "version": "0.1.0",
  "entry": "main.py",
  "description": "最小插件示例"
}

idnameversionentry 是必填字段。建议 id 使用稳定的小写标识,后续日志、上下文和冲突兜底都会依赖它。

最小 Tool

插件通过 mcdk_assistant 模块注册 Tool。下面示例注册一个只读、幂等的 hello Tool:

python
import mcdk_assistant as mcdk

helloSchema = (
    mcdk.schema.Object()
    .field("name", mcdk.schema.String("要问候的名字", default="Steve"))
)

@mcdk.tool(
    "hello",
    "返回一个问候。",
    helloSchema,
    options=mcdk.ToolOptions(read_only=True, idempotent=True),
)
def helloTool(args, ctx):
    name = str(args.get("name", "Steve")).strip() or "Steve"
    return {
        "message": "hello " + name,
        "plugin": ctx.plugin_id,
        "tool": ctx.tool,
    }

Tool 名会暴露给 MCP 客户端。请优先给 Tool 取稳定、简短、语义明确的名字;函数名和普通变量可按项目风格使用驼峰命名。

资料扩展示例

资料扩展的核心思路是:插件自带一个 docs/ 目录,首次搜索时用 mcdk.search.build_index_from_dir(...) 懒构建内存索引,然后通过自定义 Tool 返回命中结果。

推荐结构:

text
plugins/
  CustomSearchDemo/
    manifest.json
    main.py
    docs/
      cache-hot-reload.md
      script-bridge-lifecycle.md
      async-packet-pipeline.md

manifest.json

json
{
  "id": "custom_search_demo",
  "name": "Custom Search Demo",
  "version": "0.1.0",
  "entry": "main.py",
  "description": "注册一个用于检索插件内置资料库的示例工具"
}

main.py

python
import mcdk_assistant as mcdk

docIndex = None

searchSchema = (
    mcdk.schema.Object()
    .field(
        "keyword",
        mcdk.schema.String(
            "搜索关键词,例如 packet、缓存、热更新、组件生命周期",
            required=True,
        ),
    )
    .field(
        "topK",
        mcdk.schema.Integer(
            "返回结果数量,默认 5,范围 1-10",
            minimum=1,
            maximum=10,
            default=5,
        ),
    )
)

def clampInt(value, defaultValue, minValue, maxValue):
    try:
        number = int(value)
    except Exception:
        number = defaultValue
    if number < minValue:
        return minValue
    if number > maxValue:
        return maxValue
    return number

def getDocIndex(ctx):
    global docIndex
    if docIndex is None:
        docIndex = mcdk.search.build_index_from_dir(
            ctx.plugin_dir + "/docs",
            glob=["**/*.md"],
            mode="zh",
            chunk="markdown_heading",
            lazy=True,
        )
    return docIndex

@mcdk.tool(
    "demo_tech_search",
    "搜索 custom_search_demo 插件内置的技术资料。",
    searchSchema,
    options=mcdk.ToolOptions(
        read_only=True,
        idempotent=True,
        open_world=False,
        destructive=False,
    ),
)
def demoTechSearch(args, ctx):
    keyword = str(args.get("keyword", "")).strip()
    topK = clampInt(args.get("topK", 5), 5, 1, 10)

    if not keyword:
        return {
            "error": "keyword is required",
            "hint": "试试搜索 packet、缓存、热更新、组件生命周期、脚本桥接",
        }

    results = getDocIndex(ctx).search(keyword, topK)
    return {
        "plugin": ctx.plugin_id,
        "tool": ctx.tool,
        "query": keyword,
        "count": len(results),
        "results": results,
    }

这里的 demo_tech_search 是对外暴露的 MCP Tool 名,因此保留下划线命名;其余 Python 变量和函数使用驼峰风格,便于和 MCDK-ASSISTANT 文档示例保持一致。

搜索索引说明

mcdk.search.build_index_from_dir(...) 会创建一个内存索引对象:

python
index = mcdk.search.build_index_from_dir(
    root,
    glob=["**/*.md", "**/*.txt"],
    mode="zh",
    chunk="markdown_heading",
    lazy=True,
)

常用参数:

参数说明
root要索引的资料目录
glob文件匹配规则,资料扩展通常使用 Markdown 或文本文件
mode分词模式,中文资料通常使用 zh
chunk切片策略,Markdown 文档推荐 markdown_heading
lazy是否懒构建;推荐开启,第一次搜索时再构建索引

返回的索引对象可调用 search(keyword, topK)。搜索结果包含命中文本、来源文件、起止行号和分数,可直接返回给 MCP 客户端。

安装与验证

  1. 将插件目录复制到 MCDK-ASSISTANT 可执行文件同级的 plugins/ 目录下。
  2. 确保插件目录内存在 manifest.json 和入口脚本。
  3. 重启 MCP Server。
  4. 在 AI 客户端中调用或要求 Agent 调用 demo_tech_search,搜索 缓存热更新packet 等关键词。

如果 Tool 名与已有 Tool 冲突,运行时会尝试使用 plugin_id.tool_name 作为公开名称兜底。实际项目中仍建议从一开始就使用足够明确的 Tool 名,减少 Agent 选择工具时的歧义。

开发补全

安装产物中通常会提供 plugins-dev/completion 作为插件开发补全库。把该目录加入 IDE 的 Python analysis path 后,import mcdk_assistant as mcdk 可以获得类型提示和中文悬停说明。

该补全库只服务于编辑器,不会参与 PocketPy 运行时。插件发布时不需要把补全库复制进插件包。

实用建议

  • Tool 返回值保持 JSON 可序列化,优先返回 dictliststrintfloatboolNone
  • 只读查询 Tool 应声明 read_only=Trueidempotent=True,便于 MCP 客户端理解调用风险。
  • 写入文件或修改资源的 Tool 应谨慎设置 destructiveopen_world,不要把有副作用的操作伪装成只读查询。
  • 插件内资料建议按主题拆成多篇 Markdown,并使用清晰标题;markdown_heading 切片会让搜索结果更接近“可引用段落”。
  • 插件代码避免依赖 CPython 专属库和第三方包;需要文件读写时优先使用 mcdk.fs 或运行时已补齐的常用 os 接口。

Released under the BSD3 License