尧图精选

MCP Everything Server 扩展指南:Tools、Prompts、Resources 三类扩展点的注册机制与实战方法

🕒 发布时间:2026/9/4 14:14:20 📁 来源:尧图网络
MCP Everything Server 扩展指南Tools、Prompts、Resources 三类扩展点的注册机制与实战方法【免费下载链接】serversModel Context Protocol Servers项目地址: https://gitcode.com/GitHub_Trending/se/serversEverything Server 是 Model Context ProtocolMCP官方 servers 仓库中用于演示协议全部核心能力的参考实现。本文基于该服务器的扩展点文档 extension.md结合 tools/、prompts/、resources/ 目录下的真实源码完整讲清「新增一个 Tool / Prompt / Resource」的三步扩展流程文件放在哪、注册函数怎么写、如何挂进中央 index。读完后你可以按照仓库既有约定独立为自己的 Everything Server 副本添加任意 MCP 原语并理解各扩展点在服务器生命周期中的注册时机差异。扩展点总览三段式注册与服务器工厂extension 文档给出的扩展模式高度一致三类原语各自对应一个目录和一个中央编排函数原语类型文件目录注册函数中央编排index.tsToolsrc/everything/tools/registerXTool(server)registerTools(server)Promptsrc/everything/prompts/registerXPrompt(server)registerPrompts(server)Resourcesrc/everything/resources/registerXResources(server)registerResources(server)这三个编排函数并不是各自散落的它们统一由服务器工厂 createServer() 按固定顺序调用先registerTools(server)再registerResources(server)然后registerPrompts(server)最后setSubscriptionHandlers(server)挂载资源订阅处理器。也就是说只要你的模块被某个中央 index 调用就会在McpServer实例创建后的同一启动路径上完成注册无需改动任何 transport 代码。值得注意的生命周期细节是工厂在创建McpServer时声明了tools.listChanged、prompts.listChanged、resources.subscribe / listChanged等能力并在server.server.oninitialized钩子中补注册了一批「依赖客户端能力」的条件工具见 server/index.ts。这解释了为什么工具注册被拆成了两个入口后文「工具扩展」一节会展开。完整的目录职责划分可参考 structure.md它逐文件说明了tools/、prompts/、resources/中每个模块的功能是扩展新模块前最好的对照手册。添加 Tool文件约定、注册与条件注册extension 文档对 Tool 扩展的完整要求只有两条在tools/下新建文件导出registerXTool(server)函数内部通过server.registerTool(...)完成注册在 tools/index.ts 的registerTools(server)中导出并调用它。以仓库中最典型的 echo.ts 为例一个完整的工具模块由四部分组成import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { CallToolResult } from modelcontextprotocol/sdk/types.js; import { z } from zod; // 1. 输入参数 SchemaZod用于运行时校验 export const EchoSchema z.object({ message: z.string().describe(Message to echo), }); // 2. 工具名称与配置title、description、inputSchema、annotations const name echo; const config { title: Echo Tool, description: Echoes back the input string, inputSchema: EchoSchema, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }; // 3. 注册函数签名固定为 (server: McpServer) void export const registerEchoTool (server: McpServer) { server.registerTool(name, config, async (args): PromiseCallToolResult { const validatedArgs EchoSchema.parse(args); // 4. 处理器内先校验再执行 return { content: [{ type: text, text: Echo: ${validatedArgs.message} }], }; }); };这里有几个在扩展新工具时必须遵循的要点处理器是「校验 执行」两段式EchoSchema.parse(args)先按 Zod schema 校验入参再产出CallToolResult。get-sum.ts 演示了多参数版本——a、b两个数值入参求和返回The sum of a and b is X.的文本内容。annotations 四元组是该服务器的统一惯例从源码结构看tools/index.ts 中注册的每个工具都携带readOnlyHint、destructiveHint、idempotentHint、openWorldHint四个提示位新工具应保持一致AGENTS.md 明确要求所有工具包含工具级 annotations。挂接位置在tools/index.ts顶部import { registerEchoTool } from ./echo.js然后在registerTools函数体中按字母序附近的合理位置追加一行registerEchoTool(server);即完成接入。registerTools 与 registerConditionalTools 的区别tools/index.ts 里还导出第二个函数registerConditionalTools(server)用于注册依赖客户端能力的工具例如get-roots-list需要客户端声明 roots 能力trigger-elicitation-request/trigger-url-elicitation依赖 elicitationtrigger-sampling-request/trigger-sampling-request-async依赖客户端 LLM samplingsimulate-research-query及两个 async 工具依赖实验性 Tasks API。它们不能放进registerTools因为McpServer实例化时尚不知道客户端支持什么——server/index.ts 在oninitialized回调中调用registerConditionalTools(server)此时 initialize 交换已完成、客户端 capabilities 已知。因此扩展时的判断规则很明确你的工具若需要客户端侧能力roots、sampling、elicitation、tasks注册函数应挂到registerConditionalTools纯服务端工具挂到registerTools即可。添加 PromptregisterPrompt 与参数模式extension 文档对 Prompt 扩展的要求与 Tool 完全同构在prompts/下新建文件导出registerXPrompt(server)内部调用server.registerPrompt(...)再在 prompts/index.ts 的registerPrompts(server)中导出并调用。该目录提供了三档复杂度递进的示例正好覆盖了扩展时常见的参数场景。无参数 Promptsimple.ts 注册了simple-prompt处理器是无参函数直接返回固定消息server.registerPrompt( simple-prompt, { title: Simple Prompt, description: A prompt with no arguments, }, () ({ messages: [ { role: user, content: { type: text, text: This is a simple prompt without arguments. }, }, ], }) );带必填/可选参数 Promptargs.ts 的args-prompt演示了通过argsSchema声明参数city必填、state可选Zod.optional()处理器内按参数是否存在拼接最终文案Whats weather in {city}[, {state}]?。扩展自己的多参数 Prompt 时argsSchema中的每个字段都会暴露给客户端作为补全与校验依据describe()文案会直接呈现给用户务必写清语义。支持服务端补全的 Promptcompletions.ts 是最复杂的一档它用 SDK 的completable(...)辅助函数包裹 Zod 字段为department与name两个参数提供服务端补全并且第二个参数的候选列表依赖第一个参数的取值选择 Engineering 时补全 Alice/Bob/Charlie选择 Sales 时补全 David/Eve/Frank。这个模式展示了context.arguments的用法——补全回调可以读取同 Prompt 中其他参数当前值实现联动过滤。当你扩展的 Prompt 参数是枚举或依赖前置选择时这是可直接套用的模板。添加 ResourceregisterResource 与 ResourceTemplateextension 文档对 Resource 扩展的表述是在resources/下新建文件导出registerXResources(server)使用server.registerResource(...)注册可选搭配ResourceTemplate再在 resources/index.ts 的registerResources(server)中调用。当前的编排函数依次委托给registerResourceTemplates(server)与registerFileResources(server)新模块按同一模式追加即可。仓库中最完整的模板示例是 templates.ts 中的registerResourceTemplates它注册了两条动态资源模板server.registerResource( Dynamic Text Resource, new ResourceTemplate( demo://resource/dynamic/text/{resourceId}, { list: undefined, complete: { resourceId: resourceIdForResourceTemplateCompleter }, } ), { mimeType: text/plain, description: Plaintext dynamic resource fabricated from the {resourceId} variable, which must be an integer., }, async (uri, variables) { const resourceId parseResourceId(uri, variables); return { contents: [textResource(uri, resourceId)] }; } );其中几个关键设计值得在扩展时借鉴URI 模板变量与补全回调{resourceId}是模板变量配套的complete回调resourceIdForResourceTemplateCompleter只接受正整数非法输入返回空数组从而在客户端补全层面就把取值约束住内容生成器parseResourceId再做一次运行时校验双重防线。list: undefined的含义从源码注释看模板资源不出现在resources/list结果中只能通过模板 URI 访问——这是「动态、不可枚举」资源的正确表达。如果你的资源是可以枚举的静态集合则不应照抄这个选项。内容按需生成textResource/blobResource在每次读取时携带当前时间戳生成内容Blob 版本用Buffer.from(...).toString(base64)产出 Base64 负载mimeType 为application/octet-stream。跨模块复用templates.ts 还导出了textResource(uri, index)、textResourceUri(index)、blobResource/blobResourceUri四个辅助函数供prompts/resource.ts的resource-prompt直接嵌入动态资源——说明资源模块的构造函数与注册函数分开导出是便于其他原语复用的好实践。此外files.ts 演示了静态资源扩展把docs/目录下每个文件注册为demo://resource/static/document/filename形式markdown 文件映射为text/markdown.json映射为application/json。当你需要把一批固定文件暴露为资源时这是对应模板。注册时机、生命周期与能力声明把三类扩展放回 server/index.ts 的工厂视角可以看到扩展点与生命周期的完整关系能力声明new McpServer(...)的 options 中声明tools/prompts/resources三组能力的listChanged与resources.subscribe。你新增的原语若依赖某个尚未声明的能力例如让工具支持动态列表变更通知需要同步确认这里的能力位已打开。启动期注册registerTools→registerResources→registerPrompts→setSubscriptionHandlers全部发生在 transport 连接之前。初始化后补注册oninitialized中执行registerConditionalTools并延迟 350ms 触发syncRoots注释说明延迟是为了避免请求在 initialized 通知处理完成前丢失。会话清理工厂返回{ server, cleanup }transport 断开时调用cleanup(sessionId)停止模拟日志与资源更新定时器、清理任务存储。如果你的新工具引入了定时器或长任务按 AGENTS.md 的要求「为服务器关闭实现正确的清理」把停止逻辑纳入同样的清理路径。工程规范与验证方式扩展代码时AGENTS.md 列出了必须遵守的仓库约定其中与扩展直接相关的包括导入路径使用 ES Module 且带.js扩展名如import { registerEchoTool } from ./echo.js文件名、以及注册的工具/Prompt/资源名统一 kebab-case工具名用动词开头如get-annotated-message而非annotated-message工具输入一律走 Zod schema且描述要准确、有说明性变量/函数 camelCase类型 PascalCase常量 UPPER_CASE2 空格缩进。验证方面该服务器为每类原语都配备了对应的测试文件tests目录下的tools.test.ts、prompts.test.ts、resources.test.ts分别覆盖三类原语的行为registrations.test.ts则校验注册关系本身。扩展完成后用仓库既有的构建与运行命令即可端到端验证见 AGENTS.mdnpm run build # 编译 TypeScript 到 dist/并拷贝 docs/ npm run start:stdio # stdio transport 启动 npm run start:sse # SSE transport 启动 npm run start:streamableHttp # Streamable HTTP transport 启动启动后可通过客户端的tools/list、prompts/list、resources/list确认新原语已出现再逐个调用验证行为——模板类资源不会出现在resources/list中需直接按模板 URI 读取来验证。小结Everything Server 的扩展机制本质是一个「目录 注册函数 中央 index」的三段式约定新功能以独立文件存在、以registerX(server)统一签名暴露、在对应 index 的编排函数中一行接入其余能力声明与生命周期管理全部由 server/index.ts 的工厂统一承担。遵循这一约定并配合registerTools/registerConditionalTools的时机区分你就能在不触碰 transport 与工厂代码的前提下把任意 Tool、Prompt 或 Resource 干净地接入这台参考服务器。【免费下载链接】serversModel Context Protocol Servers项目地址: https://gitcode.com/GitHub_Trending/se/servers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →