首页
/ MCP servers 仓库 Everything Server 项目结构详解:目录布局、模块职责与源码级实现导读

MCP servers 仓库 Everything Server 项目结构详解:目录布局、模块职责与源码级实现导读

2026-09-04 09:54:10作者:乔或婵

本文基于 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/sdkexpresscorszodjszip;开发依赖含 typescriptvitestprettiershx

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.tsreadInstructions 实现可以看到,它按相对路径 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}(MIME text/plain
  • 二进制:demo://resource/dynamic/blob/{resourceId}(MIME application/octet-stream,Base64 载荷)

结构文档称该路径变量为 {index},其约束是必须为有限的正整数;源码中的 parseResourceIdtemplates.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.tsdocs/ 目录下每个文件注册一个静态资源,URI 遵循 demo://resource/static/document/<filename> 模式;MIME 类型按扩展名映射:.mdtext/markdown.txttext/plain.jsonapplication/json,其余默认 text/plain

session.tssubscriptions.ts

结构文档对这两个文件的描述较简略,但它们承担会话级能力:

  • session.ts:提供按会话注册/查找临时资源的机制。gzip-file-as-resource 工具就用它把压缩后的 Blob 注册为会话资源,URI 形如 demo://resource/session/<name>mimeType: application/gzip,生命周期仅限当前会话;
  • subscriptions.tsserver/index.ts 从这里导入 setSubscriptionHandlersstopSimulatedResourceUpdates,前者为服务器挂接资源订阅处理,后者在会话清理时停止模拟的资源更新检查(配合 toggle-subscriber-updates 工具触发)。

server/ 服务器组装

index.ts:服务器工厂

server/index.ts 导出 createServer() 工厂函数,返回 { server, cleanup }

  1. 通过 readInstructions() 载入服务器指令;
  2. 创建 InMemoryTaskStoreInMemoryTaskMessageQueue,以支持实验性 Tasks 能力;
  3. 构造 McpServer,声明能力包括 tools.listChangedprompts.listChangedresources.subscribe/listChangedlogging,以及 tasks(list、cancel 与 tools.call 请求);
  4. 依次调用 registerTools(server)registerResources(server)registerPrompts(server),再挂接 setSubscriptionHandlers(server)
  5. 注册 oninitialized 钩子:在客户端能力已知后注册条件工具(见下文 tools 一节),并在 350ms 延迟后调用 syncRoots 同步 roots(注释说明延迟是为了避免在 notifications/initialized 处理完成前发出请求导致丢失,见 server/index.ts);
  6. cleanup(sessionId) 负责会话结束时的收尾:停止模拟日志(stopSimulatedLogging)、停止模拟资源更新、清理 task store 定时器、清除初始化超时。

传输层在客户端断开时调用 cleanup(),这是"服务器状态与传输生命周期解耦"的关键设计。

logging.tsroots.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() 中立即执行,注册与客户端能力无关的工具;第二级 registerConditionalToolsserver.server.oninitialized 中执行,因为 rootselicitationsampling、Tasks 等工具依赖客户端在 initialize 阶段声明的能力。这一分层在 server/index.ts 中有对应调用,是理解该服务器启动时序的重要细节。

各工具的职责(沿用结构文档描述,并对照源码印证):

  • echo.ts:接收消息并返回 Echo: {message}
  • get-annotated-message.ts:演示内容级注解——按 messageType"error" | "success" | "debug")输出带 priorityaudience 注解的主文本消息,includeImage 为 true 时附带一张小型 PNG 图片;该服务器所有工具均带工具级注解(readOnlyHintdestructiveHintidempotentHintopenWorldHint);
  • 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,求 ab 之和;
  • 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。源码印证了结构文档的三点描述:

  • 自定义的 InMemoryEventStorestreamableHttp.ts)实现 storeEvent / replayEventsAfter,支持 SSE 断线后的事件重放,即"可恢复会话";
  • sessionId 为键维护 transports: Map<string, StreamableHTTPServerTransport>,收到携带 mcp-session-id 头的 POST 时复用既有传输,无 session 时初始化请求则新建 createServer() 实例并连接;
  • 启用宽松 CORS(origin: "*",注释明确这是为 Inspector 直连调试所用),并暴露 mcp-session-idlast-event-idmcp-protocol-version 响应头。

测试验证与扩展路径

src/everything/__tests__/ 下有五组测试,与目录结构一一对应:registrations.test.tstools.test.tsprompts.test.tsresources.test.tsserver.test.ts,通过 npm run test(vitest + 覆盖率)运行。其中 registrations.test.ts 直接验证了 registerResources 对 mock 服务器的注册调用,为本文所述的"编排器 + 单文件工厂"模式提供了可执行的验证依据。

当你要为这个服务器新增功能时,结构文档指出的扩展约定是:跟随所在目录的既有模式,导出一个 registerX(server) 函数,再接入对应的中心 index.tstools/index.tsresources/index.tsprompts/index.ts);更完整的扩展说明见 extension.mdAGENTS.md

小结

Everything Server 的结构可以概括为一条清晰的链条:index.ts 按 CLI 参数选择传输 → 传输模块调用 createServer() 工厂 → 工厂声明能力并依次执行 registerTools / registerResources / registerPrompts 三个编排器 → 初始化完成后按客户端能力补充条件工具 → 会话结束时以 cleanup() 统一回收定时器等资源。每个功能独立成文件、以 kebab-case 命名、由 register* 函数注入,使得目录布局、注册时序与测试边界三者高度一致。对于想学习 MCP 服务器工程化组织,或想参考"如何在单一参考实现中覆盖全部协议特性"的开发者,这套结构本身就是最有价值的部分。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388