MCP 协议详解:从原理到手把手实现一个 MCP Server
文章深入解析了MCP的核心架构与实现: 协议定位:作为AI世界的"USB-C接口",MCP通过JSON-RPC 2.0实现跨平台通信,解决传统M×N集成难题。 核心架构:采用客户端-服务器模式,支持stdio和HTTP+SSE两种传输方式,实现LLM应用与工具服务的解耦。
Model Context Protocol (MCP) 是 Anthropic 推出的开放协议,旨在为 LLM 提供标准化的外部工具和数据源接入方式。本文将深入解析 MCP 协议的设计理念、核心架构,并带你从零实现一个完整的 MCP Server。
目录
- 一、什么是 MCP
- 二、为什么需要 MCP
- 三、MCP 核心架构
- 四、协议通信机制
- 五、MCP 生命周期
- 六、核心能力详解
- 七、手把手实现一个 MCP Server
- 八、进阶:Resources 与 Prompts
- 九、调试与测试
- 十、最佳实践与总结
一、什么是 MCP
MCP (Model Context Protocol) 是一个开放的、基于 JSON-RPC 2.0 的协议,它定义了 LLM 应用(客户端)与外部数据源/工具(服务器)之间的标准化通信方式。
你可以把 MCP 理解为 AI 世界的 USB-C 接口:
- 就像 USB-C 让各种设备通过统一接口连接一样,MCP 让各种 AI 应用通过统一协议接入外部能力
- 无论是文件系统、数据库、API 服务,还是浏览器控制,都可以通过 MCP 暴露给 LLM
核心设计原则
| 原则 | 说明 |
|---|---|
| 标准化 | 统一的协议规范,任何客户端都能连接任何服务端 |
| 安全性 | 服务端主动暴露能力,客户端需授权才能调用 |
| 可组合性 | 一个客户端可连接多个服务端,能力可叠加 |
| 语言无关 | 协议基于 JSON-RPC,任何语言都能实现 |

二、为什么需要 MCP
在 MCP 出现之前,每个 AI 应用都需要为每个外部工具编写定制的集成代码。这导致了 M×N 问题:
没有 MCP:
应用 A ──定制代码──> 工具 1
应用 A ──定制代码──> 工具 2
应用 B ──定制代码──> 工具 1
应用 B ──定制代码──> 工具 2
→ 需要 M × N 个集成
有了 MCP:
应用 A ──MCP──> MCP Server 1 (封装工具 1)
应用 B ──MCP──> MCP Server 1 (封装工具 1)
应用 A ──MCP──> MCP Server 2 (封装工具 2)
→ 只需要 M + N 个实现
三、MCP 核心架构
MCP 采用 客户端-服务器 (Client-Server) 架构:
┌─────────────────────────────────────────────────┐
│ MCP Host │
│ ┌───────────────┐ ┌───────────────────────┐ │
│ │ MCP Client │───>│ MCP Server A │ │
│ │ (协议层) │ │ (文件系统工具) │ │
│ └───────────────┘ └───────────────────────┘ │
│ ┌───────────────┐ ┌───────────────────────┐ │
│ │ MCP Client │───>│ MCP Server B │ │
│ │ (协议层) │ │ (数据库查询) │ │
│ └───────────────┘ └───────────────────────┘ │
│ ┌───────────────┐ ┌───────────────────────┐ │
│ │ MCP Client │───>│ MCP Server C │ │
│ │ (协议层) │ │ (API 集成) │ │
│ └───────────────┘ └───────────────────────┘ │
└─────────────────────────────────────────────────┘
角色定义
| 角色 | 职责 |
|---|---|
| Host(宿主) | 运行 LLM 的应用环境,如 Claude Desktop、IDE 插件 |
| Client(客户端) | Host 内部的协议处理层,负责与 Server 建立连接和通信 |
| Server(服务端) | 暴露具体能力(工具、资源、提示词)的服务进程 |
四、协议通信机制
4.1 消息格式:JSON-RPC 2.0
MCP 所有消息都遵循 JSON-RPC 2.0 规范:
请求 (Request):
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": { "path": "/tmp/hello.txt" }
}
}
响应 (Response):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{ "type": "text", "text": "Hello, MCP!" }
]
}
}
通知 (Notification):(无 id 字段,不需要响应)
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": { "progress": 50, "total": 100 }
}
4.2 传输方式
MCP 支持两种标准传输方式:
stdio(标准输入/输出)
Client Server
│ │
│──stdin: JSON-RPC Request─────>│
│ │
│<──stdout: JSON-RPC Response────│
│ │
- 适用于本地进程间通信
- Client 启动 Server 作为子进程
- 通过 stdin/stdout 传递 JSON-RPC 消息
- 最常用的传输方式
HTTP + SSE(Server-Sent Events)
Client Server
│──GET /sse────────────────────>│ (建立 SSE 连接)
│<──SSE: endpoint URL───────────│
│ │
│──POST /messages──────────────>│ (发送请求)
│<──SSE: JSON-RPC Response──────│ (通过 SSE 接收)
- 适用于远程服务、Web 部署
- 支持流式响应
- 2025 年已更新为 Streamable HTTP 传输方式
五、MCP 生命周期
一个完整的 MCP 会话经历以下阶段:
Client Server
│ │
│ 1. 初始化 (Initialize) │
│──{ method: "initialize" }────────>│
│<──{ result: { capabilities } }────│
│ │
│ 2. 确认 (Initialized) │
│──{ method: "initialized" }───────>│
│ │
│ 3. 正常通信 │
│──{ method: "tools/list" }────────>│
│<──{ result: { tools: [...] } }────│
│ │
│──{ method: "tools/call" }────────>│
│<──{ result: { content: [...] } }──│
│ │
│ 4. 关闭 │
│──(进程退出 / 连接断开)────────────>│
初始化握手细节
Client 发送自身信息和能力:
{
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {
"roots": { "listChanged": true },
"sampling": {}
},
"clientInfo": {
"name": "MyApp",
"version": "1.0.0"
}
}
}
Server 响应自身能力:
{
"result": {
"protocolVersion": "2025-03-26",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": true },
"prompts": { "listChanged": true },
"logging": {}
},
"serverInfo": {
"name": "MyServer",
"version": "1.0.0"
}
}
}
六、核心能力详解
MCP 定义了三大核心能力(Primitives):
6.1 Tools(工具)
工具是 模型控制 的能力 —— LLM 决定何时调用。
{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如 '北京'"
}
},
"required": ["city"]
}
}
6.2 Resources(资源)
资源是 应用控制 的能力 —— 应用代码决定何时读取。
{
"uri": "file:///project/README.md",
"name": "项目 README",
"description": "项目的说明文档",
"mimeType": "text/markdown"
}
6.3 Prompts(提示词模板)
提示词是 用户控制 的能力 —— 用户主动选择使用。
{
"name": "code_review",
"description": "代码审查提示词",
"arguments": [
{
"name": "language",
"description": "编程语言",
"required": true
},
{
"name": "code",
"description": "待审查的代码",
"required": true
}
]
}
能力对比
| 能力 | 控制方 | 用途 | 类比 |
|---|---|---|---|
| Tools | LLM 模型 | 执行操作、调用 API | 函数调用 |
| Resources | 应用代码 | 提供上下文数据 | 文件读取 |
| Prompts | 用户 | 预设交互模板 | 快捷指令 |
七、手把手实现一个 MCP Server
接下来,我们用 TypeScript + Node.js 当前主流的方式从零实现一个功能完整的 MCP Server。这个 Server 将提供:
- 一个查询天气的 Tool
- 一个读取本地文件的 Resource
- 一个代码审查的 Prompt Template
为什么选 TypeScript? MCP 协议本身由 Anthropic 用 TypeScript 开发,官方 SDK 最为成熟;Node.js 生态与 AI 应用天然契合,async/await 异步模型也与 MCP 的异步通信完美匹配。
7.1 环境准备
# 创建项目目录
mkdir my-mcp-server && cd my-mcp-server
# 初始化项目
npm init -y
# 安装 MCP SDK
npm install @modelcontextprotocol/sdk zod
# 安装开发依赖
npm install -D typescript @types/node tsx
初始化 TypeScript 配置:
npx tsc --init
修改 tsconfig.json 关键配置:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"]
}
在 package.json 中添加启动脚本:
{
"type": "module",
"scripts": {
"build": "tsc",
"start": "node build/index.js",
"dev": "tsx src/index.ts"
}
}
要求: Node.js >= 18,TypeScript >= 5.0
7.2 最小可运行示例
先从一个最简单的 Server 开始,确保环境正确:
// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// 创建 MCP Server 实例
const server = new McpServer({
name: "my-first-server",
version: "1.0.0",
});
// 注册一个简单的 Tool
server.tool("hello", { name: { type: "string", description: "你的名字" } }, async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name}! 欢迎使用 MCP Server.` }],
}));
// 使用 stdio 传输启动 Server
const transport = new StdioServerTransport();
await server.connect(transport);
运行测试:
# 开发模式运行(无需编译)
npx tsx src/index.ts
此时 Server 已在 stdin 上监听 JSON-RPC 消息,等待 Client 连接。
7.3 实现完整功能
下面我们扩展 Server,加入实际有用的功能:
// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import fs from "node:fs/promises";
import path from "node:path";
const server = new McpServer({
name: "demo-server",
version: "1.0.0",
});
// ============================================================
// Tools:模型可调用的工具
// ============================================================
server.tool(
"get_weather",
"获取指定城市的当前天气信息",
{ city: z.string().describe("城市名称,如 '北京'") },
async ({ city }) => {
// 模拟天气数据,实际项目中可调用真实 API
const mockData: Record<string, { temp: string; weather: string; humidity: string }> = {
"北京": { temp: "22°C", weather: "晴", humidity: "45%" },
"上海": { temp: "25°C", weather: "多云", humidity: "60%" },
"深圳": { temp: "28°C", weather: "阵雨", humidity: "80%" },
};
const data = mockData[city];
if (data) {
return { content: [{ type: "text", text: JSON.stringify(data) }] };
}
return { content: [{ type: "text", text: `未找到城市 '${city}' 的天气数据` }] };
}
);
server.tool(
"calculate",
"安全地计算数学表达式",
{ expression: z.string().describe("数学表达式,如 '2 + 3 * 4'") },
async ({ expression }) => {
// 仅允许数字和基本运算符,防止注入
const allowedChars = /^[0-9+\-*/().% ]+$/;
if (!allowedChars.test(expression)) {
return { content: [{ type: "text", text: "错误:表达式包含不允许的字符" }] };
}
try {
// 使用 Function 构造器替代 eval,更安全
const result = new Function(`"use strict"; return (${expression})`)();
return { content: [{ type: "text", text: String(result) }] };
} catch (e) {
return { content: [{ type: "text", text: `计算错误:${e}` }] };
}
}
);
server.tool(
"get_current_time",
"获取当前时间",
{ timezone: z.string().optional().describe("时区,默认为 Asia/Shanghai") },
async ({ timezone = "Asia/Shanghai" }) => {
const now = new Date();
const result = {
datetime: now.toLocaleString("zh-CN", { timeZone: timezone }),
timezone,
timestamp: Math.floor(now.getTime() / 1000),
};
return { content: [{ type: "text", text: JSON.stringify(result) }] };
}
);
// ============================================================
// Resources:应用可读取的数据源
// ============================================================
server.resource(
"app-settings",
"config://app/settings",
{ description: "获取应用配置信息", mimeType: "application/json" },
async () => ({
contents: [
{
uri: "config://app/settings",
text: JSON.stringify(
{
app_name: "Demo MCP Server",
version: "1.0.0",
features: { weather: true, calculator: true, file_reader: true },
max_file_size_mb: 10,
},
null,
2
),
},
],
})
);
server.resource(
"read-file",
"file://{path}",
{ description: "读取本地文件内容" },
async (uri) => {
const filePath = uri.pathname;
// 安全检查:限制可访问的目录
const allowedDirs = [process.env.HOME + "/documents", "/tmp"];
const absPath = path.resolve(filePath);
if (!allowedDirs.some((dir) => absPath.startsWith(dir))) {
return { contents: [{ uri: uri.href, text: `错误:无权访问路径 '${filePath}'` }] };
}
try {
const content = await fs.readFile(absPath, "utf-8");
return { contents: [{ uri: uri.href, text: content }] };
} catch {
return { contents: [{ uri: uri.href, text: `错误:文件 '${filePath}' 不存在` }] };
}
}
);
// ============================================================
// Prompts:用户可选用的提示词模板
// ============================================================
server.prompt(
"code_review",
"代码审查提示词",
{
code: z.string().describe("待审查的代码"),
language: z.string().optional().describe("编程语言,默认为 typescript"),
},
async ({ code, language = "typescript" }) => ({
messages: [
{
role: "user",
content: {
type: "text",
text: `请对以下 ${language} 代码进行审查,从这几个方面给出评价:
1. **代码质量**:命名规范、可读性、结构清晰度
2. **潜在 Bug**:是否有逻辑错误、边界条件未处理
3. **性能**:是否有明显的性能问题或可优化之处
4. **安全性**:是否存在安全隐患
5. **最佳实践**:是否符合 ${language} 的最佳实践
\`\`\`${language}
${code}
\`\`\`
请给出具体的改进建议和修改后的代码示例。`,
},
},
],
})
);
server.prompt(
"explain_error",
"错误分析提示词",
{
error_message: z.string().describe("错误信息"),
context: z.string().optional().describe("相关上下文代码"),
},
async ({ error_message, context }) => {
let text = `我遇到了以下错误,请帮我分析原因并给出解决方案:
**错误信息:**
\`\`\`
${error_message}
\`\`\``;
if (context) {
text += `
**相关代码:**
\`\`\`
${context}
\`\`\``;
}
text += `
请从以下角度分析:
1. 错误的根本原因
2. 可能的触发条件
3. 推荐的解决方案
4. 如何避免类似问题`;
return {
messages: [{ role: "user", content: { type: "text", text } }],
};
}
);
// 启动 Server
const transport = new StdioServerTransport();
await server.connect(transport);
7.4 代码逐段解析
Tool 定义
server.tool(
"get_weather", // 工具名称
"获取指定城市的当前天气信息", // 工具描述
{ city: z.string().describe("城市名称,如 '北京'") }, // 参数 Schema(Zod)
async ({ city }) => { ... } // 处理函数
);
server.tool(name, description, schema, handler)四个参数- Zod schema 自动转换为 JSON Schema,同时提供运行时验证
- handler 接收已验证的参数,返回
{ content: [...] }格式 - 复杂数据用
JSON.stringify()序列化为 text 类型
Resource 定义
server.resource(
"app-settings", // 资源唯一 ID
"config://app/settings", // URI 模板
{ description: "...", mimeType: "..." }, // 元数据
async (uri) => ({ contents: [...] }) // 处理函数
);
- 静态 URI 直接匹配,动态 URI(如
file://{path})通过模板解析参数 - handler 接收解析后的
URL对象,返回{ contents: [...] }格式 - 应用代码通过 URI 主动读取,LLM 不会自动调用
Prompt 定义
server.prompt(
"code_review", // Prompt 名称
"代码审查提示词", // 描述
{ code: z.string(), language: z.string().optional() }, // 参数
async ({ code, language }) => ({ messages: [...] }) // 返回消息
);
- 返回
{ messages: [...] }格式,支持多轮消息 - 参数使用 Zod 验证,
.optional()标记可选参数
7.5 添加生命周期管理
对于需要初始化资源的 Server(如数据库连接),可以在连接前后管理生命周期:
// src/lifecycle-server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import Database from "better-sqlite3";
// ---- 生命周期:初始化资源 ----
const db = new Database(":memory:");
db.exec(`
CREATE TABLE notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
const server = new McpServer({ name: "lifecycle-demo", version: "1.0.0" });
// 注意:handler 是闭包,直接捕获外部的 db 变量
server.tool(
"add_note",
"添加一条笔记",
{ content: z.string().describe("笔记内容") },
async ({ content }) => {
db.prepare("INSERT INTO notes (content) VALUES (?)").run(content);
return { content: [{ type: "text", text: `笔记已添加:${content}` }] };
}
);
server.tool("list_notes", "列出所有笔记", {}, async () => {
const rows = db.prepare("SELECT id, content, created_at FROM notes ORDER BY id DESC").all();
if (rows.length === 0) {
return { content: [{ type: "text", text: "暂无笔记" }] };
}
const text = rows.map((r: any) => `[${r.id}] ${r.content} (${r.created_at})`).join("\n");
return { content: [{ type: "text", text }] };
});
// ---- 启动 ----
const transport = new StdioServerTransport();
await server.connect(transport);
// ---- 生命周期:进程退出时清理 ----
process.on("SIGINT", () => {
db.close();
process.exit(0);
});
7.6 使用 Server 实例进行高级交互
MCP TypeScript SDK 的 McpServer 实例提供了丰富的 API:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({
name: "advanced-server",
version: "1.0.0",
});
// 注册 Tool 并在内部使用 server 能力
server.tool(
"long_running_task",
"执行一个长时间运行的任务",
{ data: z.string().describe("输入数据") },
async ({ data }) => {
const totalSteps = 5;
for (let i = 0; i < totalSteps; i++) {
// 模拟耗时操作
await new Promise((resolve) => setTimeout(resolve, 1000));
console.error(`正在处理步骤 ${i + 1}/${totalSteps}...`);
}
return { content: [{ type: "text", text: `任务完成,处理了 ${data}` }] };
}
);
SDK 核心 API 速览:
| API | 说明 |
|---|---|
server.tool(name, desc, schema, handler) |
注册工具 |
server.resource(id, uri, meta, handler) |
注册资源 |
server.prompt(name, desc, schema, handler) |
注册提示词模板 |
server.connect(transport) |
连接传输层启动服务 |
server.sendResourceListChanged() |
通知客户端资源列表变化 |
server.sendToolListChanged() |
通知客户端工具列表变化 |
八、进阶:Resources 与 Prompts
8.1 动态 Resources
URI 模板中的 {param} 会自动提取为参数:
server.resource(
"user-profile",
"users://{user_id}/profile",
{ description: "获取用户资料" },
async (uri) => {
// user_id 从 URI 路径中自动解析
const userId = uri.pathname.split("/")[1];
return {
contents: [
{
uri: uri.href,
text: JSON.stringify({
id: userId,
name: `用户${userId}`,
email: `user${userId}@example.com`,
}),
},
],
};
}
);
8.2 Resource 的订阅机制
Client 可以订阅 Resource 的变更通知:
// 当资源内容变化时通知已订阅的客户端
server.sendResourceListChanged();
8.3 复杂 Prompt 模板
Prompt 可以返回多条消息,支持更复杂的交互:
server.prompt(
"debug_session",
"启动一个调试会话",
{
error: z.string().describe("错误信息"),
logs: z.string().optional().describe("相关日志"),
},
async ({ error, logs }) => {
const messages: any[] = [
{
role: "user",
content: { type: "text", text: `我遇到了一个错误需要调试:\n\n${error}` },
},
];
if (logs) {
messages.push({
role: "user",
content: { type: "text", text: `以下是相关日志:\n\`\`\`\n${logs}\n\`\`\`` },
});
}
return { messages };
}
);
九、调试与测试
9.1 使用 MCP Inspector
MCP 官方提供了一个可视化调试工具 Inspector:
# 安装并启动 Inspector
npx @modelcontextprotocol/inspector npx tsx src/index.ts
Inspector 提供 Web UI,可以:
- 查看 Server 暴露的所有 Tools / Resources / Prompts
- 手动调用 Tool 并查看返回值
- 查看 JSON-RPC 消息日志
9.2 使用 Claude Desktop 测试
在 Claude Desktop 配置文件中添加你的 Server:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"demo-server": {
"command": "node",
"args": ["/absolute/path/to/build/index.js"],
"env": {
"API_KEY": "your-api-key-if-needed"
}
}
}
}
开发阶段可以用 tsx 直接运行 TypeScript:
{
"mcpServers": {
"demo-server": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/src/index.ts"]
}
}
}
重启 Claude Desktop 后,在对话中即可使用你的 Server 提供的工具。
9.3 单元测试
使用 Vitest 进行测试:
npm install -D vitest
// src/__tests__/server.test.ts
import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { createServer } from "../server.js"; // 提取 server 创建函数
describe("MCP Server", () => {
let client: Client;
beforeAll(async () => {
const server = createServer();
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await server.connect(serverTransport);
client = new Client({ name: "test-client", version: "1.0.0" });
await client.connect(clientTransport);
});
it("should call hello tool", async () => {
const result = await client.callTool({ name: "hello", arguments: { name: "MCP" } });
expect(result.content[0].text).toContain("Hello, MCP");
});
it("should calculate expression", async () => {
const result = await client.callTool({ name: "calculate", arguments: { expression: "2 + 3" } });
expect(result.content[0].text).toBe("5");
});
it("should reject invalid expression", async () => {
const result = await client.callTool({
name: "calculate",
arguments: { expression: "require('child_process').exec('ls')" },
});
expect(result.content[0].text).toContain("不允许");
});
it("should list resources", async () => {
const result = await client.listResources();
expect(result.resources.length).toBeGreaterThan(0);
});
});
在 package.json 中添加测试脚本:
{
"scripts": {
"test": "vitest run"
}
}
十、最佳实践与总结
安全性
- 输入验证:利用 Zod schema 在 handler 执行前自动验证参数
- 路径限制:Resource 访问限制在安全目录内
- 避免 eval:计算类工具使用
new Function()或专用库,不要用eval - 权限控制:敏感操作需要用户确认
性能
- 异步优先:所有 handler 都是 async,避免阻塞事件循环
- 流式处理:大数据集使用分页返回
- 缓存:对频繁访问的 Resource 结果进行缓存
- 连接复用:同一个 transport 连接可处理多个请求
可维护性
- 清晰的描述:Tool 的 description 要详细,这是 LLM 理解工具的唯一依据
- Zod schema:完善的类型定义同时生成 JSON Schema 和运行时验证
- 错误处理:返回有意义的错误信息,而非抛出异常让 Server 崩溃
- 日志记录:使用
console.error()输出调试信息(stdout 用于协议通信)
协议版本兼容
// SDK 自动处理协议版本协商
const server = new McpServer({
name: "my-server",
version: "1.0.0",
// 可选:指定支持的协议版本
capabilities: {
tools: {},
resources: { subscribe: true },
prompts: {},
},
});
附录:快速参考
完整项目结构
my-mcp-server/
├── src/
│ ├── index.ts # 主服务入口
│ ├── server.ts # Server 实例创建(便于测试)
│ ├── tools/ # 工具实现
│ │ ├── weather.ts
│ │ └── calculator.ts
│ ├── resources/ # 资源实现
│ │ └── files.ts
│ ├── prompts/ # 提示词模板
│ │ └── templates.ts
│ └── __tests__/ # 测试
│ └── server.test.ts
├── build/ # 编译输出
├── tsconfig.json # TypeScript 配置
├── package.json # 项目配置
└── README.md
package.json 完整示例
{
"name": "my-mcp-server",
"version": "1.0.0",
"type": "module",
"scripts": {
"build": "tsc",
"start": "node build/index.js",
"dev": "tsx src/index.ts",
"test": "vitest run",
"inspector": "npx @modelcontextprotocol/inspector npx tsx src/index.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.0",
"zod": "^3.23.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"tsx": "^4.19.0",
"typescript": "^5.6.0",
"vitest": "^3.0.0"
}
}
常用 MCP 客户端
| 客户端 | 说明 |
|---|---|
| Claude Desktop | Anthropic 官方桌面应用 |
| Claude Code | Anthropic CLI 工具 |
| Cursor | AI 代码编辑器 |
| Windsurf | AI 代码编辑器 |
| Zed | 高性能代码编辑器 |
总结
MCP 协议通过标准化的 JSON-RPC 通信,为 LLM 生态建立了统一的工具接入标准。本文从协议设计到实际实现,完整覆盖了 MCP 的核心概念:
- 架构:Host → Client → Server 三层结构
- 通信:JSON-RPC 2.0 + stdio/SSE 传输
- 能力:Tools(模型调用)、Resources(应用读取)、Prompts(用户选择)
- 实现:TypeScript SDK + Zod schema 验证 + stdio 传输
掌握这些内容,你就可以为任何 LLM 应用构建标准化的扩展能力了。
参考资料:
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)