1. Model Context Protocol(MCP) #
MCP(Model Context Protocol)是一套开放协议,用来让 AI 应用(如 Cursor、Claude Desktop)以统一方式连接数据库、文件、API 等能力。
2. 学前准备:你需要先懂什么 #
2.1 大模型与「工具调用」 #
大模型本身只能生成文字。若要让 AI「查天气」「读文件」「发请求」,需要宿主程序把模型的意图转成真实函数调用,再把结果塞回对话。MCP 规定的是:这些能力由独立的 Server 提供,Host 通过 Client 按统一协议去调用,而不是每个 AI 产品各写一套私有接口。
2.2 JSON-RPC 是什么 #
MCP 底层用 JSON-RPC 2.0 传消息:客户端发「请求」(带 method、params),服务端回「响应」(带 result 或 error)。你不必手写每一帧,SDK 会处理;但心里要有「一问一答、JSON 格式」的印象。
2.3 stdio 传输是什么意思 #
很多入门示例里,MCP Server 是一个独立 Node 进程,通过标准输入/标准输出(stdio)与 Client 交换 JSON 消息。Client 用 node server.js 拉起子进程,双方用管道通信。
3. MCP 解决什么问题 #
没有 MCP 时:Copilot 连数据库要写一套适配,换 Claude 又要写另一套,维护成本高。
有了 MCP 后:同一个 MCP Server(例如「读项目文件」「问候工具」)可以被多个支持 MCP 的 Host 复用,就像 USB 设备插不同电脑。对新手来说,先记住:MCP = 统一插头 + 约定好的消息格式。
4. 三个角色:Host、Client、Server #
| 角色 | 是什么 | 例子 |
|---|---|---|
| Host(主机) | 你直接使用的 AI 应用,负责对话、决定是否调工具 | Cursor、Claude Desktop |
| Client(客户端) | 跑在 Host 内部,与某一个 Server 保持连接 | Cursor 里连接 greeting 的那条配置 |
| Server(服务端) | 对外提供工具/资源的轻量程序 | 本教程的 02-mcp-server.js |
关系可以简化为:Host 内含 Client → Client 通过 stdio 连 Server → Server 执行工具并返回结果。
5. 三大能力:Tools、Resources、Prompts #
MCP 用三种「原语」描述 Server 能做什么。入门阶段最重要的是 Tools。
| 原语 | 含义 | 新手是否必学 |
|---|---|---|
| Tools(工具) | 可被 AI 调用 的函数,如 greet(name) |
必学,本教程示例只实现 Tools |
| Resources(资源) | 可被 AI 读取 的静态/半静态数据,如文件片段 | 了解即可 |
| Prompts(提示模板) | 预置的对话模板 | 了解即可,日常少用 |
6. 动手:看懂 JSON-RPC 消息形状 #
下面脚本不需要安装任何 npm 包,保存为 01-json-rpc-shape.js,执行 node 01-json-rpc-shape.js 即可。它模拟「调用 greet 工具」时,消息大致长什么样。
// 构造一条「调用工具」风格的 JSON-RPC 请求(教学用简化版)
const request = {
// 固定为 JSON-RPC 2.0 版本
jsonrpc: '2.0',
// 请求编号,用于和响应配对
id: 1,
// 方法名(真实 MCP 里会是 tools/call 等,这里用通俗名字)
method: 'tools/call',
// 参数:要调用的工具名和参数
params: {
name: 'greet',
arguments: { name: '小明' },
},
};
// 打印格式化的请求 JSON
console.log('=== 请求 ===');
console.log(JSON.stringify(request, null, 2));
// 构造对应的成功响应
const response = {
// 同样是 2.0
jsonrpc: '2.0',
// 与请求的 id 一致
id: 1,
// 成功时的结果体
result: {
content: [{ type: 'text', text: '你好,小明!' }],
},
};
// 打印格式化的响应 JSON
console.log('\n=== 响应 ===');
console.log(JSON.stringify(response, null, 2));说明: 真实 MCP 的 method 名称和字段由官方规范定义,SDK 会替你序列化。你只要建立「请求带 method + params,响应带 result」的印象即可。
7. 安装 MCP SDK #
在放练习脚本的目录打开终端,执行:
npm init -y
npm install @modelcontextprotocol/sdk zod@modelcontextprotocol/sdk:官方 MCP 的 Node 实现。zod:在注册工具时描述参数类型(新版 SDK 常用)。
8. 第一个 MCP Server:greet 工具 #
把下面整段保存为 02-mcp-server.js。它启动后不会在终端和你聊天,而是等待 Client 通过 stdio 发 MCP 消息;单独运行看起来「像卡住」是正常的。
// 从 SDK 引入 MCP 服务端类
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: 'greeting-server',
version: '1.0.0',
});
// 注册名为 greet 的工具
server.registerTool(
// 工具在协议中的名称
'greet',
{
// 给 AI 看的说明文字
description: '通过名字向某人问好',
// 参数 schema:需要一个字符串 name
inputSchema: {
name: z.string().describe('要问候的人的名字'),
},
},
// 工具被调用时执行的函数
async ({ name }) => ({
// 返回文本内容给客户端
content: [{ type: 'text', text: `你好,${name}!` }],
}),
);
// 主函数:绑定 stdio 并开始监听
async function main() {
// 创建 stdio 传输层
const transport = new StdioServerTransport();
// 让 server 在该传输上工作
await server.connect(transport);
}
// 启动;出错则打印并退出
main().catch((err) => {
console.error(err);
process.exit(1);
});要点: Server 进程一般由 Client 拉起,不要指望手动 node 02-mcp-server.js 后在同一窗口打字测试;下一节用专用测试脚本连接它。
9. 用客户端脚本测试 Server #
保存为 03-test-mcp-client.js,与 02-mcp-server.js 同一目录。运行 node 03-test-mcp-client.js,应看到工具列表和问候结果。
// 引入 path,用于拼接 server 脚本路径
const path = require('path');
// 引入 MCP 客户端类
const { Client } = require('@modelcontextprotocol/sdk/client/index.js');
// 引入 stdio 客户端传输(会 spawn 子进程连 server)
const { StdioClientTransport } = require('@modelcontextprotocol/sdk/client/stdio.js');
// 主流程写在异步函数里
async function main() {
// server 脚本与本文件同目录
const serverPath = path.join(__dirname, '02-mcp-server.js');
// 创建传输:用当前 Node 可执行文件启动 server 子进程
const transport = new StdioClientTransport({
command: process.execPath,
args: [serverPath],
});
// 创建 MCP 客户端
const client = new Client({
name: 'tutorial-test-client',
version: '1.0.0',
});
// 连接到 server(内部完成握手)
await client.connect(transport);
// 列出 server 提供的所有工具
const { tools } = await client.listTools();
// 打印工具名称列表
console.log(
'工具列表:',
tools.map((t) => t.name).join(', ') || '(无)',
);
// 调用 greet 工具
const result = await client.callTool({
name: 'greet',
arguments: { name: '世界' },
});
// 把返回的 content 里的 text 拼成一行
const text =
result.content
?.filter((c) => c.type === 'text')
.map((c) => c.text)
.join('') || '(无文本)';
// 打印调用结果
console.log('调用 greet 结果:', text);
// 关闭连接
await client.close();
}
// 运行并在失败时退出
main().catch((err) => {
console.error(err);
process.exit(1);
});预期输出(大意):
工具列表: greet
调用 greet 结果: 你好,世界!10. 在 Cursor 里使用 MCP #
学会写 Server 之后,可以把同一个 02-mcp-server.js 配进 Cursor,让编辑器里的 AI 也能调 greet。配置写在 Cursor 的 MCP 设置里(具体入口以你当前版本为准),形状通常类似:
{
"mcpServers": {
"greeting": {
"command": "node",
"args": ["D:\\你的路径\\02-mcp-server.js"]
}
}
}把 args 里的路径改成你本机 02-mcp-server.js 的绝对路径。保存后重启或刷新 MCP,在对话里让 AI 使用 greet 工具即可。若连不上,先确认 node 03-test-mcp-client.js 能成功,再查路径是否写对。
11. 常见误区 #
11.1 单独运行 Server 却等不到输出 #
MCP Server(stdio 模式)是在等 Client 发来的 JSON 消息,不是等你在终端输入。测试请用第 9 节的 03-test-mcp-client.js,或在 Cursor 里配置 MCP。
11.2 只有一两个 API 也要上 MCP 吗? #
若你只是自己写脚本调一个 HTTP 接口,直接 fetch 即可,不必强行上 MCP。MCP 适合「多种 AI 产品都要复用同一套工具」或「Host 已支持 MCP 生态」的场景。
11.3 Tools 和 Resources 别混 #
- Tool:执行动作(问好、发请求、写文件)。
- Resource:提供只读内容(文档片段、配置文本)。入门先掌握 Tool 即可。
12. 知识点速查 #
| 主题 | 记住这一句 |
|---|---|
| MCP 是什么 | AI 与外部能力之间的统一连接协议 |
| 三个角色 | Host 用 AI;Client 连 Server;Server 提供工具 |
| 入门重点 | Tools:可被调用的函数 |
| 本地传输 | 常用 stdio:Client spawn Server 进程 |
| 最小 Server | McpServer + registerTool + StdioServerTransport |
| 测试方式 | 用 Client + listTools / callTool,或配进 Cursor |