MCP servers 仓库 Everything Server 项目结构详解:目录布局、模块职责与源码级实现导读
【免费下载链接】serversModel Context Protocol Servers项目地址: https://gitcode.com/GitHub_Trending/se/servers
本文基于src/everything/docs/structure.md这份官方结构文档展开,逐目录、逐文件地讲解 MCP "Everything" 参考服务器的项目组织方式:入口与传输选择、文档体系、prompts / resources / tools 三大原语的注册编排、server 工厂与 transport 层的落地实现。读完之后,你可以快速定位任意功能对应的源码文件,理解各模块之间的调用关系,并按照仓库既有模式为该服务器新增工具、资源、提示词或传输方式。
总体目录布局
structure.md首先给出了一份完整的目录树,这是理解整个 Everything Server 的骨架:
src/everything ├── index.ts ├── AGENTS.md ├── package.json ├── docs │ ├── architecture.md │ ├── extension.md │ ├── features.md │ ├── how-it-works.md │ ├── instructions.md │ ├── startup.md │ └── structure.md ├── prompts │ ├── index.ts │ ├── args.ts │ ├── completions.ts │ ├── simple.ts │ └── resource.ts ├── resources │ ├── index.ts │ ├── files.ts │ ├── session.ts │ ├── subscriptions.ts │ └── templates.ts ├── server │ ├── index.ts │ ├── logging.ts │ └── roots.ts ├── tools │ ├── index.ts │ ├── echo.ts │ ├── get-annotated-message.ts │ ├── get-env.ts │ ├── get-resource-links.ts │ ├── get-resource-reference.ts │ ├── get-roots-list.ts │ ├── get-structured-content.ts │ ├── get-sum.ts │ ├── get-tiny-image.ts │ ├── gzip-file-as-resource.ts │ ├── simulate-research-query.ts │ ├── toggle-simulated-logging.ts │ ├── toggle-subscriber-updates.ts │ ├── trigger-elicitation-request.ts │ ├── trigger-elicitation-request-async.ts │ ├── trigger-long-running-operation.ts │ ├── trigger-sampling-request.ts │ ├── trigger-sampling-request-async.ts │ └── trigger-url-elicitation.ts └── transports ├── sse.ts ├── stdio.ts └── streamableHttp.ts从目录树可以清楚看到分层思路:prompts/、resources/、tools/分别承载 MCP 协议三大原语,每个目录内部都是"一个index.ts编排器 + 每个功能一个文件"的模式;server/负责组装服务器实例;transports/负责三种通信方式(stdio、SSE、Streamable HTTP);docs/则是随构建一起打包进发行产物的文档集。同一套文档导航中还包括 架构说明、扩展指南、功能清单、工作原理 与 启动流程,结构文档与它们互为补充。
入口层:index.ts、AGENTS.md 与 package.json
index.ts:基于第一个 CLI 参数选择传输
index.ts 是整个服务器的启动入口,逻辑非常克制:
- 读取
process.argv,取第一个参数作为传输名,缺省为stdio; - 通过
switch分支动态import对应的传输模块(./transports/stdio.js、./transports/sse.js、./transports/streamableHttp.js),从而保证只有被请求的传输模块会被加载和执行,避免其他模块在未被使用时就完成初始化; - 遇到未知参数时打印使用说明(
node ./index.js [stdio|sse|streamableHttp])并以退出码 1 结束。
对应到 npm scripts 上,就是 package.json 中的三个启动命令:
"start:stdio": "node dist/index.js stdio", "start:sse": "node dist/index.js sse", "start:streamableHttp": "node dist/index.js streamableHttp"AGENTS.md:面向 Agent 的编码规范
AGENTS.md 是写给 Agent / LLM 的开发者指南,规定了构建与运行命令、代码风格(ES 模块 +.js导入后缀、严格类型、zod schema 校验、2 空格缩进、camelCase / PascalCase / kebab-case 的命名约定等),以及扩展服务器的规则:新工具、资源、提示词分别放在对应目录,导出registerX(server)函数,再接入中心index.ts编排。它相当于把"如何正确地扩展这个服务器"固化成了可被机器读取的约束。
package.json:元数据、脚本与依赖
package.json 声明了包名@modelcontextprotocol/server-everything(当前版本 2.0.0),bin字段将dist/index.js暴露为mcp-server-everything可执行命令,files只发布dist目录。关键脚本为:
"build": "tsc && shx cp -r docs dist/ && shx chmod +x dist/*.js", "watch": "tsc --watch", "test": "vitest run --coverage"build脚本做了三件事:TypeScript 编译到dist/、把docs/原样复制到dist/(这就是server/index.ts启动时能读到instructions.md的前提)、标记编译后的入口脚本可执行。依赖方面,运行时依赖@modelcontextprotocol/sdk、express、cors、zod、jszip;开发依赖含typescript、vitest、prettier、shx。
docs/ 文档体系
docs/目录在结构文档中被逐一列出,每个文件承担明确职责:
| 文件 | 职责 |
|---|---|
| architecture.md | 描述服务器架构:传输层、会话初始化、原语注册 |
| extension.md | 讲解如何扩展新工具、提示词、资源或传输 |
| features.md | 完整的功能参考:所有 prompts、resources、tools 与协议行为 |
| how-it-works.md | SSE 与 Streamable HTTP 传输的搭建方式与 session 管理 |
| instructions.md | 人类可读的使用指引,启动时被服务器读取并在 initialize 交互中返回给客户端 |
| startup.md | 启动时序、环境检查与初始化 |
| structure.md | 即本文所依据的结构文档 |
其中instructions.md有特殊的运行时身份:readInstructions()会在服务器创建时把它读入内存。从 resources/index.ts 的readInstructions实现可以看到,它按相对路径docs/instructions.md读取文件,读取失败时返回一条错误说明字符串而不是抛异常——这解释了为什么构建脚本必须把docs/复制到dist/中一起发布。
prompts/ 提示词目录
prompts/的 index.ts 提供registerPrompts(server)编排函数,把注册工作委托给各个提示词文件:
simple.ts:注册simple-prompt,无参数,返回单条用户消息;args.ts:注册args-prompt,带两个参数(city必填、state可选),用于演示参数化消息拼装;completions.ts:注册completable-prompt,参数使用 SDK 的completable(...)助手支持服务器驱动的补全(如department以及上下文相关的name补全);resource.ts:导出registerEmbeddedResourcePrompt(server),注册resource-prompt——接受resourceType("Text" 或 "Blob")与resourceId(整数),在返回消息中嵌入一个动态生成的指定类型资源。它内部直接复用resources/templates.ts暴露的构造函数,是"资源与提示词跨模块协作"的典型示例。
resources/ 资源目录
resources/实际包含五个文件,index.ts 中的编排器只做两件事:
export const registerResources = (server: McpServer) => { registerResourceTemplates(server); registerFileResources(server); };templates.ts:两个动态模板资源
templates.ts 通过ResourceTemplate注册两个模板驱动的动态资源:
- 文本:
demo://resource/dynamic/text/{resourceId}(MIMEtext/plain) - 二进制:
demo://resource/dynamic/blob/{resourceId}(MIMEapplication/octet-stream,Base64 载荷)
结构文档称该路径变量为{index},其约束是必须为有限的正整数;源码中的parseResourceId(templates.ts)正是这样校验的——非正整数或未知 URI 会抛出Unknown resource错误。内容在请求时才生成,并带当前时间戳。此外还注册了resourceId的模板补全函数,只接受正整数字符串。
该文件还对外暴露四个辅助函数,供其他模块(尤其是resource-prompt)直接构造动态资源:
textResource(uri, resourceId) // 生成文本型动态资源 textResourceUri(resourceId) // 生成 demo://resource/dynamic/text/{id} blobResource(uri, resourceId) // 生成 Blob 型动态资源 blobResourceUri(resourceId) // 生成 demo://resource/dynamic/blob/{id}files.ts:静态文件资源
files.ts为docs/目录下每个文件注册一个静态资源,URI 遵循demo://resource/static/document/<filename>模式;MIME 类型按扩展名映射:.md→text/markdown、.txt→text/plain、.json→application/json,其余默认text/plain。
session.ts与subscriptions.ts
结构文档对这两个文件的描述较简略,但它们承担会话级能力:
session.ts:提供按会话注册/查找临时资源的机制。gzip-file-as-resource工具就用它把压缩后的 Blob 注册为会话资源,URI 形如demo://resource/session/<name>、mimeType: application/gzip,生命周期仅限当前会话;subscriptions.ts:server/index.ts 从这里导入setSubscriptionHandlers与stopSimulatedResourceUpdates,前者为服务器挂接资源订阅处理,后者在会话清理时停止模拟的资源更新检查(配合toggle-subscriber-updates工具触发)。
server/ 服务器组装
index.ts:服务器工厂
server/index.ts 导出createServer()工厂函数,返回{ server, cleanup }:
- 通过
readInstructions()载入服务器指令; - 创建
InMemoryTaskStore与InMemoryTaskMessageQueue,以支持实验性 Tasks 能力; - 构造
McpServer,声明能力包括tools.listChanged、prompts.listChanged、resources.subscribe/listChanged、logging,以及tasks(list、cancel 与tools.call请求); - 依次调用
registerTools(server)、registerResources(server)、registerPrompts(server),再挂接setSubscriptionHandlers(server); - 注册
oninitialized钩子:在客户端能力已知后注册条件工具(见下文 tools 一节),并在 350ms 延迟后调用syncRoots同步 roots(注释说明延迟是为了避免在notifications/initialized处理完成前发出请求导致丢失,见 server/index.ts); cleanup(sessionId)负责会话结束时的收尾:停止模拟日志(stopSimulatedLogging)、停止模拟资源更新、清理 task store 定时器、清除初始化超时。
传输层在客户端断开时调用cleanup(),这是"服务器状态与传输生命周期解耦"的关键设计。
logging.ts与roots.ts
logging.ts:实现模拟日志——按随机间隔向客户端会话发送不同级别的日志消息,由toggle-simulated-logging工具按需启停;roots.ts:提供syncRoots,在初始化后向客户端请求 roots 列表并缓存,供get-roots-list工具返回"客户端最近一次发送的 roots"。
tools/ 工具目录:两级注册机制
结构文档将tools/index.ts描述为registerTools(server)编排器。深入 tools/index.ts 源码可以看到,实际存在两级注册:
export const registerTools = (server: McpServer) => { registerEchoTool(server); registerGetAnnotatedMessageTool(server); // ... 共 13 个无条件工具 }; export const registerConditionalTools = (server: McpServer) => { registerGetRootsListTool(server); registerTriggerElicitationRequestTool(server); // ... 其余依赖客户端能力的工具 };第一级在createServer()中立即执行,注册与客户端能力无关的工具;第二级registerConditionalTools在server.server.oninitialized中执行,因为roots、elicitation、sampling、Tasks 等工具依赖客户端在 initialize 阶段声明的能力。这一分层在 server/index.ts 中有对应调用,是理解该服务器启动时序的重要细节。
各工具的职责(沿用结构文档描述,并对照源码印证):
echo.ts:接收消息并返回Echo: {message};get-annotated-message.ts:演示内容级注解——按messageType("error" | "success" | "debug")输出带priority、audience注解的主文本消息,includeImage为 true 时附带一张小型 PNG 图片;该服务器所有工具均带工具级注解(readOnlyHint、destructiveHint、idempotentHint、openWorldHint);get-env.ts:以格式化 JSON 返回当前进程环境变量,便于调试配置;get-resource-links.ts:返回一段引导text块加多个resource_link项;get-resource-reference.ts:返回选定动态资源的引用;get-roots-list.ts:返回客户端最近一次发送的 roots 列表;get-structured-content.ts:演示structuredContent结构化响应;get-sum.ts:Zod 输入 schema,求a、b之和;get-tiny-image.ts:返回一张小型 PNG(MCP 徽标)image内容及说明文本;trigger-long-running-operation.ts:按duration(秒)与steps数模拟长时任务,客户端提供progressToken时发送notifications/progress进度通知;toggle-simulated-logging.ts/toggle-subscriber-updates.ts:分别启停当前会话的模拟日志与模拟资源订阅更新检查;trigger-elicitation-request.ts:向客户端/LLM 发起elicitation/create并返回结果;trigger-elicitation-request-async.ts:演示双向 Tasks——带任务元数据发起 elicitation 请求,随后轮询客户端tasks/get端点获取完成状态再取最终结果;trigger-sampling-request.ts/trigger-sampling-request-async.ts:同步与基于双向任务的sampling/createMessage请求演示;trigger-url-elicitation.ts:发送带外 URL 模式(mode: "url",含elicitationId请求路径)的 elicitation 请求,或抛出UrlElicitationRequiredError(错误码-32042)走客户端处理路径;错误路径携带的前置 elicitation 指向不同 URL(https://modelcontextprotocol.io),客户端满足后重试同一调用时忽略errorPath改走请求路径,避免客户端在同一错误上死循环;simulate-research-query.ts:基于 MCP Tasks(SEP-1686)的任务型工具,模拟带进度更新的多阶段研究操作;当查询被标记为含糊且客户端支持 elicitation 时,会在执行中途暂停并通过elicitation/create请求澄清,使用server.experimental.tasks.registerToolTask()且execution: { taskSupport: "required" };gzip-file-as-resource.ts:抓取 URL 或 data URI 内容并 gzip 压缩,默认返回指向会话级资源的resource_link,也可返回内联resource(含 gzip 数据);该会话资源在会话期间可通过resources/list发现。它受三个环境变量控制:GZIP_MAX_FETCH_SIZE(字节,默认 10 MiB)GZIP_MAX_FETCH_TIME_MILLIS(毫秒,默认 30000)GZIP_ALLOWED_DOMAINS(逗号分隔的域名白名单;留空表示允许所有域名)
transports/ 传输目录
三种传输模块各自是一个可独立执行的 Express/Node 入口:
stdio.ts
启动StdioServerTransport,通过createServer()创建服务器并连接;处理SIGINT以优雅关闭,并在退出前调用cleanup()清理所有活动 interval。
sse.ts
基于 Express 暴露两个端点:
GET /sse:为每个会话建立一条 SSE 连接;POST /message:接收客户端消息。
通过 transport 映射表管理多个并发客户端;每次新连接时创建SSEServerTransport,再经createServer()建服务器并连接;断开时调用cleanup()。
streamableHttp.ts
streamableHttp.ts 用单个/mcp端点承载 POST(JSON-RPC)、GET(SSE 流)与 DELETE(会话终止),底层使用 SDK 的StreamableHTTPServerTransport。源码印证了结构文档的三点描述:
- 自定义的
InMemoryEventStore(streamableHttp.ts)实现storeEvent/replayEventsAfter,支持 SSE 断线后的事件重放,即"可恢复会话"; - 以
sessionId为键维护transports: Map<string, StreamableHTTPServerTransport>,收到携带mcp-session-id头的 POST 时复用既有传输,无 session 时初始化请求则新建createServer()实例并连接; - 启用宽松 CORS(
origin: "*",注释明确这是为 Inspector 直连调试所用),并暴露mcp-session-id、last-event-id、mcp-protocol-version响应头。
测试验证与扩展路径
src/everything/__tests__/下有五组测试,与目录结构一一对应:registrations.test.ts、tools.test.ts、prompts.test.ts、resources.test.ts、server.test.ts,通过npm run test(vitest + 覆盖率)运行。其中 registrations.test.ts 直接验证了registerResources对 mock 服务器的注册调用,为本文所述的"编排器 + 单文件工厂"模式提供了可执行的验证依据。
当你要为这个服务器新增功能时,结构文档指出的扩展约定是:跟随所在目录的既有模式,导出一个registerX(server)函数,再接入对应的中心index.ts(tools/index.ts、resources/index.ts或prompts/index.ts);更完整的扩展说明见 extension.md 与 AGENTS.md。
小结
Everything Server 的结构可以概括为一条清晰的链条:index.ts按 CLI 参数选择传输 → 传输模块调用createServer()工厂 → 工厂声明能力并依次执行registerTools/registerResources/registerPrompts三个编排器 → 初始化完成后按客户端能力补充条件工具 → 会话结束时以cleanup()统一回收定时器等资源。每个功能独立成文件、以 kebab-case 命名、由register*函数注入,使得目录布局、注册时序与测试边界三者高度一致。对于想学习 MCP 服务器工程化组织,或想参考"如何在单一参考实现中覆盖全部协议特性"的开发者,这套结构本身就是最有价值的部分。
【免费下载链接】serversModel Context Protocol Servers项目地址: https://gitcode.com/GitHub_Trending/se/servers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考