自定义 Skill
学习如何为 DCC 应用程序构建自定义 Skill — 从推荐的 Skills-First 方式到低级注册表 API。
推荐:Skills-First 方式
Skills-First 方式通过环境变量发现 SKILL.md 包,是构建 DCC 工具的推荐方式:
- 零样板代码 — 无需手动注册处理器,工具自动发现
- 自动暴露为 MCP 工具 — Skill 管理器通过 MCP 协议将每个工具暴露给 AI
- 热重载 —
SKILL.md的修改无需重启即可生效
第一步:创建 SKILL.md 包
markdown
---
name: maya-geometry
description: Maya 几何体创建工具
version: 1.0.0
dcc: maya
tags: [geometry, create]
tools:
- name: create_sphere
description: 创建多边形球体
input_schema: |
{
"type": "object",
"required": ["radius"],
"properties": {
"radius": {"type": "number", "minimum": 0.1},
"name": {"type": "string"}
}
}
scripts:
- create_sphere.py
---
# Maya 几何体工具
在 Maya 中创建和编辑几何体的工具集。第二步:实现脚本
create_sphere.py:
python
import maya.cmds as cmds
from dcc_mcp_core import success_result, error_result
def create_sphere(radius: float = 1.0, name: str | None = None):
try:
sphere = cmds.polySphere(r=radius, n=name)[0]
return success_result(
message=f"已创建球体:{sphere}",
context={"object_name": sphere, "radius": radius}
)
except Exception as e:
return error_result(str(e))第三步:通过环境变量注册并启动
python
import os
from dcc_mcp_core import create_skill_server
os.environ["DCC_MCP_MAYA_SKILL_PATHS"] = "/path/to/my/skills"
# 一行代码:自动发现 Skill,启动 MCP HTTP 服务
manager = create_skill_server("maya")Skills-First 是推荐模式
所有新 DCC 工具优先使用 SKILL.md 包。仅在需要运行时动态控制处理器逻辑时,才回退到注册表 API。
低级注册表 API
当需要在运行时以编程方式控制处理器注册时,使用 ToolRegistry + ToolDispatcher API。
完整示例
python
import json
from dcc_mcp_core import ToolRegistry, ToolDispatcher
# 1. 使用 JSON Schema 注册 action 元数据
reg = ToolRegistry()
reg.register(
name="create_sphere",
description="在 Maya 中创建多边形球体",
category="geometry",
tags=["geo", "create", "mesh"],
dcc="maya",
version="1.0.0",
input_schema=json.dumps({
"type": "object",
"required": ["radius"],
"properties": {
"radius": {
"type": "number",
"minimum": 0.1,
"description": "球体半径"
},
"segments": {
"type": "integer",
"minimum": 4,
"default": 16,
"description": "细分段数"
},
"name": {
"type": "string",
"description": "可选的球体名称"
}
}
}),
)
# 2. 创建 dispatcher 并注册处理器
dispatcher = ToolDispatcher(reg)
def handle_create_sphere(params):
radius = params.get("radius", 1.0)
segments = params.get("segments", 16)
name = params.get("name")
# 调用 Maya API(使用 maya.cmds 的示例)
import maya.cmds as cmds
sphere_name = cmds.polySphere(r=radius, sx=segments, sy=segments, n=name)[0]
return {
"created": True,
"object_name": sphere_name,
"radius": radius,
"segments": segments,
}
dispatcher.register_handler("create_sphere", handle_create_sphere)
# 3. 使用 JSON 分派(wire format)
import json
result = dispatcher.dispatch("create_sphere", json.dumps({"radius": 2.0, "segments": 32}))
print(result["output"]["object_name"]) # "pSphere1"关键要点
- 使用
ToolRegistry.register()注册 —— 传入 name、description、tags、DCC、version 和 JSON Schema - 实现处理器函数 —— 接收
params: dict,返回结果字典 - 使用
ToolDispatcher注册处理器 —— 将 action 名称连接到 Python 可调用对象 - 使用 JSON Schema 进行验证 ——
ToolDispatcher在调用处理器之前验证 JSON 输入 - 使用 JSON 字符串分派 —— wire format 使用 JSON,而非 Python 字典
处理器函数签名
python
def my_handler(params: dict) -> Any:
"""
Args:
params: 验证后的参数(已从 JSON 输入解析)
Returns:
一个字典,作为 action 结果(可序列化为 JSON)
"""
pass使用 ToolValidator 进行验证
在分派前验证输入:
python
from dcc_mcp_core import ToolValidator
validator = ToolValidator.from_action_registry(reg, "create_sphere", dcc_name="maya")
ok, errors = validator.validate('{"radius": 1.5}')
if not ok:
print(f"Validation failed: {errors}")
# 处理错误版本化 Action
使用 VersionedRegistry 保持向后兼容:
python
from dcc_mcp_core import VersionedRegistry
vr = VersionedRegistry()
# v1: 基础球体
vr.register_versioned(
"create_sphere", dcc="maya", version="1.0.0",
description="Basic sphere creation",
)
# v2: 添加细分参数
vr.register_versioned(
"create_sphere", dcc="maya", version="2.0.0",
description="Sphere with subdivision control",
)
# 自动解析最佳版本
result = vr.resolve("create_sphere", "maya", "^1.0.0")
print(result["version"]) # "2.0.0"JSON Schema 技巧
- 使用
$ref可重用 schema(ToolValidator 不支持 —— 请内联所有定义) "default"字段在输入中缺少 key 时设置默认值- 使用
"minimum"/maximum进行数值约束 - 使用
"minLength"/maxLength进行字符串长度约束 - 使用
"enum"限制字符串选择
python
input_schema = json.dumps({
"type": "object",
"required": ["radius"],
"properties": {
"radius": {
"type": "number",
"minimum": 0.1,
"maximum": 1000.0,
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 64,
},
"align_to_world": {
"type": "boolean",
"default": False,
}
}
})