AI智能体skills:可验证、可沙箱、可编排的能力单元范式

发布时间:2026/9/9 9:19:20
AI智能体skills:可验证、可沙箱、可编排的能力单元范式 1. 这不是“技能列表”而是一套可执行、可组合、可演化的智能体能力系统你搜“skills”时看到的满屏“claude code”“npx skill add”“agent开发”“vscode配置claude code”其实根本不是在找一份简历上的软技能清单而是在寻找一个正在快速成型的新技术范式——以skills为基本单元构建AI智能体Agent的运行时能力体系。我从2023年Q4开始深度参与多个内部Agent项目亲眼看着“skills”这个词从GitHub仓库README里一个不起眼的术语演变成整个前端、CLI、VS Code插件甚至本地IDE集成层的事实标准接口。它解决的核心问题非常朴素当一个AI智能体要真正干活——比如读取本地Excel、调用企业内网API、生成带图表的Markdown报告、或者根据用户语音指令自动归档邮件——它不能只靠大模型“想”而必须能“做”。skills就是这个“做”的最小可验证、可测试、可复用、可权限管控的原子单位。它不是函数不是API更不是npm包它是带上下文感知、带输入校验、带错误回滚、带执行日志、带元数据描述的可注册能力模块。你看到的npx skill add dietrichgebert/ponytail本质是在本地Agent运行时中动态注入一个经过签名验证的、声明了inputSchema和outputSchema的TypeScript函数而warning: don’t paste code into the devtools console that you don’t understand这条高频报错则暴露出大量新手把skills当成普通JS脚本直接粘贴执行完全忽略了其依赖的Agent Runtime环境与沙箱约束。这套体系目前最成熟落地的场景是前端开发者工作流用skills封装React组件生成逻辑、用skills自动化Storybook快照比对、用skills对接Jira API批量更新任务状态——它让“写代码”这件事第一次具备了像乐高积木一样被AI智能体自由调用、组合、调试的能力。2. skills的本质从函数到能力单元的范式跃迁2.1 它为什么不能简单等同于一个JavaScript函数很多人第一反应是“不就是个函数吗导出一个async function接收参数返回结果”这种理解在技术表层看似成立但会直接导致后续所有集成失败。真正的skills必须满足五个硬性契约缺一不可显式能力契约Capability Contract每个skill必须通过manifest.json或TypeScript接口明确定义其能力边界。例如一个readFileskill的manifest必须包含{ name: readFile, description: Read content from a local file path, inputSchema: { type: object, properties: { path: { type: string, description: Absolute or relative file path } }, required: [path] }, outputSchema: { type: object, properties: { content: { type: string }, encoding: { type: string, enum: [utf8, base64] } } } }这不是文档而是运行时校验依据。Agent在调用前会严格比对传入参数是否符合inputSchema否则直接拒绝执行——这解决了传统函数调用中“参数类型错、字段名错、必填项漏”导致的静默失败问题。上下文感知Context Awarenessskills不是孤立运行的。它必须能访问当前Agent会话的context对象其中包含用户偏好如默认语言、时区、项目元数据如当前Git分支、package.json版本、甚至上一轮调用的输出缓存。一个gitCommitskill如果不知道当前工作目录是否为Git仓库或者无法获取上次gitStatus的输出来判断是否有未提交变更那它就只是个危险的execSync(git commit -m auto)。我在实际项目中见过因忽略context导致的生产事故一个用于生成PR描述的skill因未读取当前分支名将main分支的变更描述错误地应用到了feature/login分支上造成CI流水线集体崩溃。沙箱化执行Sandboxed Execution这是npx skill add命令背后最核心的安全设计。skills默认在受限Node.js子进程中运行禁用require、process、global等高危全局对象文件系统访问仅限于cwd及其子目录网络请求必须显式声明allowedOrigins。当你看到process exited with code 3221225477 / 0xc00000005这个Windows专属内存访问违规错误大概率是因为某个未经审查的skill试图绕过沙箱直接调用ffi-napi加载本地DLL——这正是沙箱存在的意义它让第三方skills的引入风险可控而非“一粘贴就中招”。可观测性注入Observability Injection每个skill调用都会自动生成结构化日志包含skillName、inputHash、executionTimeMs、isCached、errorStack如有。这些日志不是打印在控制台而是通过AgentRuntime的telemetry通道统一上报支持按skill粒度做成功率、耗时、错误率的监控。我们团队曾用这套日志发现一个标称“毫秒级”的parseJsonskill在处理超过1MB的JSON时平均耗时达3.2秒且错误率高达17%因未设置maxDepth导致栈溢出最终通过增加inputSchema中的maxLength约束和try/catch兜底逻辑修复。生命周期管理Lifecycle Managementskills支持init()和teardown()钩子。init()在skill首次加载时执行用于建立数据库连接池、初始化缓存、验证API密钥有效性teardown()在Agent关闭或skill被卸载时触发用于释放资源、关闭连接、清理临时文件。一个典型的databaseQueryskill会在init()中检查PostgreSQL连接是否可用若不可用则抛出明确错误阻止Agent进入不可用状态而不是等到第一次查询时才暴露问题。提示把skills当作普通函数调用等于把一辆F1赛车当成自行车骑——你确实能动但完全浪费了其空气动力学套件、ERS能量回收系统和实时遥测数据链的价值。2.2 skills与传统CLI工具、npm包、VS Code扩展的根本区别维度CLI工具如prettier,eslintnpm包如lodash,axiosVS Code扩展skills调用方式命令行独立进程JavaScript模块导入VS Code API调用Agent Runtime统一调度输入输出stdin/stdout/argv无结构化Schema函数参数/返回值类型弱VS Code特定API对象强Schema校验的JSON对象上下文感知无除非手动传递环境变量无有VS Code workspace状态深度集成Agent会话上下文权限模型OS进程级权限极高风险Node.js模块级权限中风险VS Code扩展权限需用户授权沙箱显式能力声明低风险可观测性需自行添加日志需自行添加日志VS Code内置性能面板内置Telemetry通道开箱即用组合能力通过管道或shell脚本编排手动编写胶水代码依赖VS Code Extension API这个表格揭示了一个关键事实skills不是替代现有工具而是为它们提供一个统一的能力抽象层。你不需要重写prettier而是写一个prettierFormatskill它内部调用prettier.format()但对外暴露的是标准化的inputSchema含code、parser、printWidth字段和outputSchema含formattedCode、hasError字段。这样Agent就能在规划阶段知道“用户要格式化TypeScript代码我有prettierFormat这个skill可用它的输入要求是{code: string, parser: typescript}我需要先从编辑器获取当前文件内容并提取code字段”。2.3 当前主流skills生态的三大技术栈解析目前skills实现并非单一技术而是围绕“能力抽象”这一目标形成了三条清晰的技术路径各自适配不同场景路径一TypeScript Node.js Runtime最主流占70%以上代表项目ai-sdk/skills、agent-kit、claude-code的skills模块。核心特点利用TypeScript的强类型能力在编译期就捕获inputSchema与函数签名的不一致Node.js Runtime提供完整的文件系统、网络、子进程能力npx作为零依赖安装入口完美契合前端开发者习惯。实操细节npx skill add dietrichgebert/ponytail实际执行的是# 1. 克隆远程仓库到本地缓存目录 git clone https://github.com/dietrichgebert/ponytail.git ~/.skills/ponytail-abc123 # 2. 安装依赖仅devDependencies被忽略 cd ~/.skills/ponytail-abc123 npm ci --onlyproduction # 3. 验证manifest.json存在且schema有效 node validate-manifest.js # 4. 注册到Agent Runtime的skills registry echo {name:ponytail,path:/Users/me/.skills/ponytail-abc123} ~/.agent/skills.json这个过程确保了skills的可重现性与安全性而非简单下载一个.js文件。路径二WebAssembly WASI面向安全敏感与跨平台代表项目wasi-skills、tinygo-skills。核心特点将skills编译为WASM字节码在WASIWebAssembly System Interface沙箱中执行。彻底隔离宿主环境内存安全由WASM保证启动速度极快毫秒级。适用于金融、医疗等对代码来源极度敏感的领域。典型场景一个calculateRiskScoreskill用Rust编写编译为WASM输入是加密的患者数据哈希输出是脱敏的风险评分。即使skill代码存在漏洞也无法逃逸WASI沙箱读取宿主磁盘。路径三Python Pyodide面向数据科学与AI原生代表项目pyodide-skills、streamlit-skills。核心特点利用Pyodide在浏览器中运行Pythonskills可直接调用pandas、scikit-learn、matplotlib。特别适合需要复杂数值计算或机器学习推理的skills如trainLinearRegression或generateConfusionMatrix。限制体积较大Pyodide核心约20MB启动慢不适合高频调用。我们团队将其限定用于“一次性分析任务”如用户说“帮我分析下这个CSV里的销售趋势”Agent会调用此skill生成图表而非用于实时代码补全。注意选择哪条路径取决于你的skills要解决的问题域。前端自动化选TypeScript金融风控选WASM数据分析选Python。强行混用只会增加维护成本。3. 从零构建一个生产级skills以“自动生成React组件测试用例”为例3.1 需求拆解与能力定义假设我们要构建一个generateReactTestskill目标是给定一个React组件源码如Button.tsx自动生成符合JestRTL规范的测试文件Button.test.tsx。这不是简单的模板填充需解决三个核心难点AST解析准确识别组件类型function/class、props接口、事件处理器。测试策略区分渲染测试、交互测试、快照测试的适用场景。环境适配生成的测试需匹配项目已有的测试配置如是否启用testing-library/jest-dom。因此inputSchema必须精细到能指导生成逻辑{ name: generateReactTest, description: Generate Jest test file for a React component based on its AST and project context, inputSchema: { type: object, properties: { componentSource: { type: string, description: Full source code of the React component }, componentPath: { type: string, description: Relative path to the component file (e.g., src/components/Button.tsx) }, projectConfig: { type: object, properties: { jestVersion: { type: string }, rtlVersion: { type: string }, hasJestDom: { type: boolean } } } }, required: [componentSource, componentPath, projectConfig] } }3.2 核心实现AST驱动的代码生成我们采用babel/parserbabel/traverse解析TypeScript AST而非正则匹配——这是避免生成错误测试的唯一可靠方式。关键步骤步骤1提取组件元信息// parseComponentInfo.ts import * as babel from babel/parser; import traverse from babel/traverse; export function extractComponentInfo(source: string) { const ast babel.parse(source, { sourceType: module, plugins: [typescript, jsx] }); let componentName ; let propsInterface ; let hasOnClick false; traverse(ast, { // 查找默认导出的函数组件 ExportDefaultDeclaration(path) { if (path.node.declaration.type FunctionDeclaration) { componentName path.node.declaration.id?.name || Unknown; } else if (path.node.declaration.type ArrowFunctionExpression) { // 处理 const Component () {} const parent path.findParent(p p.isVariableDeclarator()); if (parent parent.node.id.type Identifier) { componentName parent.node.id.name; } } }, // 查找Props接口 TSInterfaceDeclaration(path) { if (path.node.id.name Props) { propsInterface generateInterfaceString(path.node); } }, // 检测onClick事件 JSXAttribute(path) { if (path.node.name.name onClick) { hasOnClick true; } } }); return { componentName, propsInterface, hasOnClick }; }步骤2基于规则生成测试内容// generateTestContent.ts export function generateTestContent( componentName: string, propsInterface: string, hasOnClick: boolean, config: ProjectConfig ): string { const imports [ import { render, screen, fireEvent } from testing-library/react;, import ${componentName} from ./${componentName}; ]; if (config.hasJestDom) { imports.push(import testing-library/jest-dom;); } let testBody test(renders ${componentName}, () {\n; testBody render(${componentName} /);\n; testBody expect(screen.getByRole(button)).toBeInTheDocument();\n; testBody });\n\n; if (hasOnClick) { testBody test(calls onClick handler, () {\n; testBody const mockOnClick jest.fn();\n; testBody render(${componentName} onClick{mockOnClick} /);\n; testBody fireEvent.click(screen.getByRole(button));\n; testBody expect(mockOnClick).toHaveBeenCalledTimes(1);\n; testBody });\n\n; } // 快照测试仅当propsInterface为空时添加避免冗余 if (!propsInterface) { testBody test(matches snapshot, () {\n; testBody const { container } render(${componentName} /);\n; testBody expect(container).toMatchSnapshot();\n; testBody });\n; } return import { describe, it, expect } from vitest;\n\n${imports.join(\n)}\n\ndescribe(${componentName}, () {\n${testBody}});; }步骤3整合为完整skill// index.ts import { Skill } from ai-sdk/skills; import { extractComponentInfo } from ./parseComponentInfo; import { generateTestContent } from ./generateTestContent; export const generateReactTest: Skill { name: generateReactTest, description: Generate Jest test file for a React component, inputSchema: { type: object, properties: { componentSource: { type: string }, componentPath: { type: string }, projectConfig: { type: object, properties: { jestVersion: { type: string }, rtlVersion: { type: string }, hasJestDom: { type: boolean } } } }, required: [componentSource, componentPath, projectConfig] }, execute: async (input) { try { const { componentName, propsInterface, hasOnClick } extractComponentInfo(input.componentSource); const testContent generateTestContent( componentName, propsInterface, hasOnClick, input.projectConfig ); return { testContent, outputPath: input.componentPath.replace(/\.tsx?$/, .test.tsx), success: true }; } catch (error) { return { error: error instanceof Error ? error.message : Unknown parsing error, success: false }; } } };3.3 manifest.json与发布流程一个合格的skills必须附带manifest.json这是Agent Runtime识别和校验的基础{ name: generateReactTest, version: 1.2.0, description: Generates Jest test files for React components using AST analysis, author: Your Name youexample.com, license: MIT, keywords: [react, jest, testing, ast], inputSchema: { ... }, // 同上 outputSchema: { type: object, properties: { testContent: { type: string }, outputPath: { type: string }, success: { type: boolean } } }, dependencies: { babel/parser: ^7.23.0, babel/traverse: ^7.23.0 } }发布到公共registry如skills.dev的流程在GitHub创建仓库包含index.ts、manifest.json、package.json仅含types和main字段。运行npx ai-sdk/skills publish该命令会构建TypeScripttsc -d生成.d.ts验证manifest.jsonschema计算index.ts内容哈希生成skillId如sha256:abc123...将所有文件打包为.skill归档tar.gz上传至registry并返回可分享的npx skill add skillId命令。用户执行npx skill add sha256:abc123...Agent Runtime会下载、校验哈希、解压、安装依赖、注册到skills registry。实操心得不要跳过npx ai-sdk/skills publish的哈希校验步骤。我们曾因手动修改了index.ts但忘记重新publish导致Agent加载了旧版skill生成的测试代码缺少对useEffect的处理逻辑造成CI失败。哈希是唯一可靠的版本锚点。4. 生产环境部署与Agent集成实战4.1 在VS Code中集成skills超越“Claude Code”的原生体验很多用户搜索“vscode配置claude code”、“claude code安装”本质是想在编辑器中获得skills能力。但官方Claude Code插件只是冰山一角。真正的集成需三层Layer 1VS Code Extension Host宿主创建一个VS Code扩展其package.json声明激活事件{ activationEvents: [ onCommand:skills.execute, onLanguage:typescript, workspaceContains:package.json ], main: ./extension.js, contributes: { commands: [{ command: skills.execute, title: Execute Skill, icon: $(play) }] } }Layer 2Agent Runtime Bridge桥接层扩展的extension.js不直接执行skills而是启动一个本地Agent Runtime进程如node agent-runtime.js并通过IPC或HTTP与之通信// extension.js const { spawn } require(child_process); let agentProcess; function startAgentRuntime() { agentProcess spawn(node, [agent-runtime.js], { stdio: [pipe, pipe, pipe, ipc], env: { ...process.env, SKILLS_DIR: path.join(context.extensionPath, skills) } }); agentProcess.on(message, (data) { if (data.type SKILL_RESULT) { vscode.window.showInformationMessage(Skill ${data.skillName} completed); // 将result.testContent插入当前编辑器 const editor vscode.window.activeTextEditor; if (editor data.result.outputPath) { editor.edit(edit edit.insert(new vscode.Position(0,0), data.result.testContent)); } } }); }Layer 3Skills Registry技能注册中心agent-runtime.js负责管理skills生命周期// agent-runtime.js const { SkillsRegistry } require(ai-sdk/skills); const registry new SkillsRegistry({ skillsDir: process.env.SKILLS_DIR, sandboxOptions: { allowedFsPaths: [process.cwd()], allowedNetworkOrigins: [https://api.example.com] } }); // 监听来自VS Code的IPC消息 process.on(message, async (msg) { if (msg.type EXECUTE_SKILL) { try { const result await registry.execute(msg.skillName, msg.input); process.send({ type: SKILL_RESULT, skillName: msg.skillName, result }); } catch (error) { process.send({ type: SKILL_ERROR, skillName: msg.skillName, error: error.message }); } } });这样用户在VS Code中右键选择“Execute Skill” - “generateReactTest”扩展会获取当前打开的Button.tsx文件内容读取工作区根目录下的package.json解析devDependencies获取jest和testing-library/react版本构造input对象发送给Agent RuntimeAgent Runtime加载generateReactTestskill执行AST分析生成测试代码将testContent返回扩展自动在新标签页中打开Button.test.tsx并插入内容注意VS Code扩展的webview无法直接调用Node.js API所以必须通过spawn子进程启动独立的Agent Runtime。这是性能与安全的必要妥协。4.2 在前端应用中嵌入skills构建“超级能力”按钮skills不仅用于开发工具更是前端应用的“超能力引擎”。例如在一个内部CRM系统中添加一个“生成客户分析报告”按钮背后是skills的组合调用// CRMReportButton.tsx import { useAgent } from ai-sdk/react; export default function CRMReportButton() { const { execute, isExecuting } useAgent(); const handleGenerateReport async () { // Step 1: 调用skills获取客户数据 const customerData await execute(fetchCustomerData, { customerId: cust_123, includeInteractions: true }); // Step 2: 调用skills进行数据分析 const analysisResult await execute(analyzeCustomerBehavior, { rawData: customerData, timeRange: last_90_days }); // Step 3: 调用skills生成PDF报告 const pdfUrl await execute(generatePdfReport, { title: Customer Report for ${customerData.name}, content: analysisResult.summary, charts: analysisResult.charts }); // Step 4: 触发浏览器下载 window.open(pdfUrl, _blank); }; return ( button onClick{handleGenerateReport} disabled{isExecuting} {isExecuting ? Generating... : Generate Report} /button ); }这里的关键是useAgentHook它封装了与后端Agent Runtime的WebSocket连接、skills调用序列管理、错误重试、进度反馈。用户点击按钮前端不发送任何业务逻辑代码到服务端而是发送一个skills调用计划Plan后端Runtime负责解析、调度、执行、聚合结果。这实现了前端逻辑的极大简化所有复杂的数据处理、报表生成都下沉到skills层。4.3 权限与安全如何防止skills成为新的攻击面skills的便利性伴随巨大安全责任。unfortunately, claude is not available to new users right now这类错误常源于skills滥用导致的API配额超限或安全策略触发。必须实施四层防护1. 调用白名单Call WhitelistAgent Runtime必须配置allowedSkills列表禁止执行未注册的skills。生产环境严禁使用*通配符。// runtime-config.ts export const runtimeConfig { allowedSkills: [ fetchCustomerData, analyzeCustomerBehavior, generatePdfReport, sendEmailNotification ], // 禁止执行任意shell命令的skills blockedSkills: [execShellCommand, runPythonScript] };2. 输入长度与复杂度限制防止DoS攻击对inputJSON大小、嵌套深度、字符串长度设硬限制// input-validator.ts export function validateInput(input: any, schema: JSONSchema): boolean { if (JSON.stringify(input).length 1024 * 100) { // 100KB上限 throw new Error(Input too large); } if (getNestingDepth(input) 10) { throw new Error(Input nesting too deep); } return ajv.validate(schema, input); }3. 输出内容过滤Output Sanitizationskills的output可能包含用户敏感数据如数据库连接字符串、API密钥必须在返回前过滤// output-sanitizer.ts export function sanitizeOutput(output: any): any { const sensitiveKeys [password, apiKey, token, secret]; return JSON.parse(JSON.stringify(output), (key, value) { if (sensitiveKeys.some(k key.toLowerCase().includes(k))) { return [REDACTED]; } return value; }); }4. 执行超时与内存限制为每个skills调用设置timeoutMs和maxMemoryMB超限则强制终止// sandbox-executor.ts export async function executeInSandbox( skill: Skill, input: any, timeoutMs: number 5000, maxMemoryMB: number 100 ) { const controller new AbortController(); const timeout setTimeout(() controller.abort(), timeoutMs); try { const result await Promise.race([ skill.execute(input), new Promise((_, reject) setTimeout(() reject(new Error(Skill execution timeout)), timeoutMs) ) ]); // 检查内存使用需Node.js 18.17.0 const memoryUsage process.memoryUsage(); if (memoryUsage.heapUsed maxMemoryMB * 1024 * 1024) { throw new Error(Skill exceeded memory limit); } return result; } finally { clearTimeout(timeout); } }实操心得我们曾在线上环境遭遇一个恶意skills它在execute函数中启动无限循环while(true) { i }导致Agent Runtime进程CPU 100%。加入timeoutMs和maxMemoryMB后该skills在5秒后被强制终止系统恢复正常。安全不是锦上添花而是生死线。5. 常见问题与排查技巧实录5.1 “npx skill add 报错command not found” —— npx本身未安装这是新手最常见的拦路虎。npx是npm 5.2.0自带的命令但很多系统尤其是macOS通过Homebrew安装的Node.js默认不包含npm或npm版本过旧。排查步骤检查npm版本npm --version低于5.2.0需升级npm install -g npmlatest检查npx是否存在which npx若返回空则说明npm未正确安装重新安装Node.js推荐使用 nvm 管理nvm install --lts会同时安装最新LTS版Node.js和配套npm/npx终极解决方案# 不依赖npx直接用npm执行 npm install -g skill-package-name # 然后手动注册到Agent Runtime echo {name:skill-name,path:$(npm root -g)/skill-package-name} ~/.agent/skills.json5.2 “Agent execution terminated due to error.” —— skills执行崩溃的黄金排查法这条模糊错误信息背后可能是AST解析失败、WASM内存越界、或Python GIL死锁。我的标准排查流程Step 1开启详细日志在Agent Runtime启动时添加--log-level debugnode agent-runtime.js --log-level debug日志中会显示具体哪个skills、在哪个文件、第几行崩溃。Step 2复现并捕获堆栈在skills的execute函数最外层加try/catch并打印完整错误execute: async (input) { try { // 原有逻辑 } catch (error) { console.error(SKILL CRASH:, { skillName: generateReactTest, inputHash: createHash(sha256).update(JSON.stringify(input)).digest(hex), stack: error.stack, message: error.message }); throw error; // 重新抛出让Runtime捕获 } }Step 3隔离测试创建最小复现案例# 创建测试目录 mkdir /tmp/skill-test cd /tmp/skill-test # 复制skills代码 cp ~/my-project/skills/generateReactTest/* . # 手动执行绕过Agent Runtime node -e const { generateReactTest } require(./index); generateReactTest.execute({ componentSource: \import React from react; export default function Button() { return buttonClick/button; }\, componentPath: Button.tsx, projectConfig: { jestVersion: 29, rtlVersion: 14, hasJestDom: true } }).then(console.log).catch(console.error); 如果在此环境下仍崩溃问题100%在skills代码如果正常则是Agent Runtime的沙箱或上下文问题。5.3 “process exited with code 3221225477” —— Windows专属内存违规详解这个0xc0000005错误是Windows的STATUS_ACCESS_VIOLATION意味着skills尝试访问了非法内存地址。在skills场景下99%的原因是使用了不兼容的Native Addon如sqlite3、canvas等C编写的npm包在WASM或受限Node.js环境中无法加载。递归过深导致栈溢出Babel AST遍历中未设置maxDepth遇到超长嵌套JSON时栈爆炸。Buffer操作越界buffer.slice(100, 200)但buffer长度只有50。解决方案检查skills的dependencies移除所有node-gyp编译的包。在AST遍历中添加深度限制traverse(ast, { enter(path) { if (path.key 1000) { // 防止无限递归 throw new Error(AST traversal depth exceeded); } } });所有Buffer操作前加长度校验if (start 0 end buffer.length start end) { return buffer.slice(start, end); } else { throw new Error(Buffer slice out of bounds); }5.4 “skills如何调用MCP工具” —— MCPModel Context Protocol集成指南MCP是新兴的AI工具调用协议skills与MCP的集成是未来趋势。核心在于将skills的inputSchema和outputSchema映射为MCP的tool定义// MCP tool definition generated from skills manifest { name: generateReactTest, description: Generate Jest test file for a React component, input_schema: { type: object, properties: { componentSource: { type: string }, componentPath: { type: string } } } }在Agent Runtime中需实现MCP的tool_call处理器// mcp-handler.ts export async function handleToolCall(toolName: string, toolInput: any) { if (toolName generateReactTest) { // 将MCP toolInput转换为skills input const skillsInput { componentSource: toolInput.componentSource, componentPath: toolInput.componentPath, projectConfig: await detectProjectConfig() // 自动探测 }; return await registry.execute(generateReactTest, skillsInput); } throw new Error(Unknown tool: ${toolName}); }这样任何支持MCP