☰
第一章:TypeScript-MCP-Server-从零到一
2026/10/12 7:31:26 网站建设 项目流程

系列文章目录

  • 第一章 TypeScript MCP Server:从零到一(已更新)
  • 第二章 TypeScript MCP Server:提取业务逻辑与建立自动化测试(已更新)
  • 第三章 TypeScript MCP Server:分析 package.json 与处理文件系统边界(已更新)
  • 第四章 TypeScript MCP Server:多 Tool 组织与模块复用(已更新)
  • 第五章 TypeScript MCP Server:Resources、Prompts 与结构化输出(已更新)
  • 第六章 TypeScript MCP Server:独立综合项目与能力验收(已更新)

提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 系列文章目录
  • 前言
  • 一、认识 MCP 与运行链路
    • 1.1 MCP 是什么?
    • 1.2 运行链路一览
  • 二、项目初始化
    • 2.1 运行时依赖
    • 2.2 开发依赖
    • 2.3 配置 package.json
      • 为什么设置 `"type": "module"`
      • 每条脚本的用途
    • 2.4 创建 TypeScript 配置
  • 三、编写第一个 MCP Server
    • 3.1 创建入口文件
    • 3.2 逐段理解源码
      • McpServer
      • registerTool
      • Zod 输入 Schema
      • Tool 返回值
      • stdio Transport
      • 为什么日志必须使用 `console.error`
  • 四、类型检查与构建
  • 五、使用 MCP Inspector 调试
  • 六、接入 Trae
  • 七、日常开发工作流
  • 八、常见问题排查
    • 8.1 Trae 找不到 Tool
    • 8.2 修改源码后行为没有变化
    • 8.3 进程启动后一直不退出
    • 8.4 JSON 配置无法解析
    • 8.5 协议解析错误或 Server 意外断开
    • 8.6 Node 找不到模块
    • 8.7 TypeScript 编译报 ESM 相关错误
  • 九、验收清单与后续学习
    • 9.1 第一阶段验收清单
    • 9.2 第一阶段之后学什么
    • 9.3 命令汇总
  • 总结

前言

提示:本文记录如何从零搭建一个基于 TypeScript、Node.js 和 stdio 的本地 MCP Server,并接入 Trae 完成第一个 Tool 的调用。

随着 AI 编程助手的普及,如何让大模型安全、可控地调用本地能力成为了一个关键问题。MCP(Model Context Protocol)正是为此而生——它定义了一套标准协议,让 AI 能够发现并调用外部工具。本文将以一个最小可运行的项目为例,带你从依赖配置、源码编写、Inspector 调试,一直走到在 Trae 中成功调用第一个calculate_sumTool。

操作原则:每完成一节,先执行该节的验证命令;验证通过后再继续。


提示:以下是本篇文章正文内容,下面案例可供参考

一、认识 MCP 与运行链路

1.1 MCP 是什么?

MCP(Model Context Protocol)是一种开放协议,用于标准化应用程序向大语言模型暴露上下文和工具的方式。你可以把它理解为"AI 的 USB-C 接口"——不管 Server 端如何实现,Client 端(如 Trae)只要遵循协议,就能统一发现和调用工具。

1.2 运行链路一览

理解整体链路比急着写代码更重要。本次要建立的链路如下:

用户 ↓ 自然语言 Trae 中的 AI(MCP Client) ↓ 判断是否调用工具 calculate_sum Tool ↓ MCP 消息(stdio) 本地 Node.js MCP Server ↓ 执行 TypeScript 中定义的函数 返回计算结果 ↓ Trae 组织最终答案

各角色职责:

  • Trae是 MCP Client,负责连接 Server,并把可用 Tool 提供给 AI。
  • 本项目是 MCP Server,负责声明并执行 Tool。
  • stdio是通信通道。Trae 会启动本项目的 Node 进程,通过标准输入和标准输出交换 MCP 协议消息。
  • calculate_sum是第一个 Tool,相当于"给 AI 调用的函数"。

二、项目初始化

2.1 运行时依赖

依赖当前版本作用
@modelcontextprotocol/sdk^1.29.0官方 MCP TypeScript SDK,用于创建 Server、注册 Tool 和建立 stdio 通信
zod^4.4.3定义并校验 Tool 的输入参数,同时帮助 SDK 生成参数 Schema

2.2 开发依赖

依赖当前版本作用
typescript^7.0.2类型检查并将 TypeScript 编译为 JavaScript
@types/node^26.1.1为process、Node 文件系统等 API 提供类型
tsx^4.23.1开发阶段直接执行 TypeScript
vitest^4.1.10单元测试框架;不是运行 MCP 的必需依赖,但后续测试会用到

2.3 配置 package.json

打开项目根目录的package.json,修改为下面的结构。依赖版本保留 pnpm 当前安装的实际值,不要手动降级或复制其他版本。

{"name":"my-mcp","version":"1.0.0","description":"A TypeScript MCP server for learning MCP","type":"module","main":"dist/index.js","scripts":{"dev":"tsx watch src/index.ts","build":"tsc -p tsconfig.json","start":"node dist/index.js","typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run"},"keywords":["mcp","model-context-protocol"],"author":"","license":"ISC","packageManager":"pnpm@10.28.2","dependencies":{"@modelcontextprotocol/sdk":"^1.29.0","zod":"^4.4.3"},"devDependencies":{"@types/node":"^26.1.1","tsx":"^4.23.1","typescript":"^7.0.2","vitest":"^4.1.10"}}

为什么设置"type": "module"

MCP SDK 以现代 ESM 方式提供模块,源码会使用:

import{McpServer}from"@modelcontextprotocol/sdk/server/mcp.js";

"type": "module"告诉 Node.js,编译后的.js文件按照 ESM 运行,而不是 CommonJS。

每条脚本的用途

  • pnpm dev:开发时监听源码变化并自动重启。
  • pnpm typecheck:只检查类型,不生成文件。
  • pnpm build:将src编译到dist。
  • pnpm start:运行编译后的正式入口。
  • pnpm test:后续运行 Vitest 测试。

修改后执行:

pnpm install

这一步会让锁文件与package.json保持一致。

2.4 创建 TypeScript 配置

在项目根目录创建tsconfig.json:

{"compilerOptions":{"target":"ES2022","module":"NodeNext","moduleResolution":"NodeNext","rootDir":"src","outDir":"dist","strict":true,"esModuleInterop":true,"forceConsistentCasingInFileNames":true,"skipLibCheck":true,"sourceMap":true,"types":["node"]},"include":["src/**/*.ts"],"exclude":["node_modules","dist"]}

关键配置说明:

  • target: ES2022:使用现代 Node.js 支持的 JavaScript 能力。
  • module/moduleResolution: NodeNext:按 Node.js ESM 规则解析模块。
  • rootDir: src:TypeScript 源码放在src。
  • outDir: dist:编译结果放在dist。
  • strict: true:开启严格类型检查。
  • types: ["node"]:加载 Node.js 类型。

三、编写第一个 MCP Server

3.1 创建入口文件

创建src/index.ts:

import{McpServer}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import*aszfrom"zod/v4";constserver=newMcpServer({name:"my-mcp",version:"1.0.0",});server.registerTool("calculate_sum",{title:"两数求和",description:"计算两个数字的和。当用户需要对两个数字做加法时使用。",inputSchema:{a:z.number().describe("第一个数字"),b:z.number().describe("第二个数字"),},},async({a,b})=>{constresult=a+b;return{content:[{type:"text",text:`${a}+${b}=${result}`,},],};},);asyncfunctionmain():Promise<void>{consttransport=newStdioServerTransport();awaitserver.connect(transport);console.error("my-mcp server is running via stdio");}main().catch((error:unknown)=>{console.error("MCP Server 启动失败:",error);process.exit(1);});

3.2 逐段理解源码

McpServer

constserver=newMcpServer({name:"my-mcp",version:"1.0.0",});

它创建 MCP Server 实例。name和version是客户端连接后看到的服务身份信息,不是 Tool 名称。

registerTool

server.registerTool("calculate_sum",config,handler);

它包含三部分:

  1. calculate_sum:稳定、唯一的 Tool 标识,推荐使用英文和 snake_case。
  2. config:告诉客户端和 AI 这个 Tool 做什么、接受什么参数。
  3. handler:Tool 被调用时真正执行的业务代码。

description不只是给人看的。AI 会依靠它决定何时调用 Tool,所以应明确写出"做什么"和"什么时候使用"。

Zod 输入 Schema

inputSchema:{a:z.number().describe("第一个数字"),b:z.number().describe("第二个数字"),}

它同时承担:

  • 向客户端声明参数结构;
  • 在运行时校验外部输入;
  • 给 TypeScript 推导 handler 中a、b的类型。

因为 AI 传来的参数属于外部输入,不能只依赖 TypeScript 的编译时类型。

Tool 返回值

return{content:[{type:"text",text:"...",},],};

Tool 不直接返回普通字符串,而是返回 MCP 规定的内容数组。第一版使用最简单的text内容。

stdio Transport

consttransport=newStdioServerTransport();awaitserver.connect(transport);

这会让当前 Node.js 进程通过 stdin/stdout 接收和发送 MCP 消息。

为什么日志必须使用console.error

stdio 模式下,stdout用于传输 MCP 协议消息。随意调用console.log()可能污染协议流,导致客户端解析失败。

因此服务运行期间:

console.error("调试信息");

不要使用:

console.log("调试信息");

四、类型检查与构建

先执行类型检查:

pnpm typecheck

预期:命令正常结束,没有 TypeScript 错误。

然后执行构建:

pnpm build

构建成功后应出现:

dist/ ├─ index.js └─ index.js.map

最后尝试启动:

pnpmstart

预期看到:

my-mcp server is running via stdio

进程会继续等待 MCP Client 发送消息,这是正常现象,不是卡死。按Ctrl+C停止。

注意:仅执行pnpm start只能证明进程能启动,不能完整验证 Tool,因为 stdio Server 正在等待符合 MCP 协议的输入。下一节使用 Inspector 验证。

五、使用 MCP Inspector 调试

Inspector 是 MCP 的交互式调试客户端,可以发现并调用 Server 暴露的 Tool。

不必把 Inspector 安装为项目依赖,直接执行:

pnpm dlx @modelcontextprotocol/inspector node dist/index.js

命令会输出本地访问地址。在浏览器打开该地址,然后:

  1. 确认 Transport 为STDIO。
  2. 确认 Command 是node。
  3. 确认 Arguments 包含当前项目的dist/index.js。
  4. 点击连接按钮。
  5. 打开Tools。
  6. 点击列出工具,应看到calculate_sum。
  7. 输入a = 10、b = 20。
  8. 调用 Tool。

预期结果:

10 + 20 = 30

如果 Inspector 命令对相对路径解析异常,使用绝对路径:

pnpm dlx @modelcontextprotocol/inspector node"d:\BFF-BackendForFrontend\myMcp\dist\index.js"

Inspector 验证通过意味着:

  • Node 进程可以启动;
  • MCP 握手成功;
  • 客户端可以发现 Tool;
  • 参数 Schema 正常;
  • Tool handler 可以执行并返回 MCP 内容。

六、接入 Trae

不同版本的 Trae 设置入口和配置文件位置可能不同,但核心配置始终是"命令 + 参数 + 工作目录"。在 Trae 的 MCP 设置中新增本地 stdio Server。

推荐配置概念如下:

{"mcpServers":{"my-mcp":{"command":"node","args":["d:\\BFF-BackendForFrontend\\myMcp\\dist\\index.js"],"cwd":"d:\\BFF-BackendForFrontend\\myMcp"}}}

注意事项:

  • JSON 中 Windows 路径的反斜杠需要写成\\。
  • 使用dist/index.js前必须先执行pnpm build。
  • command使用node,不要使用会持续 watch 的pnpm dev。
  • 如果 Trae 的可视化配置只提供 Command 和 Args,就分别填写node与入口文件绝对路径。

保存配置后,重新加载或连接该 MCP Server。确认 Trae 显示calculate_sumTool,然后发起测试:

请使用 calculate_sum 工具计算 135 和 246 的和,并告诉我工具返回了什么。

预期过程:

  1. AI 识别应调用calculate_sum;
  2. 参数为{ "a": 135, "b": 246 };
  3. MCP Server 返回135 + 246 = 381;
  4. AI 将结果告诉你。

提示:明确要求"使用工具"是首次联调手段。正常使用时可以直接问"135 加 246 等于多少",但模型可能认为简单算术无需调用工具,因此不适合作为首次验证。

七、日常开发工作流

修改源码时:

pnpm dev

提交或接入 Trae 前:

pnpm typecheck pnpm test pnpm build

Trae 使用编译后的dist/index.js,所以每次修改src/index.ts后,都要重新执行:

pnpm build

然后在 Trae 中重启或重连 MCP Server。

八、常见问题排查

8.1 Trae 找不到 Tool

按顺序检查:

  1. 是否执行过pnpm build;
  2. dist/index.js是否存在;
  3. Trae 中入口路径是否为绝对路径;
  4. JSON 路径中的\\是否正确;
  5. MCP Server 是否已经在 Trae 中启用或重连;
  6. Inspector 是否能发现calculate_sum。

如果 Inspector 正常而 Trae 不正常,问题通常在 Trae 配置;如果 Inspector 也失败,优先检查项目代码和构建结果。

8.2 修改源码后行为没有变化

Trae 运行的是dist/index.js,不是src/index.ts。重新执行pnpm build,然后重连 Server。

8.3 进程启动后一直不退出

这是正常的。stdio Server 必须持续等待客户端消息。使用Ctrl+C停止手动启动的进程。

8.4 JSON 配置无法解析

Windows 路径必须转义:

"d:\\BFF-BackendForFrontend\\myMcp\\dist\\index.js"

不能直接写成:

"d:\BFF-BackendForFrontend\myMcp\dist\index.js"

8.5 协议解析错误或 Server 意外断开

检查业务代码是否使用了console.log()。stdio Server 的普通日志应改成console.error()。

8.6 Node 找不到模块

确认在项目根目录执行过:

pnpm install pnpm build

同时确认 Node.js 满足 SDK 要求。当前 SDK 要求 Node.js>=18,推荐使用 Node.js 20 或更高的 LTS 版本。

8.7 TypeScript 编译报 ESM 相关错误

确认:

  • package.json包含"type": "module";
  • tsconfig.json同时使用"module": "NodeNext"和"moduleResolution": "NodeNext";
  • SDK 子路径导入带.js后缀。

九、验收清单与后续学习

9.1 第一阶段验收清单

全部满足后,第一阶段完成:

  • package.json已配置 ESM 和开发脚本;
  • 已创建tsconfig.json;
  • 已创建src/index.ts;
  • pnpm typecheck通过;
  • pnpm build通过;
  • dist/index.js已生成;
  • Inspector 能列出calculate_sum;
  • Inspector 调用后返回正确结果;
  • Trae 能连接my-mcp;
  • Trae 能调用calculate_sum。

9.2 第一阶段之后学什么

不要立即添加数据库、远程 HTTP 或复杂框架。建议按以下顺序扩展:

  1. 将求和业务逻辑提取成独立函数,并用 Vitest 编写单元测试;
  2. 实现analyze_package_json,学习文件读取与边界校验;
  3. 实现explain_npm_script,学习多个 Tool 的组织方式;
  4. 学习 MCP Resources,向 AI 暴露只读项目信息;
  5. 接入一个外部 API,学习.env和密钥管理;
  6. 最后学习 Streamable HTTP、认证和远程部署。

建议第二个 Tool 选择analyze_package_json,因为它与你的前端经验直接相关,并且不依赖 API Key 或数据库。

9.3 命令汇总

完成文件修改后,依次执行:

pnpm install pnpm typecheck pnpm build pnpmstart

看到启动日志后按Ctrl+C,再运行 Inspector:

pnpm dlx @modelcontextprotocol/inspector node"d:\BFF-BackendForFrontend\myMcp\dist\index.js"

Inspector 验证通过后,将node + dist/index.js 绝对路径配置到 Trae,并测试calculate_sum。


总结

提示:这里对文章进行总结:

本文从认识 MCP 协议和运行链路出发,完整走通了 TypeScript MCP Server 的搭建流程:配置package.json与tsconfig.json、编写第一个calculate_sumTool、逐段理解源码核心概念、完成类型检查与构建、使用 Inspector 交互式调试,最终成功接入 Trae 并完成首次工具调用。

关键要点回顾:

  1. stdio 通信下stdout是协议通道,日志必须用console.error,否则会污染协议流。
  2. Zod Schema 三合一:同时承担参数声明、运行时校验和类型推导。
  3. Trae 运行的是dist/index.js,每次改源码都要重新pnpm build。
  4. description 是写给 AI 看的,要明确"做什么"和"什么时候使用"。
  5. 首次联调要明确要求"使用工具",避免模型跳过工具调用。

下一篇文章我们将进入进阶 Tool 开发,提取业务逻辑并编写单元测试,敬请关注。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询