1. 项目概述:为什么我们需要一个MCP服务器模板?
如果你最近在折腾Claude、Cursor这类AI工具,想给它们“装”上一些自定义功能,比如让AI帮你查数据库、调用内部API,或者执行一些特定的脚本,那你大概率已经听说过Model Context Protocol(MCP)了。简单来说,MCP就是一套标准协议,它让AI助手(我们称之为“主机”,比如Claude Desktop)能够以一种安全、可控的方式,去调用你写的各种工具(我们称之为“服务器”)。这就像给你的AI助手装上了一套标准化的“插件系统”。
听起来很美好,对吧?但当你真正上手,想从零开始用TypeScript搭建一个MCP服务器时,可能会立刻遇到几个头疼的问题:协议规范怎么理解?SDK怎么用?工具函数怎么注册?响应格式怎么定义?安全和错误处理怎么做?更别提还要适配不同的AI平台(Claude、Cursor、Windsurf等)。这些琐碎但关键的细节,足以让一个充满热情的项目在起步阶段就陷入泥潭。
这就是TheSethRose/MCP-Server-Starter这个模板项目的价值所在。它不是一个简单的“Hello World”示例,而是一个由资深开发者Seth Rose精心打磨的、生产就绪的TypeScript MCP服务器脚手架。它帮你处理了所有底层的基础设施和样板代码,让你能跳过繁琐的协议实现和配置环节,直接聚焦于核心业务逻辑——也就是你真正想为AI构建的那个酷炫工具。无论你是想做一个智能计算器、一个股票查询工具,还是一个能操作你内部系统的自动化助手,这个模板都为你铺平了道路。
2. MCP核心概念与架构深度解析
在动手之前,我们必须先吃透MCP的几个核心角色和它们之间的关系。这能帮你理解你写的代码在整个生态中处于什么位置,以及数据是如何流动的。
2.1 MCP生态中的三大角色
一个完整的MCP交互,通常涉及三个部分,它们各司其职:
MCP服务器:这是你要构建的核心。它是一个独立的进程,封装了你想要暴露给AI的功能。比如,一个“天气查询服务器”内部可能封装了对某个天气API的调用逻辑;一个“代码分析服务器”可能封装了读取文件、运行静态检查的工具。服务器通过实现MCP协议(基于JSON-RPC 2.0),以标准化的方式对外提供“工具”、“资源”或“提示词”。你的主要工作就是在这里。
MCP主机:这是消费你服务器功能的AI应用平台。比如Claude Desktop、Cursor编辑器、Windsurf IDE等。主机负责与用户交互,理解用户的自然语言指令,并判断何时、如何调用你服务器提供的工具。主机通过MCP协议与服务器通信,它不关心你服务器的内部实现,只关心协议约定的接口。
MCP客户端:在技术实现上,主机内部会集成一个MCP客户端库(例如TypeScript SDK中的Client类)。这个客户端负责与服务器建立连接、发送请求(调用工具)和接收响应。对于服务器开发者来说,你通常不需要直接与客户端打交道,你的对手是“主机”,但理解这个中间层有助于调试。
2.2 协议基石:JSON-RPC 2.0
MCP选择JSON-RPC 2.0作为通信协议,这是一个非常明智的选择。它轻量、文本化、与语言无关,并且定义了一套清晰的请求-响应模型。
- 请求:当用户向AI主机提出一个需求(如“帮我计算一下15%的小费是多少”),主机识别出这可能需要调用“计算器”工具,于是它会向你的服务器发送一个JSON-RPC请求。这个请求体里会包含一个唯一的
id、要调用的method(对应你的工具名),以及params(用户输入的数字和操作类型)。 - 响应:你的服务器处理完计算后,会返回一个JSON-RPC响应,包含相同的
id、result(计算结果)或error(如果出错)。这个result的格式,正是MCP SDK帮你封装好的ToolResponse结构。
使用这个模板的最大好处之一,就是TypeScript SDK已经为你封装了所有JSON-RPC的底层细节。你不需要手动拼接和解析JSON字符串,只需要关注高层的工具函数实现。
2.3 TypeScript SDK:类型安全的力量
MCP TypeScript SDK是这个模板的基石。它提供了强类型支持,这意味着你在编码时就能获得IDE的自动补全和类型检查,极大减少了运行时错误。
Server类:这是你的服务器实例。你通过它来注册工具、定义能力、处理生命周期。StdioServerTransport类:这是最常用的传输层实现。它使用标准输入/输出与主机通信,简单高效,无需处理网络端口。对于本地集成的AI工具,这是首选。- 工具(Tools)、资源(Resources)、提示词(Prompts):这是MCP定义的三种核心能力。本模板主要聚焦于Tools,即让AI主动调用的函数。你注册的每一个工具,都必须有明确的输入参数模式(Schema)和返回格式。
注意:虽然MCP也支持Resources(让AI读取结构化数据)和Prompts(预定义的对话模板),但对于大多数自定义功能场景,Tools是最灵活、最常用的方式。这个模板的示例和结构也是围绕Tools构建的,让你能快速上手。
3. 项目结构与核心文件详解
拿到模板后,第一件事是理解它的目录结构。一个清晰的结构是项目可维护性的基础。这个模板采用了现代TypeScript项目的典型布局,并针对MCP开发做了优化。
mcp-server-starter/ ├── .devcontainer/ │ └── devcontainer.json ├── src/ │ ├── index.ts │ └── examples/ │ ├── calculator.ts │ └── rest-api.ts ├── build/ ├── package.json ├── tsconfig.json └── README.md3.1 入口文件:src/index.ts
这是服务器的“大脑”和“总控中心”。让我们拆解一下它的典型内容:
// 1. 导入核心SDK import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // 2. 创建服务器实例,声明身份和能力 const server = new Server( { name: "my-mcp-server", // 你的服务器唯一标识 version: "1.0.0", }, { capabilities: { tools: {}, // 声明本服务器提供工具能力 // resources: {}, // 如需资源能力,取消注释 // prompts: {}, // 如需提示词能力,取消注释 }, } ); // 3. 注册工具 // 这里会导入并注册你在其他文件定义的工具 import { registerCalculatorTool } from "./examples/calculator.js"; import { registerRestApiTool } from "./examples/rest-api.js"; registerCalculatorTool(server); registerRestApiTool(server); // 4. 启动服务器,连接传输层 async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("MCP Server running on stdio"); // 使用 console.error 避免干扰协议通信 } main().catch((error) => { console.error("Server fatal error:", error); process.exit(1); });关键点解析:
name和version:这不仅是元信息。当AI主机连接多个服务器时,它们靠这个来区分。取一个清晰的名字很重要。capabilities:这里像一份“功能菜单”,告诉主机你提供哪些类型的服务。只声明你实际实现的能力。console.error:这是一个非常重要的细节。MCP协议使用标准输出(stdout)进行JSON-RPC通信。因此,任何调试信息或日志必须输出到标准错误(stderr),通常是console.error,否则会污染协议流,导致连接中断。
3.2 工具示例:src/examples/calculator.ts
这是理解如何构建一个MCP工具的绝佳范例。它演示了一个完整的、类型安全的工具实现流程。
import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { z } from "zod"; // 用于运行时输入验证 // 1. 定义输入参数的验证模式(Schema) // 使用Zod库,它既能提供运行时校验,也能推断出TypeScript类型 const CalculatorSchema = z.object({ a: z.number().describe("The first operand"), // 描述信息会帮助AI理解参数 b: z.number().describe("The second operand"), operation: z.enum(["add", "subtract", "multiply", "divide"]) .describe("The arithmetic operation to perform"), }); // 2. 实现工具逻辑函数 async function calculate(params: z.infer<typeof CalculatorSchema>) { const { a, b, operation } = params; let result: number; switch (operation) { case "add": result = a + b; break; case "subtract": result = a - b; break; case "multiply": result = a * b; break; case "divide": if (b === 0) { // 3. 错误处理:返回格式化的错误响应 return { content: [{ type: "text", text: "Error: Division by zero is not allowed.", }], isError: true, // 关键标志位,告知主机这是一个错误 }; } result = a / b; break; default: // 理论上不会走到这里,因为Zod已经验证了enum throw new Error(`Unsupported operation: ${operation}`); } // 4. 构造成功的MCP标准响应 return { content: [ { type: "text", text: `The result of ${a} ${operation} ${b} is ${result}.`, }, // 你可以返回多种类型的内容,比如同时返回文本和代码 { type: "code", text: `const result = ${a} ${operation === 'add' ? '+' : operation === 'subtract' ? '-' : operation === 'multiply' ? '*' : '/'} ${b}; // ${result}`, mimeType: "application/javascript", }, ], }; } // 5. 工具注册函数(供index.ts调用) export function registerCalculatorTool(server: Server) { server.setRequestHandler("tools/call", async (request) => { // 这里通常会有路由逻辑,根据request.params.name调用不同的工具 // 但更常见的模式是使用SDK的`server.tool`方法(如果SDK版本支持) // 以下演示一种手动注册的方式: if (request.params.name === "calculate") { // 使用Zod验证输入 const validatedParams = CalculatorSchema.parse(request.params.arguments); return calculate(validatedParams); } // ... 处理其他工具 }); }实操心得:
- Zod是黄金搭档:MCP SDK本身不强制验证输入,但强烈建议使用Zod。它能确保传入的参数格式正确,避免工具内部因类型错误而崩溃。
z.infer<typeof Schema>还能自动生成TypeScript类型,实现“一处定义,两处使用”。 - 描述性文本:在Schema中使用
.describe()为参数添加描述。这些描述会被AI主机看到,帮助AI更好地理解何时以及如何使用你的工具,甚至能生成更准确的提示。 - 响应结构是核心:MCP要求返回特定格式的
ToolResponse。content数组可以包含多个条目,支持text、code、image等类型。这让你能返回丰富的结果,比如既给出答案,又给出实现答案的代码片段。
3.3 配置与构建:package.json与tsconfig.json
package.json:定义了项目依赖和脚本。核心依赖是@modelcontextprotocol/sdk和zod。脚本部分,npm run build会编译TypeScript并确保输出文件有可执行权限;npm run watch在开发时非常有用,可以实时编译;npm run inspector则启动调试模式。tsconfig.json:TypeScript编译器配置。模板通常配置为输出到build目录,模块系统为ES2022,以兼容现代Node.js环境。确保"outDir"设置正确,因为AI主机启动服务器时,执行的就是build/index.js。
4. 从开发到集成:完整实操流程
理解了核心概念和代码结构后,我们来看如何从零开始,创建一个新的MCP工具并让它被AI主机调用。
4.1 环境准备与项目初始化
获取模板:最推荐的方式是使用GitHub模板功能或直接克隆仓库。
git clone https://github.com/TheSethRose/mcp-server-starter.git my-awesome-tool cd my-awesome-tool安装依赖:
npm install这一步会拉取MCP SDK、TypeScript、Zod以及其他开发依赖。
探索与清理:打开项目,先浏览一遍
src/examples/下的示例。你可以保留它们作为参考,也可以删除,开始创建自己的工具。我建议先保留,边做边对照。
4.2 创建你的第一个自定义工具:一个“待办事项”管理器
假设我们想创建一个简单的待办事项(Todo)管理工具,让AI能帮我们添加、查看任务。
创建工具文件:在
src/下新建tools/todo.ts。// src/tools/todo.ts import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { z } from "zod"; // 简单的内存存储(生产环境请用数据库) let todoList: string[] = []; // 1. 定义“添加待办”工具的参数模式 const AddTodoSchema = z.object({ task: z.string().min(1).describe("The description of the new todo task"), }); // 2. 定义“列出待办”工具的参数模式(无参数) const ListTodosSchema = z.object({}); // 空对象表示不需要参数 // 3. 实现“添加待办”工具函数 async function addTodo(params: z.infer<typeof AddTodoSchema>) { const { task } = params; todoList.push(task); return { content: [{ type: "text", text: `Task added successfully: "${task}". Total tasks: ${todoList.length}`, }], }; } // 4. 实现“列出待办”工具函数 async function listTodos() { if (todoList.length === 0) { return { content: [{ type: "text", text: "Your todo list is currently empty.", }], }; } const listText = todoList.map((t, i) => `${i + 1}. ${t}`).join('\n'); return { content: [{ type: "text", text: `Here are your tasks:\n${listText}`, }], }; } // 5. 工具注册函数 export function registerTodoTools(server: Server) { // 注册 addTodo 工具 server.setRequestHandler("tools/call", async (request) => { if (request.params.name === "addTodo") { const validatedParams = AddTodoSchema.parse(request.params.arguments); return addTodo(validatedParams); } if (request.params.name === "listTodos") { // 即使无参数,也解析一下空对象以确保结构正确 ListTodosSchema.parse(request.params.arguments || {}); return listTodos(); } // 如果工具名不匹配,返回null,SDK会处理成“方法未找到”错误 return null; }); }在入口文件中注册新工具:修改
src/index.ts。// ... 其他导入 ... import { registerTodoTools } from "./tools/todo.js"; // 注意导入编译后的.js文件 // ... 创建server ... // 注册工具 registerTodoTools(server); // ... 可以注释掉原来的示例工具,或保留 ... // ... 启动代码 ...构建项目:
npm run build确保
build目录下生成了对应的todo.js文件。
4.3 本地测试与调试:使用MCP Inspector
在集成到AI主机前,强烈建议先用官方提供的MCP Inspector进行测试。它是一个独立的调试工具,可以模拟AI主机与你的服务器交互。
启动Inspector:
npm run inspector这个命令会同时启动你的服务器和Inspector的Web界面(通常是一个本地URL)。
在Inspector界面中测试:
- 打开浏览器访问提示的URL(如
http://localhost:5173)。 - 你应该能在“Tools”标签页下看到你注册的
addTodo和listTodos工具。 - 在工具详情页,输入JSON格式的参数,例如
{"task": "Buy milk"},然后点击“Call”。 - 观察右侧的响应区域,应该能看到成功的返回信息。
- 再调用
listTodos,应该能看到刚添加的任务。
- 打开浏览器访问提示的URL(如
这个步骤至关重要。它能帮你:
- 验证工具是否被正确注册和发现。
- 测试参数验证(Zod Schema)是否工作。尝试传入错误类型的参数,看是否会返回验证错误。
- 检查响应格式是否符合MCP规范。
- 在受控环境下调试工具逻辑,无需启动笨重的AI应用。
4.4 集成到AI主机:以Claude Desktop为例
测试通过后,就可以让真正的AI来使用你的工具了。这里以Claude Desktop为例。
找到Claude Desktop的配置目录:
- macOS:
~/Library/Application Support/Claude/ - Windows:
%APPDATA%\Claude\ - Linux:
~/.config/Claude/
- macOS:
编辑MCP服务器配置文件: 在上述目录下,找到或创建
claude_desktop_config.json文件。{ "mcpServers": { "my-todo-server": { "command": "node", "args": ["/ABSOLUTE/PATH/TO/YOUR/PROJECT/build/index.js"] } } }my-todo-server:给你的服务器起个名字,会在Claude界面中显示。command:必须是node。args:数组,第一个元素必须是你的服务器入口文件的绝对路径。这是最容易出错的地方,请务必使用完整路径。
重要提示:在Windows上,路径分隔符要用双反斜杠或正斜杠,例如
"C:\\Users\\Name\\project\\build\\index.js"或"C:/Users/Name/project/build/index.js"。重启Claude Desktop:完全退出并重新启动Claude Desktop应用,让它加载新的配置。
验证与使用:
- 打开Claude Desktop,新建一个对话。
- 在输入框附近,如果集成成功,你应该能看到一个微小的服务器图标或提示,表明已连接的MCP服务器。
- 现在,你可以直接对Claude说:“请使用我的待办工具,添加一个任务‘阅读MCP文档’。” Claude应该能识别出
addTodo工具,并调用它。成功后,Claude会回复你工具返回的结果。 - 再说:“列出我所有的待办事项。” Claude应该会调用
listTodos工具。
4.5 使用Smithery进行一键部署与分享
手动配置路径对于分享你的工具给他人非常不友好。Smithery提供了一个优雅的解决方案。它相当于一个MCP服务器的“应用商店”和“运行时管理器”。
通过Smithery运行他人(或模板)的服务器:
npx -y @smithery/cli install @TheSethRose/mcp-server-starter --client claude这条命令会自动下载、安装并配置指定的MCP服务器到你的Claude Desktop中,无需手动编辑配置文件。对于终端用户来说,这是最友好的安装方式。
发布你自己的服务器到Smithery: 当你开发了一个有价值的工具并想分享给社区时,可以将其发布到Smithery。
- 在Smithery.ai注册账号。
- 按照其文档,你需要创建一个
smithery.yaml配置文件,定义如何构建和运行你的服务器。 - 通过GitHub Actions或Smithery CLI发布你的包。
- 之后,其他人就可以用
npx -y @smithery/cli install <your-package-name> --client claude来安装你的工具了。
5. 高级特性与生产环境最佳实践
当你的工具从玩具走向生产,以下几个方面的考虑就变得至关重要。
5.1 安全:输入验证、错误处理与资源管理
模板中提到的安全最佳实践不是空话,每一条都可能防止一次严重的生产事故。
- 深度防御的输入验证:除了用Zod做基础类型和格式校验,还要考虑业务逻辑校验。
const DangerousToolSchema = z.object({ url: z.string().url().describe("A URL to fetch"), timeout: z.number().int().positive().max(10000).describe("Timeout in ms, max 10s") }); async function fetchSafely(params: z.infer<typeof DangerousToolSchema>) { // 额外的安全检查:禁止访问内网IP const urlObj = new URL(params.url); const hostname = urlObj.hostname; if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname.startsWith('192.168.')) { return { content: [{ type: 'text', text: 'Access to local network resources is not allowed.' }], isError: true }; } // ... 使用timeout进行fetch ... } - 绝不暴露内部错误的错误处理:在catch块中,记录详细的错误到你的日志系统(如Winston、Pino),但只返回泛化的错误信息给AI。
try { // ... 一些可能失败的操作 ... } catch (error: any) { // 内部记录 logger.error('Tool X failed', { error: error.stack, params }); // 对外返回 return { content: [{ type: 'text', text: 'The service is temporarily unavailable. Please try again later.' }], isError: true }; } - 资源清理:如果你的工具打开了文件句柄、数据库连接或网络请求,确保在
finally块或使用try...catch...finally进行清理。对于长时间运行的操作,实现超时机制。
5.2 支持流式响应
对于需要长时间处理或生成大量内容的工具(如实时日志跟踪、长文本生成),MCP支持流式响应。这能提供更好的用户体验。
import { Server } from "@modelcontextprotocol/sdk/server/index.js"; server.setRequestHandler("tools/call", async (request, extra) => { if (request.params.name === "streamNumbers") { // 注意:这是一个异步生成器函数 return (async function* () { for (let i = 1; i <= 5; i++) { // 模拟一些延迟 await new Promise(resolve => setTimeout(resolve, 500)); // 多次yield返回部分结果 yield { content: [{ type: "text", text: `Chunk ${i} delivered.\n`, }], }; } // 最后可以yield一个最终状态(可选) yield { content: [{ type: "text", text: `Streaming completed.`, }], }; })(); } return null; });当AI主机(如支持流式响应的Claude)调用此工具时,用户会看到文字一段一段地出现,而不是等待全部处理完。
5.3 配置管理与环境变量
硬编码配置(如API密钥、数据库连接字符串)是安全漏洞和运维噩梦。务必使用环境变量。
- 安装
dotenv:npm install dotenv - 创建
.env文件(并加入.gitignore):WEATHER_API_KEY=your_secret_key_here DATABASE_URL=postgresql://user:pass@localhost/db SERVER_PORT=3000 - 在入口文件顶部加载:
import * as dotenv from 'dotenv'; dotenv.config(); // 加载 .env 文件中的变量到 process.env - 在工具中使用:
const apiKey = process.env.WEATHER_API_KEY; if (!apiKey) { throw new Error('WEATHER_API_KEY environment variable is not set'); } // 使用 apiKey ... - 为不同主机提供配置:在
claude_desktop_config.json中,可以通过env字段传递环境变量(如果主机支持),但更常见的做法是在服务器启动脚本中设置,或依赖用户系统的环境变量。
5.4 日志与监控
一个健壮的服务器需要可观察性。
- 结构化日志:不要只用
console.error。使用像winston或pino这样的日志库,它们支持日志级别、结构化JSON输出、日志轮转等。import winston from 'winston'; const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [new winston.transports.File({ filename: 'mcp-server.log' })], }); logger.info('Tool called', { toolName: 'calculate', params }); - 性能监控:在工具函数开始和结束时记录时间,计算耗时,对于性能瓶颈分析很有帮助。
- 健康检查端点:如果你的服务器使用WebSocket等网络传输,可以考虑增加一个简单的HTTP健康检查端点,方便容器编排系统(如Kubernetes)探测服务状态。
6. 常见问题与排查技巧实录
在实际开发和集成过程中,你几乎一定会遇到下面这些问题。这里是我踩过坑后总结的排查清单。
6.1 服务器启动失败或立即退出
- 症状:运行
node build/index.js后进程立刻结束,或者Claude Desktop提示无法连接服务器。 - 排查步骤:
- 检查Node.js版本:
node --version,确保是v18或更高。MCP SDK可能依赖较新的API。 - 检查依赖:确保
npm install已成功执行,node_modules存在且完整。 - 检查构建输出:
npm run build是否成功?build/index.js文件是否存在且内容正常? - 检查入口文件语法:在
index.ts开头加一句console.error('Server starting...'),看是否输出。如果没有,可能是TS编译错误或文件路径问题。 - 使用Inspector调试:
npm run inspector是黄金标准。如果Inspector都连不上,问题一定出在服务器代码本身。
- 检查Node.js版本:
6.2 AI主机无法发现或调用工具
- 症状:Claude/Cursor连接了服务器,但在对话中从不主动使用工具,或者手动提示它使用也说“找不到工具”。
- 排查步骤:
- 验证工具注册:确保你的
registerXxxTool(server)函数确实被index.ts调用,并且没有在运行时抛出异常。 - 检查工具名:在
server.setRequestHandler中判断的request.params.name字符串,必须与AI主机尝试调用的工具名完全一致(大小写敏感)。在Inspector里确认工具名。 - 检查Schema描述:为工具参数添加清晰、完整的
.describe()。AI主机(尤其是Claude)会利用这些描述来判断在什么上下文下调用哪个工具。描述越准确,AI的调用就越精准。 - 主机配置重启:修改Claude Desktop的
claude_desktop_config.json后,必须完全退出并重启Claude Desktop,仅仅刷新界面是不够的。 - 查看主机日志:Claude Desktop等应用通常有日志文件。查看日志中是否有关于MCP服务器连接或工具加载的错误信息。日志位置通常在配置目录附近。
- 验证工具注册:确保你的
6.3 工具被调用但返回意外错误
- 症状:AI调用了工具,但返回了错误,或者在Inspector中测试失败。
- 排查步骤:
- 优先使用Inspector:在Inspector中手动调用,复现问题。这里能看到原始的请求和响应JSON,比通过AI调试直观得多。
- 检查参数格式:在Inspector中,确保你输入的参数JSON格式正确,且类型符合Zod Schema的定义。例如,数字不要写成字符串
"5"。 - 检查Zod错误:如果Zod验证失败,SDK会返回一个包含验证错误的响应。仔细阅读错误信息,它通常会明确指出哪个字段不符合预期。
- 检查工具内部逻辑:在工具函数内部添加详细的
console.error日志,输出中间状态。确保异步操作使用了await。 - 检查响应格式:确保你的工具函数返回的对象严格符合
ToolResponse接口。content必须是数组,每个元素必须有type字段。一个常见的错误是直接返回了一个字符串或一个非标准对象。
6.4 性能问题或服务器无响应
- 症状:工具调用很慢,或者调用后服务器卡死,导致AI主机超时。
- 排查步骤:
- 实现超时:在工具函数内部,对任何可能长时间阻塞的操作(网络请求、复杂计算)设置超时。
async function callWithTimeout(promise, ms) { const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`Operation timed out after ${ms}ms`)), ms) ); return Promise.race([promise, timeout]); } - 避免同步阻塞:不要在工具函数中执行CPU密集型的同步操作(如大型循环、复杂加密)。如果必须,考虑将其放入工作线程或拆分成小块。
- 检查外部依赖:如果你的工具调用外部API或数据库,可能是这些外部服务响应慢。为它们也配置合理的超时和重试机制。
- 使用流式响应:对于长时间运行的任务,如前所述,改用流式响应,定期向客户端发送进度更新,避免单次响应过大或等待时间过长。
- 实现超时:在工具函数内部,对任何可能长时间阻塞的操作(网络请求、复杂计算)设置超时。
6.5 跨平台路径问题
- 症状:在macOS上工作正常,在Windows上配置失败。
- 解决方案:
- 绝对路径:在
claude_desktop_config.json的args中,始终使用绝对路径。 - 路径分隔符:在Windows的JSON配置中,使用双反斜杠
\\或正斜杠/。 - 使用环境变量:可以考虑在配置中使用环境变量来构造路径,但这依赖于主机是否支持展开环境变量。更可靠的方法是写一个简单的启动脚本(
.bat或.sh),在脚本中处理路径,然后在配置中指向这个脚本。
- 绝对路径:在
经过以上六个部分的拆解,你应该已经从“知道MCP是什么”进阶到“能够构建并部署一个健壮的MCP生产级工具”了。这个模板的价值在于它提供了一个坚实的起点,而真正的魔法在于你基于它构建的、解决实际问题的工具。从今天开始,试着把你的一个常用脚本、一个内部API或者一个复杂的工作流,封装成一个MCP工具,你会发现,让AI成为你的得力助手,原来可以如此直接和高效。