当前位置: 首页 > news >正文

从零到一:用TypeScript打造你的第一个MCP工具服务器

1. 为什么选择TypeScript开发MCP服务器

TypeScript作为JavaScript的超集,在开发MCP服务器时有着天然的优势。我刚开始接触MCP开发时也纠结过语言选择问题,但实际使用下来发现TypeScript的类型系统简直就是为MCP这类协议开发量身定制的。想象一下,当你在定义工具接口时,能够清晰地看到每个参数的类型和返回值结构,这种开发体验比纯JavaScript要舒服太多。

MCP(Model 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" } }

使用nodemon+ts-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 Map<string, 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}` }] }; });
http://www.jsqmd.com/news/488498/

相关文章:

  • Web前端技术选型:手机检测系统管理后台开发指南
  • 通义千问2.5-0.5B-Instruct部署教程:Windows本地运行指南
  • 魔兽世界私服搭建指南:从零开始轻松架设个人游戏服务器
  • VinXiangQi:AI驱动的中国象棋智能助手技术突破
  • 基于嘉立创梁山派与三环串级PID的O型独轮车自平衡与电磁循迹实战(附开源代码)
  • HTML5 Canvas贪吃蛇游戏开发实战:从零到可玩(附完整代码)
  • Qwen3-14b_int4_awq部署案例:低成本GPU服务器上运行14B大模型的实测分享
  • MySQL连表查询实战:从基础到高级应用
  • 光敏电阻选型避坑指南:从MG45到硫化铅的8个实战经验
  • Uniapp小程序微信登录实战:FastAPI后端如何安全处理AppSecret和session_key
  • Phi-3-vision-128k-instruct多模态安全机制解析:内容过滤与指令对齐设计
  • 新手友好:通过快马平台生成w777.7cc待办事项应用入门实例
  • DeEAR语音情感识别惊艳案例:低信噪比录音中仍稳定输出韵律维度判断
  • 3分钟上手抖音无水印批量下载工具:全场景解决方案让效率提升10倍
  • GD32L233C-START开发板ADC采样精度提升实战:巧用内部参考电压校准VDD波动
  • DASD-4B-Thinking在STM32开发中的应用探索
  • 企业级仓库管理系统设计:SpringBoot后端与Vue前端的完美结合
  • GME多模态向量-Qwen2-VL-2B学术应用:LaTeX论文中图表自动生成描述与索引
  • PyBullet新手必看:5分钟搞定mini cheetah机器人仿真(附完整URDF配置代码)
  • 视频创作者福音:HunyuanVideo-Foley智能音效生成,效果惊艳实测
  • 避开这3个坑!用wxauto对接ChatGPT API时遇到的权限问题和解决方案
  • uni-app跨页面通信实战:用events实现列表页-详情页双向数据更新
  • ACE-Step快速上手:无需乐理知识,三步生成视频配乐和背景音乐
  • ZYNQ双核AMP实战:构建独立运行的异构通信系统
  • 程序员学梅花易数:用Python模拟卦象生成与数理推演
  • draw.io二次开发实战:从零打造专属绘图工具的10个关键步骤
  • 宝塔面板性能优化实战:5个必做设置让你的服务器飞起来
  • 3个效率倍增点:AsrTools让智能语音处理效率提升80%
  • Mac 上配置 Emscripten 开发环境:从零到 WebAssembly
  • 拉格朗日乘子法实战:从等式约束到不等式优化的5个经典案例解析