1. 这个 SDK 是做什么的 #
MCP 是协议(消息格式、能力约定);@modelcontextprotocol/sdk 是官方提供的 JavaScript/TypeScript 实现,帮你处理:
- JSON-RPC 消息的收发与握手
McpServer上注册 Tool、声明参数类型Client连接 Server、listTools、callTool
你不用自己拼每一帧 JSON;按 SDK 的 API 写 Server/Client 即可。
2. 学前准备 #
2.1 zod 是做什么的 #
新版 SDK 注册 Tool 时,常用 zod 描述参数类型(如 z.string()、z.number())。它会在注册阶段生成 JSON Schema,供 AI 客户端理解「这个工具要传哪些字段」。
只需会写:
inputSchema: { name: z.string().describe('名字') }2.3 stdio 传输 #
- Server:
StdioServerTransport—— 从 stdin 读、向 stdout 写 MCP 消息。 - Client:
StdioClientTransport—— 用spawn启动 Server 子进程,与子进程 stdin/stdout 通信。
3. 安装 #
在练习目录打开终端(PowerShell 或 CMD):
npm init -y
npm install @modelcontextprotocol/sdk zod@modelcontextprotocol/sdk:MCP 官方 SDK。zod:Tool 的inputSchema依赖(与 SDK 配套使用)。
4. Server 端:McpServer 与 registerTool #
Server 端典型步骤:
new McpServer({ name, version })server.registerTool(工具名, { description, inputSchema }, 回调)await server.connect(new StdioServerTransport())
回调返回形如 { content: [{ type: 'text', text: '...' }] } 的结果,Client 的 callTool 会收到。
下面整段保存为 01-mcp-server.js。单独 node 01-mcp-server.js 会看起来像「卡住」——它在等 Client 发消息,属正常现象。
// 从 SDK 服务端入口引入 McpServer
const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp.js');
// 引入 stdio 传输(标准输入/输出)
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
// 引入 zod,定义工具参数类型
const { z } = require('zod');
// 创建 MCP 服务实例
const server = new McpServer({
name: 'sdk-tutorial-server',
version: '1.0.0',
});
// 注册名为 greet 的工具
server.registerTool(
// 工具名称(Client 调用时用这个名字)
'greet',
{
// 给 AI / 人类看的说明
description: '通过名字向某人问好',
// 参数:一个字符串 name
inputSchema: {
name: z.string().describe('要问候的人的名字'),
},
},
// 被调用时执行;参数来自 Client 的 arguments
async ({ name }) => ({
content: [{ type: 'text', text: `你好,${name}!` }],
}),
);
// 异步主函数
async function main() {
// 创建 stdio 传输
const transport = new StdioServerTransport();
// 绑定传输并开始处理消息
await server.connect(transport);
}
// 启动;失败则打印并退出
main().catch((err) => {
console.error(err);
process.exit(1);
});5. Client 端:连接、列工具、调用 #
Client 端典型步骤:
new StdioClientTransport({ command, args })拉起 Server 进程new Client({ name, version })await client.connect(transport)await client.listTools()/await client.callTool({ name, arguments })await client.close()
保存为 02-mcp-client.js,与 01-mcp-server.js 同目录。运行:
node 02-mcp-client.js// 拼接 server 脚本路径
const path = require('path');
// SDK 客户端类
const { Client } = require('@modelcontextprotocol/sdk/client/index.js');
// stdio 客户端传输
const { StdioClientTransport } = require('@modelcontextprotocol/sdk/client/stdio.js');
// 主流程
async function main() {
// 与本文件同目录的 server 脚本
const serverPath = path.join(__dirname, '01-mcp-server.js');
// 用当前 Node 启动 server 子进程
const transport = new StdioClientTransport({
command: process.execPath,
args: [serverPath],
});
// 创建 Client(名称/version 会在握手时上报)
const client = new Client({
name: 'sdk-tutorial-client',
version: '1.0.0',
});
// 连接并完成 MCP 握手
await client.connect(transport);
// 列出 Server 注册的所有工具
const { tools } = await client.listTools();
console.log(
'SDK 返回的工具:',
tools.map((t) => t.name).join(', '),
);
// 调用 greet
const result = await client.callTool({
name: 'greet',
arguments: { name: 'SDK' },
});
// 提取 text 类型内容
const text =
result.content
?.filter((item) => item.type === 'text')
.map((item) => item.text)
.join('') || '(无文本)';
console.log('callTool 结果:', text);
// 关闭连接与子进程
await client.close();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});预期输出(大意):
SDK 返回的工具: greet
callTool 结果: 你好,SDK!6. SDK 常用 API 对照(Server / Client) #
入门阶段记住下表即可;方法名以你安装的 SDK 版本为准,若报错请对照 npm 文档。
| 端 | 类 / 方法 | 作用 |
|---|---|---|
| Server | McpServer |
创建服务 |
| Server | registerTool(...) |
注册可被调用的工具 |
| Server | StdioServerTransport |
stdio 通信 |
| Server | server.connect(transport) |
开始监听 |
| Client | Client |
创建客户端 |
| Client | StdioClientTransport |
spawn Server |
| Client | client.connect(transport) |
握手连接 |
| Client | client.listTools() |
获取工具列表 |
| Client | client.callTool({ name, arguments }) |
调用工具 |
| Client | client.close() |
断开连接 |
7. 把 MCP 工具转成 OpenAI 风格 schema(可选) #
mcp_client.js 会把 listTools() 的结果转成 DeepSeek / OpenAI 的 tools 数组。
// path
const path = require('path');
// Client
const { Client } = require('@modelcontextprotocol/sdk/client/index.js');
// stdio 传输
const { StdioClientTransport } = require('@modelcontextprotocol/sdk/client/stdio.js');
// 将 MCP 的 tool 定义转为 OpenAI tools 数组里的一项(简化版)
function mcpToolToOpenAI(tool) {
const schema = tool.inputSchema || { type: 'object', properties: {} };
return {
type: 'function',
function: {
name: tool.name,
description: tool.description || `MCP 工具:${tool.name}`,
parameters: schema,
},
};
}
async function main() {
const serverPath = path.join(__dirname, '01-mcp-server.js');
const transport = new StdioClientTransport({
command: process.execPath,
args: [serverPath],
});
const client = new Client({ name: 'schema-demo', version: '1.0.0' });
await client.connect(transport);
const { tools } = await client.listTools();
const openAiTools = tools.map(mcpToolToOpenAI);
console.log(JSON.stringify(openAiTools, null, 2));
await client.close();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});说明: 真实 Agent 会把这类 schema 传给 Chat Completions 的 tools 参数;收到 tool_calls 后再 callTool 把结果写回对话。
8. 知识点速查 #
| 主题 | 记住这一句 |
|---|---|
| 包名 | @modelcontextprotocol/sdk |
| Server 核心 | McpServer + registerTool + StdioServerTransport |
| Client 核心 | Client + StdioClientTransport + listTools / callTool |
| 参数类型 | 用 zod 写 inputSchema |
| 本地测试 | Client spawn Server,不要单独测 Server stdin |