
1. 为什么选择TypeScript开发MCP服务器TypeScript作为JavaScript的超集在开发MCP服务器时有着天然的优势。我刚开始接触MCP开发时也纠结过语言选择问题但实际使用下来发现TypeScript的类型系统简直就是为MCP这类协议开发量身定制的。想象一下当你在定义工具接口时能够清晰地看到每个参数的类型和返回值结构这种开发体验比纯JavaScript要舒服太多。MCPModel Context Protocol的核心在于规范化的通信接口而TypeScript的interface正好可以完美描述这些协议结构。比如定义一个加法工具的输入参数你可以直接用interface声明interface AddParams { a: number; b: number; }这样不仅代码更易读还能在编码阶段就捕获类型错误。我遇到过最典型的场景是处理数字输入时JavaScript需要手动做类型检查而TypeScript在编译阶段就会提醒你参数类型不匹配的问题。另一个重要优势是开发工具链的支持。VS Code对TypeScript的智能提示简直不要太友好当你输入server.tool(时IDE会自动提示需要填写的参数类型和返回值结构。这对于MCP开发这种需要严格遵循协议规范的场景特别有用大大降低了出错概率。2. 从零搭建开发环境2.1 初始化项目结构先创建一个干净的项目目录这是我推荐的标准结构mkdir mcp-calculator cd mcp-calculator npm init -y接下来安装核心依赖时有个小技巧把开发依赖和生产依赖分开安装会更清晰。我通常会这样操作# 生产依赖 npm install modelcontextprotocol/sdk zod # 开发依赖 npm install -D typescript types/node ts-node nodemon初始化TypeScript配置时建议使用更严格的编译选项。这是我常用的tsconfig.json配置{ compilerOptions: { target: ES2020, module: commonjs, outDir: ./dist, rootDir: ./src, strict: true, esModuleInterop: true, skipLibCheck: true }, include: [src/**/*] }2.2 配置开发工作流在package.json中添加这些脚本会让开发更高效{ scripts: { build: tsc, start: node dist/server.js, dev: nodemon --watch src/**/*.ts --exec ts-node src/server.ts } }使用nodemonts-node的组合可以实现保存自动重启实测开发效率提升至少50%。第一次配置时我踩过的坑是忘记安装ts-node导致nodemon无法正确解析TypeScript文件所以务必确保这两个开发依赖都已安装。3. 核心代码实现详解3.1 构建服务器骨架先创建一个最基本的服务器实例。这里有个细节需要注意MCP服务器的name和version字段会暴露给客户端所以命名要有意义import { McpServer } from modelcontextprotocol/sdk/server/mcp; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio; const server new McpServer({ name: calculator-server, version: 1.0.0, description: 提供四则运算服务的MCP服务器, capabilities: { tools: {} } });3.2 实现工具方法以加法工具为例完整的实现应该包含三部分工具定义、参数验证和业务逻辑。我习惯用Zod先定义严格的输入模式import { z } from zod; const NumberSchema z.number({ required_error: 参数必须为数字, invalid_type_error: 参数必须为数字 }).describe(用于计算的数字参数);然后实现工具逻辑时建议把核心计算部分提取成纯函数这样更易于测试function addNumbers(a: number, b: number): number { return a b; } server.tool(add, 执行两个数字的加法运算, { a: NumberSchema, b: NumberSchema }, async ({a, b}) { const result addNumbers(a, b); return { content: [{ type: text, text: ${a} ${b} ${result} }] }; });3.3 增强错误处理对于除法这种可能出错的操作建议实现两重保护Zod验证和运行时检查。这是我总结的最佳实践server.tool(divide, 执行除法运算, { dividend: NumberSchema, divisor: NumberSchema.min(0.0001, 除数不能为零) }, async ({dividend, divisor}) { // 双重检查更保险 if (Math.abs(divisor) Number.EPSILON) { throw new Error(Division by zero); } const result dividend / divisor; return { content: [{ type: text, text: ${dividend} ÷ ${divisor} ${result.toFixed(4)} }] }; });4. 调试与集成技巧4.1 VS Code调试配置在.vscode/launch.json中添加这个配置可以方便调试{ version: 0.2.0, configurations: [ { type: node, request: launch, name: Debug MCP Server, skipFiles: [node_internals/**], program: ${workspaceFolder}/src/server.ts, outFiles: [${workspaceFolder}/dist/**/*.js] } ] }4.2 性能优化建议当工具调用频繁时可以考虑添加简单的缓存机制。比如对计算器来说可以缓存最近的计算结果const calculationCache new Mapstring, number(); function getCacheKey(operation: string, a: number, b: number): string { return ${operation}_${a}_${b}; } server.tool(add, 加法运算, { a: NumberSchema, b: NumberSchema }, async ({a, b}) { const cacheKey getCacheKey(add, a, b); if (calculationCache.has(cacheKey)) { return calculationCache.get(cacheKey); } const result a b; calculationCache.set(cacheKey, result); return { content: [{ type: text, text: ${a} ${b} ${result} }] }; });5. 进阶开发思路5.1 支持批量操作MCP协议支持批量调用工具我们可以扩展计算器支持批量计算server.batchTool(batch-calculate, 批量执行计算, { operations: z.array(z.object({ type: z.enum([add, subtract, multiply, divide]), a: NumberSchema, b: NumberSchema })) }, async ({operations}) { const results []; for (const op of operations) { let result: number; switch (op.type) { case add: result op.a op.b; break; case subtract: result op.a - op.b; break; case multiply: result op.a * op.b; break; case divide: result op.a / op.b; break; } results.push({ type: op.type, a: op.a, b: op.b, result }); } return { content: results.map(r ({ type: text, text: ${r.a} ${r.type} ${r.b} ${r.result} })) }; });5.2 添加日志监控生产环境建议添加详细的运行日志可以使用winston这样的日志库import winston from winston; const logger winston.createLogger({ level: info, format: winston.format.json(), transports: [ new winston.transports.File({ filename: error.log, level: error }), new winston.transports.File({ filename: combined.log }) ] }); // 在工具调用中添加日志 server.tool(add, 加法运算, { a: NumberSchema, b: NumberSchema }, async ({a, b}) { logger.info(Adding numbers: ${a} ${b}); const result a b; logger.info(Result: ${result}); return { content: [{ type: text, text: ${a} ${b} ${result} }] }; });