<!-- title: Claude Code MCP服务器开发从零到上线全实战 -->

# Claude Code MCP服务器开发从零到上线全实战

## 概述

MCP（Model Context Protocol）是Anthropic推出的开放协议，标准化的AI模型与外部工具交互方式。本教程从架构原理出发，手把手带你用Python（FastMCP）和TypeScript两种语言各构建一个完整的MCP服务器，涵盖工具（Tools）、资源（Resources）、提示模板（Prompts）三大原语，最终接入Claude Code并通过MCP Inspector完成调试。适合有一定编程基础、希望扩展Claude Code能力的开发者和运维工程师。

---

## 一、MCP架构核心概念

在动手写代码之前，必须理解MCP的架构模型。MCP采用经典的**客户端-服务器**架构，但与HTTP服务不同，它专为LLM与工具交互而设计。

```mermaid
graph TB
    subgraph Host["宿主应用 (Host)"]
        CC["Claude Code / Claude Desktop"]
        Client["MCP Client"]
    end

    subgraph Servers["MCP Servers"]
        S1["📁 文件系统 Server"]
        S2["🗄️ 数据库 Server"]
        S3["🔧 自定义 Server"]
    end

    CC -->|"用户指令"| Client
    Client -->|"stdio / HTTP"| S1
    Client -->|"stdio / HTTP"| S2
    Client -->|"stdio / HTTP"| S3

    subgraph Primitives["MCP 三大原语"]
        T["🛠️ Tools<br/>执行操作"]
        R["📄 Resources<br/>暴露数据"]
        P["💬 Prompts<br/>提示模板"]
    end

    S1 --> T
    S2 --> R
    S3 --> P
```

### 1.1 三大原语详解

| 原语 | 英文 | 作用 | 典型场景 |
|------|------|------|----------|
| **工具** | Tools | LLM可调用的函数/操作 | 查询数据库、发送通知、执行计算 |
| **资源** | Resources | LLM可读取的数据内容 | 文件内容、API响应、数据库记录 |
| **提示模板** | Prompts | 可复用的提示模板 | 代码审查模板、报告生成模板 |

### 1.2 传输协议

MCP支持两种传输方式：

- **stdio**：标准输入输出，适用于本地进程间通信，Claude Code默认方式
- **Streamable HTTP**：基于HTTP的传输，适用于远程部署和微服务架构

Claude Code主要通过stdio与MCP服务器通信——它启动你的服务器进程，通过stdin/stdout交换JSON-RPC消息。

---

## 二、前置条件

| 工具 | 版本要求 | 用途 |
|------|----------|------|
| Python | ≥ 3.10 | FastMCP Python服务器 |
| Node.js | ≥ 18 | TypeScript MCP服务器 |
| Claude Code CLI | 最新版 | 宿主客户端 |
| pip / uv | 最新版 | Python包管理 |
| npm / pnpm | 最新版 | Node包管理 |

环境检查命令：

```bash
# 检查Python版本
python --version  # 需要 >= 3.10

# 检查Node.js版本
node --version    # 需要 >= 18

# 检查Claude Code
claude --version
```

---

## 三、Python路线：用FastMCP构建服务器

### 3.1 项目初始化

```bash
# 创建项目目录
mkdir mcp-weather-server && cd mcp-weather-server

# 创建虚拟环境
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate

# 安装FastMCP（官方Python MCP框架）
pip install fastmcp httpx
```

> **为什么选FastMCP？** FastMCP是MCP Python SDK内置的高级框架（`mcp.server.fastmcp`），由Prefect团队维护。一个`@mcp.tool()`装饰器就能把普通Python函数变成MCP工具，自动处理JSON-RPC协议、参数校验、类型推断。

### 3.2 最小可运行服务器

创建`server.py`：

```python
from mcp.server.fastmcp import FastMCP

# 初始化MCP服务器，名称将显示在Claude Code中
mcp = FastMCP("weather-server")


@mcp.tool()
def get_current_weather(city: str) -> str:
    """获取指定城市的当前天气信息
    
    Args:
        city: 城市名称，如"北京"、"上海"
    
    Returns:
        天气信息描述字符串
    """
    # 这里使用模拟数据，实际项目中可接入天气API
    weather_data = {
        "北京": "☀️ 晴，温度 28°C，湿度 45%，北风3级",
        "上海": "🌧️ 小雨，温度 22°C，湿度 78%，东风2级",
        "深圳": "⛅ 多云，温度 30°C，湿度 65%，南风2级",
    }
    return weather_data.get(city, f"暂无{city}的天气数据")


@mcp.tool()
def get_weather_forecast(city: str, days: int = 3) -> str:
    """获取未来几天的天气预报
    
    Args:
        city: 城市名称
        days: 预报天数，默认3天，最多7天
    
    Returns:
        天气预报信息
    """
    if days > 7:
        return "最多支持7天预报"
    
    forecasts = []
    for i in range(1, days + 1):
        forecasts.append(f"  第{i}天: 晴转多云，温度 20-30°C")
    
    return f"{city}未来{days}天预报:\n" + "\n".join(forecasts)


# 运行服务器（默认使用stdio传输）
if __name__ == "__main__":
    mcp.run()
```

### 3.3 添加资源（Resources）

资源是LLM可以**读取**的数据，不需要执行操作时使用资源而非工具：

```python
@mcp.resource("weather://cities/supported")
def get_supported_cities() -> str:
    """返回支持查询天气的城市列表"""
    cities = ["北京", "上海", "深圳", "广州", "成都", "杭州"]
    return "支持查询天气的城市：\n" + "\n".join(f"  - {c}" for c in cities)


@mcp.resource("weather://alert/{city}")
def get_weather_alert(city: str) -> str:
    """获取指定城市的天气预警信息
    
    Args:
        city: 城市名称
    """
    alerts = {
        "北京": "🟡 大风蓝色预警：预计未来24小时阵风可达7级",
        "上海": "🔴 暴雨橙色预警：预计未来6小时降雨量将达100mm以上",
    }
    return alerts.get(city, f"✅ {city}当前无天气预警")
```

资源URI使用`协议://路径`格式，支持路径参数模板（如`{city}`）。

### 3.4 添加提示模板（Prompts）

提示模板是预定义的、可复用的提示词：

```python
@mcp.prompt()
def weather_report_prompt(city: str) -> str:
    """生成天气报告的提示模板
    
    Args:
        city: 要生成报告的城市
    """
    return f"""请为{city}生成一份详细的天气分析报告，包含以下内容：
1. 当前天气状况概述
2. 未来3天天气预报
3. 出行建议
4. 健康提示（如紫外线指数、空气质量等）

请使用专业但易懂的语言，适合公众阅读。"""
```

### 3.5 完整服务器代码

将以上内容整合为完整的`server.py`：

```python
#!/usr/bin/env python3
"""天气查询 MCP 服务器 - 演示MCP三大原语的完整实现"""

from mcp.server.fastmcp import FastMCP

mcp = FastMCP(
    "weather-server",
    version="1.0.0",
    description="天气查询服务 - 提供城市天气查询、预报和预警功能"
)


# ============ Tools（工具）============

@mcp.tool()
def get_current_weather(city: str) -> str:
    """获取指定城市的当前天气信息
    
    Args:
        city: 城市名称，如"北京"、"上海"
    """
    weather_data = {
        "北京": "☀️ 晴，温度 28°C，湿度 45%，北风3级",
        "上海": "🌧️ 小雨，温度 22°C，湿度 78%，东风2级",
        "深圳": "⛅ 多云，温度 30°C，湿度 65%，南风2级",
        "广州": "🌤️ 晴间多云，温度 32°C，湿度 70%，南风2级",
        "成都": "☁️ 阴，温度 24°C，湿度 60%，微风",
        "杭州": "🌦️ 阵雨，温度 25°C，湿度 75%，东风3级",
    }
    return weather_data.get(city, f"暂无{city}的天气数据")


@mcp.tool()
def get_weather_forecast(city: str, days: int = 3) -> str:
    """获取未来几天的天气预报
    
    Args:
        city: 城市名称
        days: 预报天数，默认3天，最多7天
    """
    if days > 7:
        return "错误：最多支持7天预报"
    if days < 1:
        return "错误：天数必须大于0"
    
    forecasts = []
    conditions = ["☀️ 晴", "⛅ 多云", "🌤️ 晴间多云", "🌦️ 阵雨", "☁️ 阴"]
    for i in range(1, days + 1):
        cond = conditions[i % len(conditions)]
        high = 25 + (i % 5)
        low = 15 + (i % 3)
        forecasts.append(f"  第{i}天: {cond}，温度 {low}-{high}°C")
    
    return f"📍 {city}未来{days}天预报:\n" + "\n".join(forecasts)


@mcp.tool()
def compare_cities(city1: str, city2: str) -> str:
    """对比两个城市的天气
    
    Args:
        city1: 第一个城市
        city2: 第二个城市
    """
    w1 = get_current_weather(city1)
    w2 = get_current_weather(city2)
    return f"天气对比：\n\n📍 {city1}: {w1}\n📍 {city2}: {w2}"


# ============ Resources（资源）============

@mcp.resource("weather://cities/supported")
def get_supported_cities() -> str:
    """返回支持查询天气的城市列表"""
    cities = ["北京", "上海", "深圳", "广州", "成都", "杭州"]
    return "支持查询天气的城市：\n" + "\n".join(f"  - {c}" for c in cities)


@mcp.resource("weather://alert/{city}")
def get_weather_alert(city: str) -> str:
    """获取指定城市的天气预警信息"""
    alerts = {
        "北京": "🟡 大风蓝色预警：预计未来24小时阵风可达7级",
        "上海": "🔴 暴雨橙色预警：预计未来6小时降雨量将达100mm以上",
    }
    return alerts.get(city, f"✅ {city}当前无天气预警")


# ============ Prompts（提示模板）============

@mcp.prompt()
def weather_report_prompt(city: str) -> str:
    """生成天气分析报告的提示模板"""
    return f"""请为{city}生成一份详细的天气分析报告，包含：
1. 当前天气状况概述
2. 未来3天天气预报分析
3. 出行建议
4. 健康提示

请使用专业但易懂的语言。"""


if __name__ == "__main__":
    mcp.run()
```

---

## 四、TypeScript路线：用官方SDK构建服务器

### 4.1 项目初始化

```bash
# 创建项目
mkdir mcp-note-server && cd mcp-note-server
npm init -y

# 安装MCP SDK和类型校验库
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node

# 初始化TypeScript配置
npx tsc --init
```

修改`tsconfig.json`关键配置：

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}
```

### 4.2 构建笔记管理服务器

创建`src/index.ts`：

```typescript
#!/usr/bin/env node

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// 初始化MCP服务器
const server = new McpServer({
  name: "note-server",
  version: "1.0.0",
  description: "笔记管理服务 - 轻量级笔记CRUD操作",
});

// 内存存储（实际项目中替换为数据库）
interface Note {
  id: string;
  title: string;
  content: string;
  tags: string[];
  createdAt: string;
  updatedAt: string;
}

const notes: Map<string, Note> = new Map();

function generateId(): string {
  return Date.now().toString(36) + Math.random().toString(36).slice(2);
}

// ============ Tools ============

server.tool(
  "create_note",
  "创建一条新笔记",
  {
    title: z.string().describe("笔记标题"),
    content: z.string().describe("笔记内容"),
    tags: z.array(z.string()).optional().describe("标签列表"),
  },
  async ({ title, content, tags = [] }) => {
    const id = generateId();
    const now = new Date().toISOString();
    const note: Note = { id, title, content, tags, createdAt: now, updatedAt: now };
    notes.set(id, note);
    return {
      content: [{ type: "text" as const, text: `✅ 笔记已创建\nID: ${id}\n标题: ${title}` }],
    };
  }
);

server.tool(
  "list_notes",
  "列出所有笔记（支持按标签筛选）",
  {
    tag: z.string().optional().describe("按标签筛选"),
  },
  async ({ tag }) => {
    let filtered = Array.from(notes.values());
    if (tag) {
      filtered = filtered.filter((n) => n.tags.includes(tag));
    }
    if (filtered.length === 0) {
      return {
        content: [{ type: "text" as const, text: "📭 没有找到笔记" }],
      };
    }
    const list = filtered
      .map((n) => `- [${n.id}] ${n.title} (${n.tags.join(", ") || "无标签"}) ${n.updatedAt.split("T")[0]}`)
      .join("\n");
    return {
      content: [{ type: "text" as const, text: `📝 笔记列表 (${filtered.length}条):\n${list}` }],
    };
  }
);

server.tool(
  "read_note",
  "读取指定ID的笔记详情",
  {
    id: z.string().describe("笔记ID"),
  },
  async ({ id }) => {
    const note = notes.get(id);
    if (!note) {
      return {
        content: [{ type: "text" as const, text: `❌ 未找到ID为 ${id} 的笔记` }],
        isError: true,
      };
    }
    return {
      content: [
        {
          type: "text" as const,
          text: `# ${note.title}\n\n${note.content}\n\n---\n标签: ${note.tags.join(", ") || "无"}\n创建: ${note.createdAt}\n更新: ${note.updatedAt}`,
        },
      ],
    };
  }
);

server.tool(
  "delete_note",
  "删除指定ID的笔记",
  {
    id: z.string().describe("笔记ID"),
  },
  async ({ id }) => {
    const deleted = notes.delete(id);
    return {
      content: [
        {
          type: "text" as const,
          text: deleted ? `✅ 已删除笔记 ${id}` : `❌ 未找到笔记 ${id}`,
        },
      ],
    };
  }
);

// ============ Resources ============

server.resource("notes://all", "notes://all", async (uri) => {
  const allNotes = Array.from(notes.values());
  return {
    contents: [
      {
        uri: uri.href,
        text: JSON.stringify(allNotes, null, 2),
      },
    ],
  };
});

// ============ Prompts ============

server.prompt(
  "summarize_notes",
  "生成所有笔记的摘要报告",
  [],
  async () => {
    const count = notes.size;
    const allTags = new Set(Array.from(notes.values()).flatMap((n) => n.tags));
    return {
      messages: [
        {
          role: "user" as const,
          content: {
            type: "text" as const,
            text: `当前共有 ${count} 条笔记，使用了 ${allTags.size} 个标签（${[...allTags].join("、")}）。\n请根据这些笔记内容生成一份结构化的知识摘要。`,
          },
        },
      ],
    };
  }
);

// ============ 启动服务器 ============

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  // 服务器已启动，通过stdio通信
}

main().catch((err) => {
  console.error("Server error:", err);
  process.exit(1);
});
```

### 4.3 构建与配置

在`package.json`中添加构建和启动脚本：

```json
{
  "name": "mcp-note-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  },
  "bin": {
    "mcp-note-server": "./dist/index.js"
  }
}
```

构建项目：

```bash
npm run build
```

---

## 五、接入Claude Code

### 5.1 配置方式对比

Claude Code提供三种方式注册MCP服务器：

```mermaid
graph LR
    subgraph 方法1["CLI命令（推荐）"]
        A["claude mcp add"]
    end

    subgraph 方法2["项目级配置"]
        B[".mcp.json"]
    end

    subgraph 方法3["用户级配置"]
        C["~/.claude.json"]
    end

    A --> D["Claude Code"]
    B --> D
    C --> D

    style 方法1 fill:#4CAF50,color:#fff
    style 方法2 fill:#2196F3,color:#fff
    style 方法3 fill:#FF9800,color:#fff
```

| 方式 | 作用域 | 适用场景 | 配置文件 |
|------|--------|----------|----------|
| CLI命令 | 项目/用户 | 快速添加 | 自动写入配置 |
| `.mcp.json` | 项目级 | 团队共享，可提交Git | 项目根目录 |
| `~/.claude.json` | 用户级 | 个人全局工具 | 用户主目录 |

### 5.2 方法一：CLI命令添加（推荐）

**添加Python天气服务器：**

```bash
# 在项目目录下执行（项目级）
claude mcp add weather-server -- python /path/to/mcp-weather-server/server.py

# 或添加到用户级（全局可用）
claude mcp add weather-server -s user -- python /path/to/mcp-weather-server/server.py
```

**添加TypeScript笔记服务器：**

```bash
claude mcp add note-server -- node /path/to/mcp-note-server/dist/index.js
```

**带环境变量的配置：**

```bash
claude mcp add weather-server \
  -e OPENWEATHER_API_KEY=your_key \
  -- python /path/to/server.py
```

### 5.3 方法二：`.mcp.json`项目配置

在项目根目录创建`.mcp.json`：

```json
{
  "mcpServers": {
    "weather-server": {
      "command": "python",
      "args": ["/absolute/path/to/mcp-weather-server/server.py"],
      "env": {
        "OPENWEATHER_API_KEY": "your_api_key_here"
      }
    },
    "note-server": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-note-server/dist/index.js"]
    }
  }
}
```

> ⚠️ **安全提示**：`.mcp.json`可能被提交到Git，**不要在env中放真实密钥**。使用环境变量引用或`.claude/settings.json`中的用户级配置。

### 5.4 方法三：用户级全局配置

编辑`~/.claude.json`，在`mcpServers`字段添加：

```json
{
  "mcpServers": {
    "weather-server": {
      "command": "python",
      "args": ["/home/user/mcp-weather-server/server.py"],
      "env": {
        "OPENWEATHER_API_KEY": "sk-real-key-here"
      }
    }
  }
}
```

### 5.5 管理MCP服务器

```bash
# 列出所有已配置的MCP服务器
claude mcp list

# 查看某个服务器详情
claude mcp get weather-server

# 删除服务器
claude mcp remove weather-server

# 以JSON格式添加（复杂配置）
claude mcp add-json weather-server '{
  "command": "python",
  "args": ["./server.py"],
  "env": {"API_KEY": "xxx"}
}'
```

### 5.6 验证连接

启动Claude Code后，MCP服务器会自动加载。验证方式：

```bash
# 启动Claude Code
claude

# 在交互界面中输入
> 帮我查一下北京现在的天气

# 预期结果：Claude会调用weather-server的get_current_weather工具
```

也可以在Claude Code中直接检查：

```
/MCP        # 查看已连接的MCP服务器列表
/tools      # 查看所有可用工具（包括MCP工具）
```

---

## 六、调试与测试

### 6.1 MCP Inspector可视化调试

MCP Inspector是官方提供的交互式调试工具，可在浏览器中测试MCP服务器。

```bash
# 安装并启动Inspector
npx @modelcontextprotocol/inspector

# 指定Python服务器
npx @modelcontextprotocol/inspector python /path/to/server.py

# 指定Node服务器
npx @modelcontextprotocol/inspector node /path/to/dist/index.js
```

启动后浏览器会打开一个Web界面，提供以下功能：

| 功能模块 | 作用 |
|----------|------|
| **Tools面板** | 列出所有工具，输入参数并执行，查看返回结果 |
| **Resources面板** | 浏览和读取资源URI |
| **Prompts面板** | 测试提示模板 |
| **Connection面板** | 查看JSON-RPC通信日志 |

### 6.2 常见问题排查

**问题1：服务器启动失败**

```bash
# 手动测试服务器是否能运行
python /path/to/server.py
# 如果报错，检查Python版本和依赖

# 查看Claude Code日志
claude --debug
```

**问题2：工具未出现在Claude Code中**

```bash
# 检查MCP服务器是否被识别
claude mcp list

# 确认配置文件路径正确（使用绝对路径）
# 确认Python/node命令在PATH中可用
which python
which node
```

**问题3：中文参数编码问题**

Python服务器需确保UTF-8输出：

```python
# 在server.py头部添加
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
```

**问题4：Claude Code权限提示**

首次使用项目级`.mcp.json`中的MCP服务器时，Claude Code会弹出权限确认。这是安全机制。可在`.claude/settings.json`中预先授权：

```json
{
  "permissions": {
    "allow": ["mcp__weather-server__*"]
  }
}
```

### 6.3 编写单元测试

为Python MCP服务器编写测试（使用pytest）：

```python
# test_server.py
import pytest
from server import mcp

def test_get_current_weather():
    """测试天气查询工具"""
    # FastMCP提供test client用于测试
    from mcp.server.fastmcp import FastMCP
    
    result = mcp._tool_manager.call_tool("get_current_weather", {"city": "北京"})
    assert "28" in result or "北京" in str(result)

def test_get_forecast_validation():
    """测试预报参数校验"""
    result = mcp._tool_manager.call_tool(
        "get_weather_forecast", {"city": "北京", "days": 10}
    )
    assert "最多支持7天" in str(result)
```

---

## 七、实战案例：代码审查MCP服务器

以下是一个面向开发团队的完整实战案例——一个代码审查MCP服务器，集成了Git操作、静态分析和报告生成。

### 7.1 项目结构

```
mcp-code-reviewer/
├── server.py           # 主服务器文件
├── analyzers/          # 分析模块
│   ├── __init__.py
│   ├── complexity.py   # 圈复杂度分析
│   └── security.py     # 安全检查
├── requirements.txt
└── README.md
```

### 7.2 服务器实现

```python
# server.py
import os
import subprocess
import json
from pathlib import Path
from mcp.server.fastmcp import FastMCP

mcp = FastMCP(
    "code-reviewer",
    version="1.0.0",
    description="代码审查助手 - 分析Git变更、检测安全和复杂度问题"
)


def run_git(cmd: list[str], cwd: str | None = None) -> str:
    """执行Git命令并返回输出"""
    result = subprocess.run(
        ["git"] + cmd,
        capture_output=True,
        text=True,
        cwd=cwd or os.getcwd()
    )
    return result.stdout.strip()


@mcp.tool()
def analyze_git_diff(repo_path: str = ".", base_branch: str = "main") -> str:
    """分析当前分支与基准分支的代码差异
    
    Args:
        repo_path: Git仓库路径
        base_branch: 基准分支名，默认为main
    
    Returns:
        变更文件列表和统计信息
    """
    # 获取差异统计
    diff_stat = run_git(
        ["diff", "--stat", f"origin/{base_branch}...HEAD"],
        cwd=repo_path
    )
    
    # 获取变更文件列表
    diff_files = run_git(
        ["diff", "--name-only", f"origin/{base_branch}...HEAD"],
        cwd=repo_path
    )
    
    files = diff_files.split("\n") if diff_files else []
    
    # 按文件类型分类
    categories = {
        "🐍 Python": [], "📄 TypeScript": [], "📄 JavaScript": [],
        "🏗️ Config": [], "📦 Other": []
    }
    
    ext_map = {
        ".py": "🐍 Python", ".ts": "📄 TypeScript", ".tsx": "📄 TypeScript",
        ".js": "📄 JavaScript", ".jsx": "📄 JavaScript",
        ".json": "🏗️ Config", ".yaml": "🏗️ Config", ".yml": "🏗️ Config",
    }
    
    for f in files:
        ext = Path(f).suffix
        cat = ext_map.get(ext, "📦 Other")
        categories[cat].append(f)
    
    result = f"📊 变更统计（对比 {base_branch}）:\n\n{diff_stat}\n\n"
    result += "📁 变更文件分类:\n"
    for cat, cat_files in categories.items():
        if cat_files:
            result += f"\n{cat}:\n"
            for f in cat_files:
                result += f"  - {f}\n"
    
    return result


@mcp.tool()
def check_python_complexity(file_path: str) -> str:
    """检查Python文件的圈复杂度
    
    Args:
        file_path: Python文件路径
    """
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            lines = f.readlines()
    except FileNotFoundError:
        return f"❌ 文件不存在: {file_path}"
    
    # 简单的复杂度估算（计算if/for/while/and/or数量）
    complexity_keywords = ["if ", "elif ", "for ", "while ", "and ", "or ", "except "]
    total_complexity = 1  # 基础复杂度
    issues = []
    
    for i, line in enumerate(lines, 1):
        stripped = line.strip()
        if stripped.startswith("#"):
            continue
        for kw in complexity_keywords:
            if kw in stripped:
                total_complexity += 1
    
    if total_complexity > 15:
        level = "🔴 高复杂度"
    elif total_complexity > 8:
        level = "🟡 中等复杂度"
    else:
        level = "🟢 低复杂度"
    
    return (
        f"📋 复杂度分析: {file_path}\n"
        f"圈复杂度: {total_complexity} {level}\n"
        f"总行数: {len(lines)}\n"
        f"代码行数: {sum(1 for l in lines if l.strip() and not l.strip().startswith('#'))}"
    )


@mcp.tool()
def generate_review_summary(repo_path: str = ".", base_branch: str = "main") -> str:
    """生成代码审查摘要报告
    
    Args:
        repo_path: 仓库路径
        base_branch: 基准分支
    """
    diff_info = analyze_git_diff(repo_path, base_branch)
    
    # 获取提交信息
    commits = run_git(
        ["log", f"origin/{base_branch}...HEAD", "--oneline"],
        cwd=repo_path
    )
    
    return (
        f"📋 代码审查摘要报告\n"
        f"{'='*40}\n\n"
        f"{diff_info}\n\n"
        f"💬 提交记录:\n{commits}\n\n"
        f"建议审查重点:\n"
        f"  1. 检查新增文件的安全性和复杂度\n"
        f"  2. 确认配置文件变更是否符合预期\n"
        f"  3. 验证测试覆盖率"
    )


@mcp.resource("review://template")
def get_review_template() -> str:
    """代码审查模板"""
    return """## 代码审查清单

### 功能性
- [ ] 代码实现了预期功能
- [ ] 边界条件已处理
- [ ] 错误处理完善

### 安全性
- [ ] 无硬编码密钥/密码
- [ ] 输入已校验和清理
- [ ] 无SQL注入/XSS风险

### 可维护性
- [ ] 命名清晰有意义
- [ ] 复杂度可控
- [ ] 注释充分且准确

### 测试
- [ ] 单元测试覆盖关键路径
- [ ] 集成测试通过
- [ ] 性能测试（如适用）"""


@mcp.prompt()
def code_review_prompt(file_path: str) -> str:
    """对指定文件进行深度代码审查
    
    Args:
        file_path: 要审查的文件路径
    """
    return f"""请对文件 {file_path} 进行全面的代码审查。

审查维度：
1. **代码质量**：命名规范、代码风格、可读性
2. **安全性**：潜在漏洞、敏感信息泄露、输入校验
3. **性能**：不必要的计算、内存泄漏、N+1查询
4. **可维护性**：耦合度、复杂度、可扩展性
5. **测试**：测试覆盖、边界条件、错误路径

请用中文输出审查报告，按严重程度分级（🔴严重 🟡警告 🟢建议）。"""


if __name__ == "__main__":
    mcp.run()
```

### 7.3 注册到Claude Code

```bash
# 添加服务器
claude mcp add code-reviewer \
  -s project \
  -- python /path/to/mcp-code-reviewer/server.py

# 验证
claude mcp list
```

使用示例：

```
请分析当前分支相对于main的代码变更

请检查 src/api/auth.py 的复杂度

请生成代码审查摘要报告
```

---

## 八、生产级最佳实践

### 8.1 安全原则

```mermaid
graph TB
    S["MCP服务器安全"] --> A["输入验证"]
    S --> B["权限最小化"]
    S --> C["敏感信息保护"]
    S --> D["错误处理"]

    A --> A1["使用Zod/Pydantic校验参数"]
    A --> A2["限制文件系统访问范围"]
    A --> A3["防止命令注入"]

    B --> B1["只暴露必要的工具"]
    B --> B2["不直接暴露数据库连接"]
    B --> B3["使用只读权限优先"]

    C --> C1["环境变量存储密钥"]
    C --> C2["不在日志中输出敏感数据"]
    C --> C3["响应中脱敏处理"]

    D --> D1["所有异常捕获并返回友好消息"]
    D --> D2["设置超时限制"]
    D --> D3["记录操作审计日志"]
```

### 8.2 性能优化

| 优化点 | 实践方案 |
|--------|----------|
| **工具粒度** | 保持工具功能单一，避免一个工具做太多事 |
| **返回数据** | 控制返回数据量，避免返回超大文本 |
| **异步操作** | Python使用`async def`，TypeScript使用`async/await` |
| **缓存** | 对频繁调用的数据实现缓存层 |
| **超时** | 设置合理的工具执行超时 |

### 8.3 Python异步工具示例

```python
import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("async-example")

@mcp.tool()
async def fetch_api_data(url: str) -> str:
    """异步获取API数据
    
    Args:
        url: API端点URL
    """
    async with httpx.AsyncClient(timeout=10.0) as client:
        try:
            response = await client.get(url)
            response.raise_for_status()
            return f"✅ 状态码: {response.status_code}\n数据长度: {len(response.text)} 字符"
        except httpx.TimeoutException:
            return "❌ 请求超时"
        except httpx.HTTPStatusError as e:
            return f"❌ HTTP错误: {e.response.status_code}"
```

### 8.4 发布与分发

将MCP服务器发布为可复用的npm包或Python包：

**Python包发布流程：**

```bash
# 1. 创建pyproject.toml
# 2. 添加console_scripts入口
# 3. 构建并发布
pip install build
python -m build
pip install twine
twine upload dist/*
```

**npm包发布流程：**

```bash
# 1. 配置package.json的bin字段
# 2. 在入口文件添加shebang：#!/usr/bin/env node
# 3. 发布
npm publish
```

用户安装后只需一行命令注册：

```bash
# Python包
claude mcp add my-tool -- my-tool-server

# npm包
claude mcp add my-tool -- npx -y my-mcp-server
```

---

## 九、完整工作流程总结

```mermaid
flowchart TD
    A["🚀 需求分析"] --> B["选择技术栈"]
    B --> B1{"Python / TypeScript?"}
    B1 -->|"Python"| C1["安装FastMCP<br/>pip install fastmcp"]
    B1 -->|"TypeScript"| C2["安装MCP SDK<br/>npm install @modelcontextprotocol/sdk"]

    C1 --> D["实现三大原语"]
    C2 --> D

    D --> D1["🛠️ Tools"]
    D --> D2["📄 Resources"]
    D --> D3["💬 Prompts"]

    D1 --> E["本地测试"]
    D2 --> E
    D3 --> E

    E --> E1["MCP Inspector<br/>可视化调试"]
    E --> E2["单元测试"]

    E1 --> F["注册到Claude Code"]
    E2 --> F

    F --> F1["claude mcp add"]
    F --> F2["或 .mcp.json"]

    F1 --> G["集成测试"]
    F2 --> G

    G --> G1{"通过?"}
    G1 -->|"是"| H["📦 打包发布"]
    G1 -->|"否"| D

    H --> I["npm publish / PyPI upload"]
    I --> J["🎉 完成"]
```

---

## 十、训练营适用性评估

| 维度 | 评估 |
|------|------|
| **适合训练营类型** | AI开发训练营、DevOps工具链训练营、企业内部工具开发培训 |
| **前置要求** | Python或TypeScript基础，命令行操作经验 |
| **建议教学时长** | 4-6小时（含实战练习） |
| **模块拆分建议** | 理论1h + Python实战1.5h + TypeScript实战1.5h + 调试部署1h |
| **难度等级** | ⭐⭐⭐ 中等（需要编程基础，但MCP封装大大降低了难度） |
| **实操价值** | 极高——学员完成后可将团队内部工具直接接入Claude Code |

---

## 参考来源

1. [Build an MCP server - Model Context Protocol 官方文档](https://modelcontextprotocol.io/docs/develop/build-server) — MCP服务器构建官方指南
2. [Connect Claude Code to tools via MCP - Claude Code Docs](https://code.claude.com/docs/en/mcp) — Claude Code MCP集成官方文档
3. [FastMCP GitHub - PrefectHQ](https://github.com/PrefectHQ/fastmcp) — FastMCP Python框架源码和文档
4. [How to Build Your First MCP Server for Claude (Step-by-Step, 2026)](https://www.aiforanything.io/blog/how-to-build-mcp-server-claude-2026) — TypeScript MCP服务器完整教程
5. [MCP Inspector - Model Context Protocol](https://modelcontextprotocol.io/docs/tools/inspector) — MCP调试工具官方文档
6. [@modelcontextprotocol/sdk - npm](https://www.npmjs.com/package/@modelcontextprotocol/sdk) — TypeScript MCP SDK官方包

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
