
Everything MCP Server 架构深度解析Server 工厂、三种传输层与多客户端会话管理【免费下载链接】serversModel Context Protocol Servers项目地址: https://gitcode.com/GitHub_Trending/se/servers本篇基于servers仓库中src/everything包的官方架构文档及其配套文档系统讲解 Everything MCP Server 的高层设计、目录结构、启动流程、Server 工厂机制与多客户端会话管理原理并结合server/index.ts、transports/*、index.ts等源码逐层印证。读完本文你可以掌握该 MCP 参考服务器的完整运行时架构理解 tools/prompts/resources 的注册链路、条件注册机制以及cleanup(sessionId)会话清理设计从而能够按仓库规范正确扩展自己的 MCP Server。一、高层架构概览1.1 定位覆盖 MCP 核心特性的参考服务器根据 README 与 架构文档 的说明Everything Server 是一个“最小化、模块化”的 MCPModel Context Protocol服务器其目标不是成为实用的业务服务器而是作为 MCP 客户端开发者的测试服务器它刻意暴露了简单但完整的 tools、prompts、resources并支持 STDIO、SSE、Streamable HTTP 三种传输方式用以演练 MCP 协议的全部核心能力。package.json 中的描述同样印证了这一定位MCP server that exercises all the features of the MCP protocol当前版本为2.0.0依赖modelcontextprotocol/sdk ^1.30.0、express ^5.2.1、zod ^4.0.0等。1.2 设计要点Server 工厂 独立传输入口 原语子模块架构文档给出的设计原则可以归纳为三条Server 工厂Server Factory一个小型工厂函数负责构造McpServer实例并注册全部功能原语tools、prompts、resources传输层解耦每种传输STDIO / SSE / Streamable HTTP是独立入口模块负责创建/连接 server 并处理各自的网络细节原语模块化tools、prompts、resources 各自组织为独立子目录每个原语一个文件通过index.ts聚合注册。1.3 多客户端支持该服务器支持多个并发客户端连接。架构文档指出按会话session跟踪数据的能力通过两个演示机制体现资源订阅resource subscriptions与模拟日志simulated logging。具体而言HTTP 类传输会将每个客户端的 transport 映射到sessionId并为每个会话维护独立的定时器与内存状态会话结束时统一通过cleanup(sessionId)回收。二、构建与分发架构文档的 “Build and Distribution” 一节说明了产物的构建方式结合 package.json 可以确认以下事实编译TypeScript 源码通过npm run build实际执行tsc shx cp -r docs dist/ shx chmod x dist/*.js编译到dist/文档随包发布build脚本会把docs/整目录复制到dist/使得说明文件尤其是instructions.md见 5.1 节能够与编译后的服务器一起分发并被运行时读取CLI 入口package.json的bin字段将mcp-server-everything指向dist/index.js因此安装后既可用npx -y modelcontextprotocol/server-everything [stdio|sse|streamableHttp]直接运行也可在客户端配置如 Claude Desktop、VS Code 的 MCP 配置中声明该命令启动脚本start:stdio、start:sse、start:streamableHttp三个 npm script 分别执行node dist/index.js transport用于从源码构建后本地调试 HTTP 传输容器化仓库提供 DockerfileREADME 同时给出docker run -i --rm mcp/everything的接入方式。三、项目结构与模块划分项目结构文档 给出了完整目录树这里按其脉络整理各模块职责该目录树继承自 架构文档 的导航骨架src/everything ├── index.ts # CLI 入口按第一个参数选择传输模块 ├── AGENTS.md # 面向 Agent/LLM 的编码规范与扩展指南 ├── package.json ├── docs/ # 架构/结构/启动/特性/扩展/原理 六篇文档 ├── prompts/ # 4 个演示 prompt ├── resources/ # 资源模板、静态文档、会话资源、订阅跟踪 ├── server/ # Server 工厂 模拟日志 roots 同步 ├── tools/ # 17 个演示工具 └── transports/ # stdio.ts / sse.ts / streamableHttp.ts各目录核心文件说明依据 structure.md 与源码3.1index.tsCLI 入口解析命令行参数并按第一个参数动态import对应传输模块默认stdio。源码中的注释说明了动态导入的用意只加载被请求的模块避免所有模块全部初始化。未知参数时打印用法并以退出码 1 终止见 index.ts。3.2server/服务器核心server/index.tsServer 工厂创建带能力声明的McpServer加载指令instructions注册 tools/prompts/resources 并设置资源订阅处理器详见第五节server/logging.ts实现模拟日志——按会话以随机级别周期性发送日志消息由专用工具按需启停server/roots.ts提供syncRoots(server, sessionId)在初始化完成后向客户端同步 roots 请求。3.3prompts/与tools/与resources/promptssimple-prompt无参数、args-promptcity必填、state可选、completable-prompt用 SDKcompletable(...)助手实现参数自动补全、resource-prompt内嵌动态生成的资源。tools见 tools/index.ts 中的编排函数涵盖 echo、结构化内容、Zod 校验求和、tiny PNG 图片、长时任务进度通知、sampling/elicitation 触发器、URL 模式 elicitation、MCP TasksSEP-1686等特性清单见 5.3 节。resources按 structure.md 的说明包含四类——动态 Textdemo://resource/dynamic/text/{index}text/plain内容按请求带时间戳生成{index}须为有限正整数动态 Blobdemo://resource/dynamic/blob/{index}application/octet-streamBase64 载荷静态文档demo://resource/static/document/filename将docs/目录下的文件作为文件型资源服务按扩展名映射 MIMEmarkdown/json/txt 等会话级demo://resource/session/name由工具在运行期动态注册、仅存活于当前会话典型使用者是gzip-file-as-resource工具将压缩内容以application/gzip注册为会话资源。server/index.ts中对../resources/subscriptions.js与../resources/index.js的导入server/index.ts印证了该模块在运行时被工厂直接装配。四、启动流程从 CLI 到传输管理器启动流程文档 将启动过程描述为三层启动器Launcher→ 传输管理器Transport Manager→ 服务器工厂Server Factory。4.1 启动器用法为node dist/index.js [stdio|sse|streamableHttp]参数缺省为stdio映射关系为参数模块stdiotransports/stdio.tsssetransports/sse.tsstreamableHttptransports/streamableHttp.ts对应源码即 index.ts 中的switch分支与动态import。4.2 传输管理器三种传输的会话处理差异每个传输管理器都会调用createServer()位于server/index.ts创建 server 实例并通过server.connect(transport)连接到 MCP SDK 提供的具体传输类型。三种传输的关键差异来自 startup.md 与传输源码STDIOtransports/stdio.ts单连接、进程绑定直接new StdioServerTransport()后await server.connect(transport)无 sessionId 概念连接即clientConnect()语义监听SIGINT先server.close()再调用cleanup()清空调度器最后退出进程stdio.ts。SSEtransports/sse.ts基于 Express暴露两个端点GET /sse每个新会话建立一条 SSE 流创建SSEServerTransport(/message, res)并按sessionId存入transportsMapPOST /message客户端 JSON-RPC 消息入口按 query 中的sessionId找到对应 transport 调用handlePostMessage。多客户端支持客户端 transport 与sessionId一一映射server.server.onclose钩子在断连时从 Map 中删除该会话并调用cleanup(sessionId)sse.ts。Streamable HTTPtransports/streamableHttp.tsExpress 应用仅暴露/mcp单一端点用三种 HTTP 方法承载协议POSTJSON-RPC 消息。无mcp-session-id头视为初始化请求——现场创建 server、StreamableHTTPServerTransportsessionIdGenerator: () randomUUID()并注入InMemoryEventStore以获得断线重放能力onsessioninitialized时登记 transport随后server.connect(transport)并transport.handleRequest(req, res)GETSSE 事件流支持Last-Event-ID头配合事件存储实现可恢复resumable会话DELETE会话终止触发cleanup(sessionId)。会话管理细节值得注意源码注释说明 transport 在onsessioninitialized中才入 Map是为了规避“会话尚未登记、请求已到达”的竞态streamableHttp.tsInMemoryEventStore是仓库内自实现的最小EventStore——storeEvent以randomUUID()作为 eventId 存入 MapreplayEventsAfter按存储顺序从lastEventId之后逐条重放streamableHttp.ts。两个 HTTP 传输都通过process.env.PORT || 3001决定监听端口并配置了宽松 CORS注释明确“生产环境请慎用*”方便用 MCP Inspector 直连调试。4.3 多客户端的前置条件startup.md 最后强调能够支持多客户端的传输必须把每会话的数据映射到 session 标识——这是整个多客户端架构的公理后续的订阅表、日志定时器、会话资源都以此为键。五、Server 工厂createServer()全解析5.1 能力声明、任务存储与指令加载server/index.ts 是工厂的实现。createServer()的完整装配序列如下读取指令readInstructions()从 docs 目录加载instructions.md作为 server instructions这就是构建时要把docs/复制进dist/的原因——运行时按相对路径读取它并在 initialize 交互中返回给客户端任务基础设施创建InMemoryTaskStore与InMemoryTaskMessageQueue来自 SDK 的experimental/tasks用于 MCP TasksSEP-1686的生命周期与消息管理创建McpServer身份信息为name: mcp-servers/everything、title: Everything Reference Server、version: 2.0.0能力声明包括tools: { listChanged: true }、prompts: { listChanged: true }——原语列表变化时可发变更通知resources: { subscribe: true, listChanged: true }——显式声明subscribe: true正是资源订阅功能的前提logging: {}——启用日志能力tasks: { list, cancel, requests: { tools: { call } } }——声明 Tasks 能力对应 features.md 中“Capabilities advertised”一节。注册三大原语registerTools(server)→registerResources(server)→registerPrompts(server)安装订阅处理器setSubscriptionHandlers(server)来自resources/subscriptions.ts见 6.2 节。5.2 条件注册等握手完成才知道客户端能力how-it-works.md 解释了该服务器一个重要的机制——条件工具注册部分工具只有在客户端支持相应能力时才有意义如get-roots-list、trigger-elicitation-request、trigger-sampling-request而客户端能力要到初始化握手完成后才可知。因此工厂在server.server.oninitialized回调中延迟调用registerConditionalTools(server)。从 tools/index.ts 的源码可以看到两组注册的精确划分registerTools连接前立即注册echo、get-annotated-message、get-env、get-resource-links、get-resource-reference、get-structured-content、get-sum、get-tiny-image、gzip-file-as-resource、toggle-simulated-logging、toggle-subscriber-updates、trigger-long-running-operation 共 12 个不依赖客户端能力的工具registerConditionalToolsoninitialized 中注册get-roots-list、trigger-elicitation-request、trigger-url-elicitation、trigger-sampling-request、simulate-research-query以及两个双向任务演示工具trigger-sampling-request-async/trigger-elicitation-request-async。oninitialized中还有第二件事延迟 350ms 后调用syncRoots(server, sessionId)。server/index.ts 的注释说明了原因——roots 同步必须等notifications/initialized处理器完全结束之后发出否则请求会丢失这属于典型的“初始化时序敏感”细节也解释了为什么需要一个可被cleanup清掉的initializeTimeout。5.3 注册的原语特性清单features.md 列出了全部已实现能力是理解这个服务器“能演示什么”的权威清单Tools19 个工具演示的协议能力echo基础工具调用Zod 输入校验get-annotated-message内容级annotationspriority、audience随messageType变化可选附带小图片get-env返回进程环境变量 JSON用于调试配置get-resource-links文本 多个resource_link混合响应get-resource-reference返回具体动态资源的resource内容块get-roots-list返回客户端最近一次发送的 roots 列表gzip-file-as-resource拉取 URL/data URI → 压缩 → 注册为会话资源并返回 link/inline resourceget-structured-contentcontent文本内嵌 JSON 经outputSchema校验的structuredContent双返回get-sumZod schema 定义的双数求和get-tiny-image返回 tiny PNG 的image内容项trigger-long-running-operation多步长任务客户端提供progressToken时发notifications/progresstoggle-simulated-logging按会话启停随机级别日志尊重客户端logging/setLeveltoggle-subscriber-updates按会话启停资源更新通知模拟trigger-elicitation-requestform 模式elicitation/create字符串/数字/布尔/枚举/格式校验trigger-url-elicitationURL 模式 elicitation或抛出-32042UrlElicitationRequiredError错误路径前置 elicitation 指向不同 URL 以避免客户端在同一错误上循环trigger-sampling-request向客户端/LLM 发sampling/createMessagesimulate-research-query服务端 TasksSEP-1686多阶段研究任务 状态更新ambiguous: true时中途发 elicitation 澄清trigger-sampling-request-async双向任务服务端发采样请求、客户端作后台任务执行服务端轮询tasks/gettrigger-elicitation-request-async双向任务elicitation 版需客户端声明tasks.requests.elicitation.createPrompts4 个simple-prompt、args-prompt、completable-prompt、resource-prompt内嵌动态资源。Resources4 类 URI动态 Text / 动态 Blob / 静态文档 / 会话级资源见 3.3 节。TasksSEP-1686生命周期客户端以task: true调用tools/call→ 服务端返回带taskId的CreateTaskResult而非即时结果 → 客户端轮询tasks/get获取状态与statusMessage→ 状态为completed后调tasks/result取最终结果。状态集合为working / input_required / completed / failed / cancelled双向任务方向与演示工具的对应关系为tools/call服务端执行simulate-research-query、sampling/createMessage与elicitation/create客户端执行两个-async工具。其他行为约定features.md模拟资源更新通知与模拟日志默认均关闭opt-in由对应 toggle 工具启停多客户端并发下每个客户端的订阅按会话独立跟踪、独立投递。六、会话状态与清理多客户端的内存模型how-it-works.md 按模块说明了会话状态的四条主线它们共同构成了“多客户端”承诺的落地方式6.1 条件工具见 5.2 节registerConditionalTools(server)由oninitialized触发保证依赖客户端能力的工具只在握手完成后出现。6.2 资源订阅resources/subscriptions.ts维护Mapuri, SetsessionId的每 URI 订阅者表setSubscriptionHandlers(server)在工厂中被调用见 server/index.ts安装 subscribe/unsubscribe 处理器并保持表更新toggle-subscriber-updates工具调用beginSimulatedResourceUpdates(server, sessionId)/stopSimulatedResourceUpdates(sessionId)启停每会话定时器仅向该会话已订阅的 URI 发送notifications/resources/updated { uri }cleanup(sessionId)会调用stopSimulatedResourceUpdates(sessionId)清掉定时器与会话级状态。6.3 会话级资源resources/session.tsgetSessionResourceURI(name)构造demo://resource/session/nameregisterSessionResource(server, resource, type, payload)按text | blob类型在内存中登记内容并返回resource_link内容仅在当前会话生命周期内可读取——工具可以借此创建“一次性”产物而不落盘如gzip-file-as-resource的 gzip 会话资源。6.4 模拟日志server/logging.ts周期性发送随机级别debug 至 emergency 全八级日志消息可携带 sessionId 便于演示辨识由toggle-simulated-logging工具调用beginSimulatedLogging(server, sessionId?)/stopSimulatedLogging(sessionId?)启停通过server.sendLoggingMessage({ level, data }, sessionId?)发送因此客户端配置的最小日志级别由 SDK 侧强制执行传输断连触发cleanup()同样会停止活跃的定时器。6.5cleanup()的统一收尾回到工厂返回值server/index.ts 中cleanup(sessionId?)依次执行——stopSimulatedLogging(sessionId)→stopSimulatedResourceUpdates(sessionId)→taskStore.cleanup()清理任务存储定时器→ 清除 pending 的initializeTimeout。三种传输的收尾路径最终都汇聚到它stdio 在SIGINT时无 sessionId清理全部SSE 在onclose时带 sessionIdStreamable HTTP 在 DELETE /onclose与进程SIGINT遍历所有会话时。七、扩展点向服务器添加新能力扩展点文档 给出了三条标准扩展路径与“原语模块化 index 编排”的架构完全一致添加工具在tools/下新建文件实现registerXTool(server)并通过server.registerTool(...)注册然后在 tools/index.ts 的registerTools(server)不依赖客户端能力或registerConditionalTools(server)依赖客户端能力中导出并调用。添加 Prompt在prompts/下新建registerXPrompt(server)server.registerPrompt(...)接入prompts/index.ts的registerPrompts(server)。添加资源在resources/下新建registerXResources(server)可配合ResourceTemplate做动态模板资源接入resources/index.ts的registerResources(server)。仓库中的 AGENTS.md 进一步面向 Agent/LLM 提供了编码规范与“如何恰当扩展服务器”的指导src/everything/__tests__/下的 registrations.test.ts、tools.test.ts、resources.test.ts、prompts.test.ts、server.test.ts以vitest运行见 vitest.config.ts则为注册完整性与工厂行为提供了回归验证——扩展时保持这些测试通过是符合仓库规范的重要检查项。八、小结Everything Server 的架构可以概括为一句话“一个工厂造服务器三个入口管传输所有会话状态按sessionId建账并随cleanup销账”。工厂层server/index.ts声明能力、加载指令、注册原语、安装订阅处理器并通过oninitialized完成依赖客户端能力的条件注册传输层transports/*各自处理网络协议与多路复用把每个客户端映射为一个 session并在断连/终止时回调统一清理原语层tools/、prompts/、resources/保持单文件单原语的扁平结构使扩展点始终只有两步写注册函数、挂到index.ts编排器。对 MCP 客户端开发者而言这个仓库的价值正在于此它用最小化的代码把协议特性逐条“立牌”出来配合docs/下 架构、结构、启动、特性、扩展、原理 六篇文档构成了一份可直接阅读源码核实的 MCP 行为参考实现。【免费下载链接】serversModel Context Protocol Servers项目地址: https://gitcode.com/GitHub_Trending/se/servers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考