ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

CopilotKit 的 mcp-use 开发基石:掌握 MCP 四大原语(Tool / Resource / Prompt / Widget)

2026/9/11 8:10:33 拓冰建站 浏览量
CopilotKit 的 mcp-use 开发基石:掌握 MCP 四大原语(Tool / Resource / Prompt / Widget) CopilotKit 的 mcp-use 开发基石掌握 MCP 四大原语Tool / Resource / Prompt / Widget【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit导读本文以 CopilotKit 仓库中mcp-apps-builder技能包的 foundations/concepts 文档为主线系统讲解用mcp-use框架构建 MCPModel Context Protocol服务器时最核心的四种原语Tool工具、Resource资源、Prompt提示词模板和 Widget带 UI 的工具。你将学会如何为每一种场景挑选正确的原语、如何用决策矩阵在四者之间做取舍以及如何避免exposeAsTool、惰性加载、状态归属等典型陷阱。文中所有示例均可在仓库内对应的完整参考文档与真实源码中找到依据读完即可直接用于搭建自己的 MCP 服务器。为什么先理解原语在 MCPModel Context Protocol协议中服务器向 AI 客户端暴露的能力被抽象为有限的几种原语。mcp-use框架把这些协议能力封装成了几个等价的 TypeScript 方法server.tool()—— 后端动作server.resource()—— 只读数据server.prompt()—— 可复用消息模板Widgetwidget —— 带视觉界面的工具在动手写任何 MCP 服务器之前先明确我要暴露的是哪种能力可以避免写出语义混乱、难以被 AI 正确调用的服务器。参考文档 concepts.md 开篇即指出这些原语就是构建 mcp-use 服务器时你将反复使用的基本积木。四大原语详解1. Tool工具AI 可调用的后端动作定义Tool 是 AI 可以调用的后端动作接收输入、返回输出。它适合承载动作、操作、变更类逻辑和 API 调用。server.tool({ name, description, schema }, async (input) { // Your logic here return text(result); });适用场景发送邮件、创建用户、拉取数据等一切有副作用或有计算逻辑的动作。纵深解读从 tools.md 可以看出一个完整的 Tool 定义远不止name/description/schema三项还包括annotations声明工具性质让客户端可以对用户做出风险提示。例如destructiveHint: true表示会删除/覆盖数据客户端可能要求用户二次确认readOnlyHint: true表示无副作用可安全重复调用openWorldHint: true表示会调用用户控制范围之外的外部 API。ctx第二参数提供高级能力包括ctx.reportProgress(current, total, message)上报进度、ctx.log(level, message, data?)结构化日志、ctx.sample(prompt)请求 LLM 协助分析需客户端支持sampling能力可用ctx.client.can(sampling)探测。outputSchema对工具输出做运行时校验适合多条代码路径返回不同结构、或需要保证输出一致性的场景。错误处理规范明确要求用error()帮助函数优雅失败不要 throw 异常并建议在 catch 中记录日志后返回error(message)。性能模式对昂贵的操作建议加 TTL 缓存限流需使用 Hono 兼容中间件如hono-rate-limiter因为 mcp-use 底层构建在 Hono 之上Express 中间件如express-rate-limit不兼容。2. Resource资源客户端可拉取的只读数据定义Resource 是只读数据客户端可以直接获取通常不带输入参数需要参数时使用资源模板 resource template。它适合承载配置、静态数据、文档、列表类内容。server.resource({ uri, name, mimeType }, async () { return object({ data }); });纵深解读根据 resources.md 的详细说明URI 规范推荐使用 scheme 前缀来组织资源例如config://settings、docs://user-guide、data://available-cities、state://current-user。不要使用无 scheme 的裸字符串也不要占用保留的http://。元信息name是机器可读标识kebab-casetitle是展示给用户的可读名称description可选但推荐mimeType指示内容格式JSON 对应application/json、Markdown 对应text/markdown、图片对应image/png等。静态 vs 动态静态资源返回固定数据动态资源在请求时实时计算如当前在线会话数、服务器 uptime适合数据随时间变化计算昂贵按需计算反映服务器当前状态的场景。资源模板当需要参数时使用server.resourceTemplate()URI 中用{param}单个路径段或{param*}贪婪匹配多个路径段占位。处理函数签名是async (uri: URL, params: Recordstring, string)官方建议在函数体内显式提取参数而非直接解构params以避免 TypeScript 类型匹配问题。自动补全通过callbacks.complete为模板变量提供静态建议列表或动态回调建议客户端经由 MCP 的completion/complete请求获取。组织与缓存按 URI scheme 归类资源有助于客户端在列出资源时发现由于资源只读缓存收益明显如对昂贵计算加 10 分钟 TTL 缓存。3. Prompt提示词带参数的可复用消息模板定义Prompt 是可复用的消息模板带参数。它适合承载通用提示词、指令模板类内容。server.prompt({ name, description, schema }, async (input) { return text(Your prompt template with ${input.param}); });纵深解读prompts.md 给出了丰富的实战模式命名与描述使用 kebab-case 描述性命名如code-review、summarize-document、translate-text描述要说明模板能做什么而非简单名词。参数 Schema所有字段都用.describe()描述尽量用z.enum()约束取值、.optional()标记非必填、.default()提供默认值。常见模式代码评审、摘要生成、翻译、概念讲解、多步骤重构指导按激进/温和/保守策略生成步骤、带环境上下文的优化建议node/browser/edge/serverless。Markdown 长模板结构化长提示词使用markdown()返回可包含标题、清单、编号步骤。参数自动补全用completable(schema, values)静态列表自动前缀匹配或completable(schema, callback)动态回调接收(value, ctx)可通过ctx.arguments读取其他字段值做上下文相关建议。Prompt vs Tool 的分界线Prompt 只提供指令无后端逻辑Tool 执行动作、调用 API/数据库、有副作用。典型反例是用 tool 跑 linter执行动作与用 prompt 生成代码评审指令纯模板的区分。4. WidgetWidget Tool返回视觉 UI 的工具定义Widget 是返回可视化 UI 的工具与普通 Tool 相同但会渲染一个 React 组件。它适合浏览数据、交互式选择、需要视觉反馈的场景。server.tool({ name, schema, widget: { name: widget-name } }, async (input) widget({ props: { data }, output: text(...) }), );纵深解读Widget 是这套原语体系中信息量最大的一类参考 widgets/basics.md实现三要素(1) 在工具配置中声明widget: { name }(2) 处理函数返回widget({ props, output })(3) 在resources/目录创建同名组件文件如resources/{name}.tsx。widgetMetadata每个组件须导出widgetMetadata包含description展示什么、propsZod schema 定义 props 结构、可选的metadata.invoking/invoked加载中/完成时的状态文案会同步到工具元数据与metadata.cspCSP 允许连接的域名。useWidget()Hook提供props来自工具响应的数据、isPendingprops 是否加载中、state/setStatewidget 内部状态。关键点Widget 会在工具执行完成前就挂载渲染——首次渲染时isPending true、props {}因此访问props字段前必须先检查isPending。McpUseProvider autoSize所有组件包括 loading 分支的根节点都必须包裹它提供上下文并处理 iframe 尺寸autoSize{true}自动适配内容高度。类型安全四步法先单独定义propsSchema常量 → 在widgetMetadata.props中引用该变量不要内联z.object()→type Props z.infertypeof propsSchema→useWidgetProps()。否则 TypeScript 会丢失类型信息props退化为unknown。从 widget 内调用工具使用专用的useCallTool()Hook见 interactivity.md。决策矩阵什么时候用哪种原语当你不确定该用哪一种时直接对照这张决策表需求使用示例后端动作Toolsend-email、create-user、fetch-data只读数据Resourceconfig、user-profile、api-docs提示词模板Promptcode-review、summarize、translate视觉 UIWidget Toolsearch-results、calendar、dashboard判断要点有副作用或需要结构化输入校验的动作选 Tool纯只读、可能被浏览/枚举的数据选 Resource只提供指令、无后端逻辑的选 Prompt需要可视化展示与交互的选 Widget。Tool 还是 Widget一条经验法则当输出是简单文本或数据、没有可视化表达的价值、只需快速对话式响应时使用普通 Tool不带 widget。当需要浏览/比较多个条目、可视化数据能显著提升理解图表、图片、可视化选择比文本操作更直观时使用 Widget。concepts.md 给出的态度非常明确拿不准的时候就用 Widget——它通常会带来更好的用户体验。四个关键设计模式模式一一个工具 一个能力❌manage-users过于宽泛✅create-user、delete-user、list-users把宽泛的管理用户拆成语义单一、边界清晰的工具AI 才能准确判断何时调用哪一个。模式二不要惰性加载工具调用是昂贵的一轮模型推理 网络往返。应该在一次调用中返回全部所需数据❌list-productsget-product-details两次调用✅list-products直接返回含明细的完整数据模式三Widget 自己管理自己的状态UI 状态选中项、筛选条件应放在 Widget 内部通过useState或setState维护❌ 专门定义select-item、set-filter这样的工具✅ 由 Widget 内部自行管理这条模式与 SKILL.md 中的Golden Rules一致不要在 widget 中用工具模拟前端状态这会显著增加交互延迟并让服务器承载本属于前端的逻辑。模式四exposeAsTool默认是falseWidget 默认不会被自动注册为工具。当通过自定义工具 widget: { name }的模式暴露 Widget 时省略exposeAsTool或保持false才是正确的——注册工作由那个自定义工具完成避免重复注册export const widgetMetadata: WidgetMetadata { description: ..., props: z.object({...}), // exposeAsTool defaults to false — correct for custom-tool pattern };只有当你想让 Widget 以资源身份被 AI 自动发现并调用时才显式设置exposeAsTool: true。仓库内的完整落地示例concepts.md 中的抽象概念在仓库里有非常具体的实现mcp-use-server应用中的 tools/product-search.ts 完整演示了自定义工具 Widget这一核心模式server.tool( { name: search-tools, description: Search for fruits and display the results in a visual widget, schema: z.object({ query: z.string().optional().describe(Search query to filter fruits), }), widget: { name: product-search-result, // 必须与 resources/ 下的目录名一致 invoking: Searching..., invoked: Results loaded, }, _meta: { // 尚未发生真实调用时MCP UI Studio 中展示的预览数据 ui/previewData: { ... }, }, }, async ({ query }) { const results fruits.filter(...); await new Promise((resolve) setTimeout(resolve, 2000)); // 模拟网络延迟展示加载态 return widget({ props: { query: query ?? , results }, output: text(Found ${results.length} fruits matching ${query ?? all}), }); }, );这段源码印证了 concepts.md 中的多个要点Tool 配置name/description/schema三段式定义query字段带.describe()Widget 声明widget.name与resources/下的目录名严格对应注释明确指出 must match the folder name under resources/加载状态用 2 秒延迟模拟真实网络请求配合invoking/invoked文案让 Widget 展示完整的加载态与完成态纯数据工具伴生同一文件还注册了get-fruit-details数据工具供 Widget 内部通过useCallTool()调用体现一个工具 一个能力的拆分思想。一次完整的构建路径从脚手架到产出为了让上述原语真正落到可运行的服务器上concepts.md 的 Next Steps 指向了完整的入门流程脚手架npx create-mcp-use-app my-server创建项目默认starter模板widget 优先场景推荐--template mcp-apps从零开始用--template blank还支持--template owner/repo拉取 GitHub 社区模板。常用 flag 有--npm/--pnpm选择包管理器、--install --skills跳过交互提示、--list-templates列出所有模板。详见 quickstart.md。开发循环npm run dev启动带热重载的服务器访问http://localhost:3000/inspector打开 MCP Inspector 调试在index.ts中添加 tools/resources/promptswidget 组件以.tsx文件放入resources/生产构建用npm run build发布用npm run deploy。质量检查SKILL.md 中的安全清单与常见错误清单可作为提交前的自查项——所有 schema 字段是否有.describe()、输入是否经 Zod 校验、API 密钥是否走环境变量、错误是否用error()返回、破坏性操作是否设置destructiveHint: true、widget 是否检查isPending并包裹McpUseProvider等。总结一条可复用的判断链把本文内容压缩成一条工作流先问场景是动作→ Tool、只读数据→ Resource、指令模板→ Prompt还是可视化交互→ Widget再看约束需要参数就考虑 Resource Template / Prompt schema需要视觉就优先 Widget拿不准就选 Widget。最后套模式一个工具只做一个能力一次调用返回完整数据UI 状态留在 Widget 内部自定义工具 Widget 时保持exposeAsTool为false。mcp-apps-builder技能包把 mcp-use 的这套最佳实践沉淀为可直接遵循的参考手册。深入阅读 tools.md、resources.md、prompts.md、widgets/basics.md 四份细分文档再对照 product-search.ts 这份真实实现就能把四大原语从概念变成肌肉记忆。【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考