
系列文章目录第一章 TypeScript MCP Server从零到一已更新第二章 TypeScript MCP Server提取业务逻辑与建立自动化测试已更新第三章 TypeScript MCP Server分析 package.json 与处理文件系统边界已更新第四章 TypeScript MCP Server多 Tool 组织与模块复用已更新第五章 TypeScript MCP ServerResources、Prompts 与结构化输出已更新第六章 TypeScript MCP Server独立综合项目与能力验收已更新文章目录系列文章目录前言一、阶段目标与任务边界1.1 本阶段目标1.2 本阶段包含1.3 本阶段不包含二、重构后的结构与分层设计2.1 项目结构2.2 分层职责2.3 为什么提取纯函数2.4 输入校验边界三、制定测试策略3.1 测试范围3.2 JavaScript 小数注意事项3.3 暂不测试的内容四、按测试优先方式实施4.1 第一步先创建测试4.2 第二步实现最少业务代码4.3 第三步让 MCP Tool 使用业务函数4.4 第四步执行静态验证五、验证 MCP 集成没有回归六、验收标准七、常见问题排查7.1 Vitest 提示找不到模块7.2 pnpm test 仍提示没有测试文件7.3 小数用例严格相等失败7.4 修改后 Trae 行为没有变化7.5 pnpm start 找不到 SDK 子路径八、命令汇总与后续学习总结关键要点回顾下一篇预告前言第一阶段已经完成一个可运行的 stdio MCP Server并注册了calculate_sumTool。本文不急着增加新 Tool而是先解决业务逻辑与 MCP 协议适配耦合、Vitest 尚无测试文件这两个基础工程问题。我们将采用测试优先方式把求和逻辑提取为纯函数以 Vitest 覆盖正常值、零、负数和小数再接回 MCP Tool建立可持续演进的自动化验证基础。操作原则先编写失败测试再实现最少代码使测试通过最后接回 MCP Tool 并执行完整验证。一、阶段目标与任务边界1.1 本阶段目标完成后项目应具备以下能力calculateSum作为独立纯函数存在求和函数不依赖 MCP SDK、stdio 或全局状态Vitest 覆盖正常值、零、负数和小数calculate_sumTool 调用提取后的函数不再自行实现加法pnpm test、pnpm typecheck和pnpm build全部通过Inspector 和 Trae 中的 Tool 名称、参数及返回格式保持不变。1.2 本阶段包含新建独立的求和业务模块新建对应的 Vitest 单元测试修改src/index.ts让 Tool handler 调用业务函数验证测试、类型检查、构建和 MCP Tool 行为。1.3 本阶段不包含不添加新的 MCP Tool不引入数据库、HTTP 服务或外部 API不修改 stdio Transport不增加测试覆盖率插件或复杂测试配置不测试 MCP SDK 内部实现不处理货币精度等需要十进制定点计算的业务场景。二、重构后的结构与分层设计2.1 项目结构myMcp/ ├─ docs/ │ ├─ MCP_ZERO_TO_ONE.md │ └─ MCP_STAGE_TWO.md ├─ src/ │ ├─ index.ts │ ├─ calculate-sum.ts │ └─ calculate-sum.test.ts ├─ dist/ ├─ package.json ├─ pnpm-lock.yaml └─ tsconfig.json测试文件放在src中是为了与当前tsconfig.json的范围保持一致rootDir:src,include:[src/**/*.ts]项目规模扩大后可以再决定是否使用独立的tests目录本阶段不提前增加额外配置。2.2 分层职责Trae / Inspector ↓ MCP Tool 调用 src/index.ts ↓ 参数已由 Zod 校验为 number calculateSum(one, two) ↓ 返回 number src/index.ts ↓ 封装为 MCP content Trae / Inspector模块职责src/index.ts创建 MCP Server、声明 Tool Schema、适配 MCP 输入输出、连接 stdiosrc/calculate-sum.ts执行两数相加不感知 MCPsrc/calculate-sum.test.ts验证求和函数的业务行为2.3 为什么提取纯函数当前求和代码位于异步 Tool handler 内。若直接测试 handler需要构造 MCP 上下文或启动客户端测试成本高且关注点混杂。提取后的函数如下exportfunctioncalculateSum(one:number,two:number):number{returnonetwo;}它具有以下特点相同输入始终产生相同输出没有网络、文件、stdio 等副作用可以直接调用单元测试快速且稳定MCP 接入方式变化时业务逻辑仍可复用。2.4 输入校验边界calculateSum接收两个number不重复进行运行时类型校验外部输入校验由 Tool 的 Zod Schema 负责TypeScript 保证项目内部调用时的静态类型calculateSum只负责加法。这样可以避免在业务函数中重复实现已经由 MCP SDK 和 Zod 完成的校验。三、制定测试策略3.1 测试范围用例输入预期输出目的两个正整数1, 23验证基本流程包含零0, 77验证零值不会被错误处理两个负数-2, -3-5验证负数正负数相加10, -46验证混合符号两个小数1.5, 2.253.75验证普通小数3.2 JavaScript 小数注意事项JavaScript 使用 IEEE 754 浮点数因此下面的结果不适合直接使用严格相等判断0.10.2它的实际结果接近但不严格等于0.3。增加该用例时应使用 Vitest 的近似比较expect(calculateSum(0.1,0.2)).toBeCloseTo(0.3);本阶段不引入 Decimal 等额外依赖。3.3 暂不测试的内容字符串、对象、缺失参数等非法输入由 Zod Schema 负责不属于纯函数单元测试SDK 的 Tool 注册和 stdio 协议由官方库负责不重复测试其内部逻辑Inspector 负责最终的 MCP 集成验证。四、按测试优先方式实施4.1 第一步先创建测试创建src/calculate-sum.test.tsimport{describe,expect,it}fromvitest;import{calculateSum}from./calculate-sum.js;describe(calculateSum,(){it(计算两个正整数的和,(){expect(calculateSum(1,2)).toBe(3);});it(正确处理零,(){expect(calculateSum(0,7)).toBe(7);});it(计算两个负数的和,(){expect(calculateSum(-2,-3)).toBe(-5);});it(计算正数与负数的和,(){expect(calculateSum(10,-4)).toBe(6);});it(计算两个小数的和,(){expect(calculateSum(1.5,2.25)).toBe(3.75);});it(处理存在浮点误差的小数,(){expect(calculateSum(0.1,0.2)).toBeCloseTo(0.3);});});注意相对导入写的是./calculate-sum.js而不是./calculate-sum.ts。项目启用了 Node ESM 和NodeNext源码导入需要描述编译后 Node.js 实际加载的.js文件。此时执行pnpm test预期测试失败因为calculate-sum.ts尚未创建。这个失败用于确认测试确实能够发现缺失实现。4.2 第二步实现最少业务代码创建src/calculate-sum.tsexportfunctioncalculateSum(one:number,two:number):number{returnonetwo;}再次执行pnpm test预期全部测试通过。4.3 第三步让 MCP Tool 使用业务函数在src/index.ts顶部添加import{calculateSum}from./calculate-sum.js;将 Tool handler 中的constsumonetwo;替换为constsumcalculateSum(one,two);Tool 对外契约保持不变Tool 名称仍是calculate_sum参数仍是one和two返回文案仍是两个数字的和为{sum}。4.4 第四步执行静态验证依次执行pnpm test pnpm typecheck pnpm build预期结果Vitest 找到并通过全部测试TypeScript 没有类型错误dist中生成运行文件和 Source Map。由于当前tsconfig.json会编译src/**/*.ts测试文件也可能被输出到dist。这不影响本阶段功能但应用项目通常不需要发布测试构建产物。若后续需要整理生产构建可将测试移到独立目录并拆分测试与构建配置本阶段先保持配置简单。五、验证 MCP 集成没有回归先启动编译结果pnpmstart看到以下日志后表示 Server 已连接 stdio 并等待客户端my-mcp server is running via stdio按CtrlC停止然后启动 Inspectorpnpm dlx modelcontextprotocol/inspector noded:\BFF-BackendForFrontend\myMcp\dist\index.js在 Inspector 中调用{one:10,two:20}预期返回两个数字的和为30最后在 Trae 中重启或重连该 MCP Server确认仍能发现并调用calculate_sum。六、验收标准全部满足后第二阶段完成已创建src/calculate-sum.tscalculateSum是不依赖 MCP SDK 的纯函数已创建src/calculate-sum.test.ts测试覆盖正数、零、负数和小数浮点误差用例使用toBeCloseTosrc/index.ts已调用calculateSumTool 名称、输入字段和返回格式未改变pnpm test通过pnpm typecheck通过pnpm build通过Inspector 能调用calculate_sum并得到正确结果Trae 重连后仍能调用该 Tool。七、常见问题排查7.1 Vitest 提示找不到模块确认测试中的相对导入为import{calculateSum}from./calculate-sum.js;同时确认文件名确实是src/calculate-sum.ts。7.2pnpm test仍提示没有测试文件确认测试文件以.test.ts或.spec.ts结尾例如src/calculate-sum.test.ts7.3 小数用例严格相等失败对于0.1 0.2这类输入不使用expect(result).toBe(0.3);改用expect(result).toBeCloseTo(0.3);7.4 修改后 Trae 行为没有变化Trae 运行的是dist/index.js。重新执行pnpm build然后在 Trae 中重启或重连 MCP Server。7.5pnpm start找不到 SDK 子路径确认 MCP SDK 的子路径导入包含.jsimport{McpServer}frommodelcontextprotocol/sdk/server/mcp.js;import{StdioServerTransport}frommodelcontextprotocol/sdk/server/stdio.js;八、命令汇总与后续学习测试优先实施过程# 创建测试后执行第一次预期失败pnpm test# 创建 calculate-sum.ts 后重新执行pnpm test# Tool 接入纯函数后执行完整验证pnpm test pnpm typecheck pnpm build pnpmstart集成验证pnpm dlx modelcontextprotocol/inspector noded:\BFF-BackendForFrontend\myMcp\dist\index.js第二阶段验收通过后再实现analyze_package_jsonTool重点学习使用 Zod 定义文件路径输入使用 Node.js 文件系统 API 读取文件在系统边界校验路径和 JSON 内容区分业务成功结果与 Tool 错误结果为文件不存在、JSON 非法和正常解析编写测试。在第二阶段未通过前不建议同时添加该 Tool以免把单元测试、文件系统和 MCP 错误处理混在一次改动中。总结本文没有扩张 MCP Server 的功能面而是先完成了一次关键的工程化重构通过测试优先方式把加法逻辑提取为独立纯函数用 Vitest 覆盖整数、零、负数和浮点数场景再让原有 Tool 接回该函数并通过类型检查、构建、Inspector 与 Trae 验证对外契约没有回归。关键要点回顾业务逻辑与协议适配分层calculateSum不依赖 MCPindex.ts专注 Tool Schema、输入输出和 stdio。先红后绿先用失败测试确认需求再写最少实现让测试通过。NodeNext 导入使用.js后缀TypeScript 源码描述的是编译后 Node.js 实际加载路径。浮点数使用近似断言0.1 0.2应配合toBeCloseTo。重构不改变外部契约Tool 名称、参数和返回文案保持不变并用 Inspector、Trae 做集成回归。下一篇预告下一篇将实现analyze_package_jsonTool从文件路径、异步读取、unknown数据校验到 Tool 错误隔离系统学习 MCP Server 的文件系统边界处理。