来源：<https://blog.csdn.net/weixin_44067347/article/details/161381421?ops_request_misc=elastic_search_misc&request_id=b59f75f5b577fe0ceb32bff5a38ff278&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~sobaiduend~default-2-161381421-null-null.541^v3^pc_search_result_blog8&utm_term=mcp%20%E5%8E%9F%E7%90%86&spm=1018.2226.3001.4450>

> Model Context Protocol (MCP) 是 Anthropic 推出的开放协议，旨在为 LLM 提供标准化的外部工具和数据源接入方式。本文将深入解析 MCP 协议的设计理念、核心架构，并带你从零实现一个完整的 MCP Server。

---

### 目录

- [一、什么是 MCP](https://blog.csdn.net/weixin_44067347/article/details/#%E4%B8%80%E4%BB%80%E4%B9%88%E6%98%AF-mcp)
- [二、为什么需要 MCP](https://blog.csdn.net/weixin_44067347/article/details/#%E4%BA%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81-mcp)
- [三、MCP 核心架构](https://blog.csdn.net/weixin_44067347/article/details/#%E4%B8%89mcp-%E6%A0%B8%E5%BF%83%E6%9E%B6%E6%9E%84)
- [四、协议通信机制](https://blog.csdn.net/weixin_44067347/article/details/#%E5%9B%9B%E5%8D%8F%E8%AE%AE%E9%80%9A%E4%BF%A1%E6%9C%BA%E5%88%B6)
- [五、MCP 生命周期](https://blog.csdn.net/weixin_44067347/article/details/#%E4%BA%94mcp-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F)
- [六、核心能力详解](https://blog.csdn.net/weixin_44067347/article/details/#%E5%85%AD%E6%A0%B8%E5%BF%83%E8%83%BD%E5%8A%9B%E8%AF%A6%E8%A7%A3)
- [七、手把手实现一个 MCP Server](https://blog.csdn.net/weixin_44067347/article/details/#%E4%B8%83%E6%89%8B%E6%8A%8A%E6%89%8B%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA-mcp-server)
- [八、进阶：Resources 与 Prompts](https://blog.csdn.net/weixin_44067347/article/details/#%E5%85%AB%E8%BF%9B%E9%98%B6resources-%E4%B8%8E-prompts)
- [九、调试与测试](https://blog.csdn.net/weixin_44067347/article/details/#%E4%B9%9D%E8%B0%83%E8%AF%95%E4%B8%8E%E6%B5%8B%E8%AF%95)
- [十、最佳实践与总结](https://blog.csdn.net/weixin_44067347/article/details/#%E5%8D%81%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E4%B8%8E%E6%80%BB%E7%BB%93)

---

### 一、什么是 MCP

**MCP (Model Context Protocol)** 是一个开放的、基于 JSON-RPC 2.0 的协议，它定义了 LLM 应用（客户端）与外部数据源/工具（服务器）之间的标准化通信方式。

你可以把 MCP 理解为 **AI 世界的 USB-C 接口**：

- 就像 USB-C 让各种设备通过统一接口连接一样，MCP 让各种 AI 应用通过统一协议接入外部能力
- 无论是文件系统、数据库、API 服务，还是浏览器控制，都可以通过 MCP 暴露给 LLM

#### 核心设计原则

| 原则 | 说明 |
| --- | --- |
| **标准化** | 统一的协议规范，任何客户端都能连接任何服务端 |
| **安全性** | 服务端主动暴露能力，客户端需授权才能调用 |
| **可组合性** | 一个客户端可连接多个服务端，能力可叠加 |
| **语言无关** | 协议基于 JSON-RPC，任何语言都能实现 |

---

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/994449a28457412ea584bafdc72da1cd.png)

---

### 二、为什么需要 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)：**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "read_file",
    "arguments": { "path": "/tmp/hello.txt" }
  }
}
```

**响应 (Response)：**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      { "type": "text", "text": "Hello, MCP!" }
    ]
  }
}
```

**通知 (Notification)：**（无 id 字段，不需要响应）

```json
{
  "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 发送自身信息和能力：

```json
{
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-03-26",
    "capabilities": {
      "roots": { "listChanged": true },
      "sampling": {}
    },
    "clientInfo": {
      "name": "MyApp",
      "version": "1.0.0"
    }
  }
}
```

Server 响应自身能力：

```json
{
  "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 决定何时调用。

```json
{
  "name": "get_weather",
  "description": "获取指定城市的天气信息",
  "inputSchema": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "城市名称，如 '北京'"
      }
    },
    "required": ["city"]
  }
}
```

#### 6.2 Resources（资源）

资源是 **应用控制** 的能力 —— 应用代码决定何时读取。

```json
{
  "uri": "file:///project/README.md",
  "name": "项目 README",
  "description": "项目的说明文档",
  "mimeType": "text/markdown"
}
```

#### 6.3 Prompts（提示词模板）

提示词是 **用户控制** 的能力 —— 用户主动选择使用。

```json
{
  "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 环境准备

```bash

mkdir my-mcp-server && cd my-mcp-server

npm init -y

npm install @modelcontextprotocol/sdk zod

npm install -D typescript @types/node tsx
```

初始化 TypeScript 配置：

```bash
npx tsc --init
```

修改 `tsconfig.json` 关键配置：

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"]
}
```

在 `package.json` 中添加启动脚本：

```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 开始，确保环境正确：

```typescript

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new McpServer({
  name: "my-first-server",
  version: "1.0.0",
});

server.tool("hello", { name: { type: "string", description: "你的名字" } }, async ({ name }) => ({
  content: [{ type: "text", text: `Hello, ${name}! 欢迎使用 MCP Server.` }],
}));

const transport = new StdioServerTransport();
await server.connect(transport);
```

运行测试：

```bash

npx tsx src/index.ts
```

此时 Server 已在 stdin 上监听 JSON-RPC 消息，等待 Client 连接。

#### 7.3 实现完整功能

下面我们扩展 Server，加入实际有用的功能：

```typescript

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",
});

server.tool(
  "get_weather",
  "获取指定城市的当前天气信息",
  { city: z.string().describe("城市名称，如 '北京'") },
  async ({ city }) => {
    
    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 {
      
      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) }] };
  }
);

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}' 不存在` }] };
    }
  }
);

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 } }],
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);
```

#### 7.4 代码逐段解析

##### Tool 定义

```typescript
server.tool(
  "get_weather",                                        
  "获取指定城市的当前天气信息",                            
  { city: z.string().describe("城市名称，如 '北京'") },   
  async ({ city }) => { ... }                           
);
```

- `server.tool(name, description, schema, handler)` 四个参数
- **Zod schema** 自动转换为 JSON Schema，同时提供运行时验证
- **handler** 接收已验证的参数，返回 `{ content: [...] }` 格式
- 复杂数据用 `JSON.stringify()` 序列化为 text 类型

##### Resource 定义

```typescript
server.resource(
  "app-settings",                          
  "config://app/settings",                 
  { description: "...", mimeType: "..." }, 
  async (uri) => ({ contents: [...] })     
);
```

- 静态 URI 直接匹配，动态 URI（如 `file://{path}`）通过模板解析参数
- handler 接收解析后的 `URL` 对象，返回 `{ contents: [...] }` 格式
- 应用代码通过 URI 主动读取，LLM 不会自动调用

##### Prompt 定义

```typescript
server.prompt(
  "code_review",                           
  "代码审查提示词",                         
  { code: z.string(), language: z.string().optional() }, 
  async ({ code, language }) => ({ messages: [...] })    
);
```

- 返回 `{ messages: [...] }` 格式，支持多轮消息
- 参数使用 Zod 验证，`.optional()` 标记可选参数

#### 7.5 添加生命周期管理

对于需要初始化资源的 Server（如数据库连接），可以在连接前后管理生命周期：

```typescript

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" });

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：

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

const server = new McpServer({
  name: "advanced-server",
  version: "1.0.0",
});

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}` 会自动提取为参数：

```typescript
server.resource(
  "user-profile",
  "users://{user_id}/profile",
  { description: "获取用户资料" },
  async (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 的变更通知：

```typescript

server.sendResourceListChanged();
```

#### 8.3 复杂 Prompt 模板

Prompt 可以返回多条消息，支持更复杂的交互：

```typescript
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`：

```bash

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`

```json
{
  "mcpServers": {
    "demo-server": {
      "command": "node",
      "args": ["/absolute/path/to/build/index.js"],
      "env": {
        "API_KEY": "your-api-key-if-needed"
      }
    }
  }
}
```

开发阶段可以用 `tsx` 直接运行 TypeScript：

```json
{
  "mcpServers": {
    "demo-server": {
      "command": "npx",
      "args": ["tsx", "/absolute/path/to/src/index.ts"]
    }
  }
}
```

重启 Claude Desktop 后，在对话中即可使用你的 Server 提供的工具。

#### 9.3 单元测试

使用 Vitest 进行测试：

```bash
npm install -D vitest
```

```typescript

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"; 

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` 中添加测试脚本：

```json
{
  "scripts": {
    "test": "vitest run"
  }
}
```

---

### 十、最佳实践与总结

#### 安全性

1. **输入验证**：利用 Zod schema 在 handler 执行前自动验证参数
2. **路径限制**：Resource 访问限制在安全目录内
3. **避免 eval**：计算类工具使用 `new Function()` 或专用库，不要用 `eval`
4. **权限控制**：敏感操作需要用户确认

#### 性能

1. **异步优先**：所有 handler 都是 async，避免阻塞事件循环
2. **流式处理**：大数据集使用分页返回
3. **缓存**：对频繁访问的 Resource 结果进行缓存
4. **连接复用**：同一个 transport 连接可处理多个请求

#### 可维护性

1. **清晰的描述**：Tool 的 description 要详细，这是 LLM 理解工具的唯一依据
2. **Zod schema**：完善的类型定义同时生成 JSON Schema 和运行时验证
3. **错误处理**：返回有意义的错误信息，而非抛出异常让 Server 崩溃
4. **日志记录**：使用 `console.error()` 输出调试信息（stdout 用于协议通信）

#### 协议版本兼容

```typescript

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 完整示例

```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 应用构建标准化的扩展能力了。

---

> **参考资料：**
>
> - [MCP 官方文档](https://modelcontextprotocol.io)
> - [MCP 规范](https://spec.modelcontextprotocol.io)
> - [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
> - [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)