🛠️ 使用 Model Context Protocol (MCP) SDK 构建 AI 工具服务
摘要
Model Context Protocol (MCP) 是一个规范,允许 AI 模型(如大型语言模型 LLM)与外部工具(Tools)或服务进行通信。本文将通过一个简单的 "计算器" 示例,演示如何使用 TypeScript 和 @modelcontextprotocol/sdk 快速构建一个遵循 MCP 规范的工具服务器,并使其能够被任何支持 MCP 的 AI 模型所调用。
必备
如何不了解MCP是什么请三分钟了解此文章MCP 入门小短文
1. 为什么需要 MCP?
LLM 具有强大的推理和生成能力,但它们通常缺乏实时信息获取、复杂计算或执行外部操作的能力。MCP 旨在解决这一问题,它为 LLM 提供了一个标准化的通信接口,使其能够:
-
查询 服务端有哪些工具可用(Tools)。
-
调用 特定工具并传递参数。
-
接收 工具的执行结果。
2. 环境准备与依赖
我们需要安装 Model Context Protocol 的 SDK 以及用于数据验证的 zod 库。
Bash
npm install @modelcontextprotocol/sdk zod
# TypeScript 环境下安装类型定义
npm install -D typescript @types/node
3. 核心代码分析与实现
我们将分析您提供的模板代码,它定义了一个名为 calculator 的工具服务。
3.1 导入模块与定义结构
TypeScript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod"; // 用于参数的强类型验证
-
Server:MCP 服务器的核心类。 -
StdioServerTransport:定义了服务器与客户端(即 AI 模型)之间通过标准输入/输出 (stdio) 进行通信的方式。这在沙箱或命令行环境中非常常见。 -
zod:在 TypeScript 中提供运行时验证,确保从 AI 模型接收到的参数是正确的类型和结构。
3.2 服务器初始化
我们初始化一个 Server 实例,并为其命名和版本号。
TypeScript
const server = new Server(
{
name: "calculator",
version: "1.0.0",
},
{
capabilities: {
tools: {}, // 表明这是一个工具服务
},
}
);
3.3 定义工具列表(ListToolsRequest 处理)
当 AI 模型想要知道它能做什么时,它会发送一个 ListToolsRequest。服务器需要注册一个处理程序来响应这个请求,并以 OpenAPI Schema 的格式描述工具的功能。
TypeScript
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "add",
description: "计算两个数字的和",
// inputSchema 必须遵循 JSON Schema 规范
inputSchema: {
type: "object",
properties: {
a: { type: "number", description: "第一个数字" },
b: { type: "number", description: "第二个数字" },
},
required: ["a", "b"],
},
},
],
};
});
关键点: inputSchema 是 AI 模型理解如何调用这个工具的"说明书"。LLM 会解析这个 Schema 来生成正确的 JSON 参数。
3.4 处理工具调用(CallToolRequest 处理)
这是执行实际功能的逻辑所在。当 AI 模型决定调用 add 工具时,它会发送一个 CallToolRequest。
TypeScript
// 定义参数验证模式
const AddArgumentsSchema = z.object({
a: z.number().describe("第一个数字"),
b: z.number().describe("第二个数字"),
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
if (name === "add") {
// 1. 使用 Zod 验证参数
const { a, b } = AddArgumentsSchema.parse(args);
const result = a + b;
// 2. 返回结果
return {
content: [
{
type: "text",
text: `${a} + ${b} = ${result}`,
},
],
};
} else {
throw new Error(`未知的工具: ${name}`);
}
} catch (error) {
// 3. 错误处理,特别是参数验证错误
// ... (ZodError 处理逻辑)
throw error;
}
});
关键点:
-
参数验证: 使用
Zod对接收到的args进行严格验证,防止 LLM 生成的参数格式或类型错误。 -
返回结构: 工具执行的结果必须封装在
{ content: [...] }结构中,以便 LLM 能够将其作为上下文信息解析。
3.5 启动服务
最后,我们通过 StdioServerTransport 启动服务,监听标准输入/输出的 MCP 消息。
TypeScript
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Calculator MCP Server running on stdio"); // 错误日志输出到 stderr
}
main().catch(/* ... 错误处理 */);
3.6 接入客户端
改动args参数为你本地磁盘路径
样例:
typescript
"calculator": {
"timeout": 60,
"type": "stdio",
"command": "node",
"args": [
"C:\\Users\\wangqian\\Desktop\\mcp-demo\\mcp-client\\build\\calculator.js"
]
}
4. 总结与展望
通过以上步骤,我们成功构建了一个符合 Model Context Protocol 规范的"计算器"工具服务。
-
对于开发者: MCP 提供了一种标准、强类型的方式来构建外部服务。
-
对于 AI 模型: LLM 现在可以通过标准的
ListTools和CallTool流程,安全、准确地调用我们的add函数来解决计算问题。
这种模式不仅限于计算器,还可以扩展到 实时天气查询 、数据库查询 、外部 API 调用等更复杂的工具,极大地增强了 AI 模型的功能边界。
如何遇到其他问题可参考
参考文章:
MCP官网:简介 - MCP 官方文档中文版
面向Nodejs开发人员MCP快速入门Site Unreachable