本教程面向希望用 Python 构建自定义 MCP 服务器的开发者,从零完成一个生产级 MCP 服务器项目。你将掌握 FastMCP 框架的核心 API、Tools/Resources/Prompts 三大原语的设计模式、Claude Code 集成配置、调试部署全链路。适合有 Python 基础、了解 Claude Code 基本用法的开发者。
学习目标:完成一个「代码审查助手」MCP 服务器,具备文件分析、规范检查、审查报告生成三大能力,可直接接入 Claude Code 使用。
| 项目 | 要求 |
|---|---|
| Python | 3.10+ |
| Claude Code | 最新版(claude --version 确认) |
| 包管理 | uv 或 pip |
| 操作系统 | macOS / Linux / Windows(WSL) |
安装核心依赖:
# 推荐 uv(更快)
uv pip install fastmcp
# 或传统 pip
pip install fastmcp
验证安装:
python -c "import fastmcp; print(fastmcp.__version__)"
预期输出类似 3.2.4(以实际版本为准)。
MCP(Model Context Protocol)采用 Client-Server 架构, Claude Code 内置 MCP Client,你开发的是 MCP Server。
┌─────────────────┐ stdio/HTTP ┌─────────────────┐
│ Claude Code │◄───────────────►│ MCP Server │
│ (MCP Client) │ JSON-RPC 2.0 │ (你的 Python) │
└─────────────────┘ └────────┬────────┘
│
┌──────────┼──────────┐
│ │ │
┌────▼───┐ ┌───▼────┐ ┌───▼────┐
│ Tools │ │Resources│ │Prompts │
└────────┘ └────────┘ └────────┘
graph TB
subgraph "MCP Server 三大原语"
T["🔧 Tools<br/>可执行函数<br/>模型主动调用"]
R["📄 Resources<br/>只读数据源<br/>按 URI 访问"]
P["💬 Prompts<br/>提示模板<br/>用户触发"]
end
T -->|副作用| E1["执行操作、修改状态"]
R -->|无副作用| E2["获取上下文数据"]
P -->|参数化| E3["生成结构化提示"]
| 原语 | 类比 | 何时使用 | 示例 |
|---|---|---|---|
| Tool | API 端点 | 需要执行操作、有副作用 | 代码分析、文件写入 |
| Resource | GET 请求 | 提供只读上下文数据 | 配置文件、数据库记录 |
| Prompt | 模板函数 | 参数化提示生成 | 审查模板、报告格式 |
graph LR
subgraph "本地开发"
A["Claude Code"] -->|stdio| B["MCP Server<br/>子进程"]
end
subgraph "远程部署"
C["Claude Code"] -->|Streamable HTTP| D["MCP Server<br/>HTTP 服务"]
end
本教程使用 stdio 模式(最常用的 Claude Code 集成方式),最后介绍 HTTP 模式。
mkdir code-review-mcp && cd code-review-mcp
uv init
编辑 pyproject.toml:
[project]
name = "code-review-mcp"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
"fastmcp>=3.0.0",
]
创建 server.py:
from fastmcp import FastMCP
mcp = FastMCP("code-review")
@mcp.tool()
def hello(name: str) -> str:
"""向用户打招呼"""
return f"Hello, {name}! 代码审查助手已就绪。"
if __name__ == "__main__":
mcp.run()
# 安装依赖
uv sync
# 启动服务器(stdio 模式)
uv run python server.py
此时服务器等待 stdin 输入。按 Ctrl+C 退出,这是正常的——stdio 模式下由 Claude Code 作为客户端驱动。
# 添加 MCP 服务器到 Claude Code
claude mcp add code-review -- uv run --directory /完整路径/code-review-mcp python server.py
验证:
claude mcp list
预期输出:
code-review: uv run --directory /.../code-review-mcp python server.py
在 Claude Code 会话中测试:
> 使用 hello 工具向 Alice 打招呼
Claude Code 会自动调用你的 hello Tool,返回 Hello, Alice! 代码审查助手已就绪。
常见问题:
| 问题 | 原因 | 解决方案 |
|---|---|---|
Server not found |
路径不正确 | 使用绝对路径 |
Connection refused |
依赖未安装 | 先执行 uv sync |
Module not found |
Python 版本过低 | 确认 3.10+ |
graph TB
subgraph "code-review MCP Server"
M["FastMCP 实例"]
subgraph "Tools"
T1["analyze_code<br/>代码复杂度分析"]
T2["check_style<br/>编码规范检查"]
T3["generate_report<br/>生成审查报告"]
end
subgraph "Resources"
R1["config://rules<br/>审查规则配置"]
R2["config://templates<br/>报告模板"]
end
subgraph "Prompts"
P1["review_template<br/>审查提示模板"]
end
end
CC["Claude Code"] -->|JSON-RPC| M
M --> T1 & T2 & T3
M --> R1 & R2
M --> P1
Tool 是 MCP 最核心的原语。FastMCP 使用 @mcp.tool() 装饰器,参数通过类型注解自动推断 JSON Schema。
import ast
from typing import Annotated
from pydantic import Field
@mcp.tool()
def analyze_code(
source_code: Annotated[str, Field(description="要分析的 Python 源代码")],
threshold: Annotated[int, Field(description="圈复杂度阈值,默认 10")] = 10,
) -> dict:
"""
分析 Python 代码的圈复杂度和函数统计。
返回每个函数的复杂度评分、行数、参数数量。
"""
try:
tree = ast.parse(source_code)
except SyntaxError as e:
return {"error": f"语法错误: {e}"}
results = []
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
complexity = _calculate_complexity(node)
results.append({
"function": node.name,
"line": node.lineno,
"complexity": complexity,
"params": len(node.args.args),
"lines_of_code": node.end_lineno - node.lineno + 1,
"exceeds_threshold": complexity > threshold,
})
return {
"total_functions": len(results),
"exceeding_threshold": sum(1 for r in results if r["exceeds_threshold"]),
"functions": results,
}
def _calculate_complexity(node: ast.AST) -> int:
"""计算圈复杂度(简化版 McCabe)"""
complexity = 1
for child in ast.walk(node):
if isinstance(child, (ast.If, ast.While, ast.For, ast.ExceptHandler)):
complexity += 1
elif isinstance(child, ast.BoolOp):
complexity += len(child.values) - 1
return complexity
关键设计要点:
Annotated + Field:提供参数描述,Claude Code 据此决定何时调用dict:FastMCP 自动序列化为 JSON,Claude 直接理解import re
STYLE_RULES = {
"line_too_long": {"pattern": r".{121,}", "message": "行长度超过 120 字符"},
"trailing_whitespace": {"pattern": r"[ \t]+$", "message": "行尾有多余空白"},
"missing_type_hint": {
"pattern": r"def\s+\w+\([^)]+\)(?!\s*->)",
"message": "函数缺少返回类型注解",
},
"todo_without_ticket": {
"pattern": r"#\s*TODO(?!\s*\(\#?\d+\))",
"message": "TODO 未关联 ticket 编号",
},
"bare_except": {"pattern": r"except\s*:", "message": "使用裸 except,应指定异常类型"},
}
@mcp.tool()
def check_style(
source_code: Annotated[str, Field(description="要检查的源代码")],
rules: Annotated[list[str] | None, Field(
description="要应用的规则名称列表,为空则应用全部规则"
)] = None,
) -> dict:
"""
检查代码是否符合编码规范。
支持的规则:line_too_long, trailing_whitespace, missing_type_hint,
todo_without_ticket, bare_except。
"""
active_rules = rules if rules else list(STYLE_RULES.keys())
violations = []
lines = source_code.splitlines()
for rule_name in active_rules:
rule = STYLE_RULES.get(rule_name)
if not rule:
continue
for i, line in enumerate(lines, 1):
if re.search(rule["pattern"], line):
violations.append({
"rule": rule_name,
"line": i,
"message": rule["message"],
"content": line.strip()[:80],
})
return {
"total_violations": len(violations),
"by_rule": {r: sum(1 for v in violations if v["rule"] == r)
for r in active_rules},
"violations": violations,
}
@mcp.tool()
def generate_report(
analysis: Annotated[dict, Field(description="analyze_code 的返回结果")],
style_issues: Annotated[dict, Field(description="check_style 的返回结果")],
project_name: Annotated[str, Field(description="项目名称")] = "未命名项目",
) -> str:
"""
综合代码分析和规范检查结果,生成 Markdown 格式的审查报告。
"""
lines = [
f"# 代码审查报告:{project_name}",
"",
"## 概要",
"",
f"- 分析函数数量:{analysis.get('total_functions', 0)}",
f"- 复杂度超标函数:{analysis.get('exceeding_threshold', 0)}",
f"- 规范违规数量:{style_issues.get('total_violations', 0)}",
"",
]
# 复杂度警告
high_complexity = [
f for f in analysis.get("functions", [])
if f.get("exceeds_threshold")
]
if high_complexity:
lines.append("## ⚠️ 复杂度警告")
lines.append("")
for func in high_complexity:
lines.append(
f"- `{func['function']}` (L{func['line']}): "
f"复杂度 {func['complexity']}, {func['lines_of_code']} 行"
)
lines.append("")
# 规范问题
by_rule = style_issues.get("by_rule", {})
if any(by_rule.values()):
lines.append("## 📋 规范问题分布")
lines.append("")
for rule, count in by_rule.items():
if count > 0:
lines.append(f"- **{rule}**: {count} 处")
lines.append("")
# 详细违规
violations = style_issues.get("violations", [])
if violations:
lines.append("## 详情")
lines.append("")
for v in violations[:20]: # 限制前 20 条
lines.append(f"- L{v['line']} [{v['rule']}]: {v['message']}")
if len(violations) > 20:
lines.append(f"- ... 还有 {len(violations) - 20} 条")
lines.append("")
lines.append("---")
lines.append(f"*由 code-review MCP 自动生成*")
return "\n".join(lines)
Resource 是只读数据源,Claude Code 通过 URI 访问。适合提供上下文信息。
import json
REVIEW_RULES = {
"complexity_threshold": 10,
"max_line_length": 120,
"required_type_hints": True,
"severity_levels": {
"critical": ["bare_except", "complexity > 20"],
"warning": ["missing_type_hint", "complexity > 10"],
"info": ["trailing_whitespace", "line_too_long"],
},
}
REPORT_TEMPLATES = {
"standard": "## {project} 审查报告\n\n{content}",
"detailed": "# {project} 深度审查\n\n{content}\n\n## 附录\n{appendix}",
}
@mcp.resource("config://rules")
def get_review_rules() -> str:
"""获取代码审查规则配置"""
return json.dumps(REVIEW_RULES, indent=2, ensure_ascii=False)
@mcp.resource("config://templates")
def get_report_templates() -> str:
"""获取报告模板列表"""
return json.dumps(REPORT_TEMPLATES, indent=2, ensure_ascii=False)
Resource vs Tool 的选择原则:
graph TD
A["需要暴露数据?"] -->|是| B{"有副作用?"}
A -->|否| Z["不需要 MCP 原语"]
B -->|是| C["用 Tool"]
B -->|否| D{"数据量大?<br/>需要按需加载?"}
D -->|是| E["用 Resource<br/>支持 URI 模板分页"]
D -->|否| F{"需要参数化?"}
F -->|是| G["用 Tool<br/>返回纯数据"]
F -->|否| H["用 Resource"]
Prompt 让用户可以通过 Claude Code 触发预定义的交互流程。
@mcp.prompt()
def review_template(
file_path: str,
focus: str = "all",
) -> str:
"""
生成代码审查的提示模板。
focus 参数控制审查重点:all / complexity / style / security
"""
focus_instructions = {
"all": "全面审查代码质量、复杂度、编码规范",
"complexity": "重点审查函数复杂度和可维护性",
"style": "重点审查编码规范和格式问题",
"security": "重点审查安全漏洞和敏感信息泄露",
}
instruction = focus_instructions.get(focus, focus_instructions["all"])
return f"""请对以下文件进行代码审查。
文件路径:{file_path}
审查重点:{instruction}
请按以下步骤执行:
1. 读取文件 {file_path} 的内容
2. 调用 analyze_code 工具分析代码复杂度
3. 调用 check_style 工具检查编码规范
4. 调用 generate_report 工具生成审查报告
5. 根据报告给出改进建议
先读取 config://rules 获取审查规则配置。"""
将以上所有部分合并为完整的 server.py:
#!/usr/bin/env python3
"""代码审查 MCP 服务器 - 基于 FastMCP"""
import ast
import json
import re
from typing import Annotated
from fastmcp import FastMCP
from pydantic import Field
mcp = FastMCP("code-review")
# ── 配置数据 ──────────────────────────────────────────
STYLE_RULES = { ... } # 如上定义
REVIEW_RULES = { ... }
REPORT_TEMPLATES = { ... }
# ── 辅助函数 ──────────────────────────────────────────
def _calculate_complexity(node: ast.AST) -> int: ... # 如上定义
# ── Tools ─────────────────────────────────────────────
@mcp.tool()
def analyze_code(...) -> dict: ... # 如上定义
@mcp.tool()
def check_style(...) -> dict: ... # 如上定义
@mcp.tool()
def generate_report(...) -> str: ... # 如上定义
# ── Resources ─────────────────────────────────────────
@mcp.resource("config://rules")
def get_review_rules() -> str: ...
@mcp.resource("config://templates")
def get_report_templates() -> str: ...
# ── Prompts ───────────────────────────────────────────
@mcp.prompt()
def review_template(...) -> str: ...
# ── 启动入口 ──────────────────────────────────────────
if __name__ == "__main__":
mcp.run()
graph TD
subgraph "配置范围层级"
L["Local Scope<br/>.claude/settings.local.json<br/>仅当前项目,个人使用"]
P["Project Scope<br/>.mcp.json<br/>项目级,可提交 Git"]
U["User Scope<br/>~/.claude.json<br/>全局,所有项目"]
end
L -->|"优先级最高"| P
P -->|"次之"| U
推荐方案:团队共享用 .mcp.json(Project Scope),个人调试用 Local Scope。
# User scope(全局可用)
claude mcp add code-review \
--scope user \
-- uv run --directory /home/user/code-review-mcp python server.py
# Project scope(提交到 Git,团队共享)
claude mcp add code-review \
--scope project \
-- uv run --directory ./tools/code-review-mcp python server.py
# Local scope(个人调试)
claude mcp add code-review \
--scope local \
-- uv run python server.py
在项目根目录创建 .mcp.json(推荐纳入版本控制):
{
"mcpServers": {
"code-review": {
"command": "uv",
"args": ["run", "--directory", "./tools/code-review-mcp", "python", "server.py"],
"env": {}
}
}
}
带环境变量的配置:
{
"mcpServers": {
"code-review": {
"command": "uv",
"args": ["run", "python", "server.py"],
"env": {
"REVIEW_STRICTNESS": "high",
"MAX_COMPLEXITY": "8"
}
}
}
}
# 列出已配置的服务器
claude mcp list
# 查看服务器详情
claude mcp get code-review
# 删除服务器
claude mcp remove code-review
# 重置所有 MCP 服务器配置
claude mcp reset
MCP Inspector 是官方调试工具,提供浏览器界面来测试服务器。
# 安装并启动 Inspector
npx @modelcontextprotocol/inspector uv run python server.py
浏览器打开 http://localhost:6274,你可以:
# test_server.py
import pytest
from server import analyze_code, check_style, generate_report
def test_analyze_code_simple():
code = """
def add(a, b):
return a + b
"""
result = analyze_code(code)
assert result["total_functions"] == 1
assert result["functions"][0]["function"] == "add"
assert result["functions"][0]["complexity"] == 1
def test_analyze_code_complex():
code = """
def process(data):
if data:
for item in data:
if item.active:
try:
item.save()
except ValueError:
pass
except TypeError:
pass
"""
result = analyze_code(code, threshold=5)
assert result["total_functions"] == 1
assert result["exceeding_threshold"] == 1
def test_check_style_bare_except():
code = """try:
x = 1
except:
pass
"""
result = check_style(code, rules=["bare_except"])
assert result["total_violations"] == 1
def test_check_style_clean():
code = "x = 1\n"
result = check_style(code)
assert result["total_violations"] == 0
def test_analyze_invalid_syntax():
result = analyze_code("def (broken syntax")
assert "error" in result
def test_generate_report():
analysis = {
"total_functions": 2,
"exceeding_threshold": 1,
"functions": [
{"function": "ok_func", "line": 1, "complexity": 2,
"lines_of_code": 3, "exceeds_threshold": False},
{"function": "bad_func", "line": 5, "complexity": 15,
"lines_of_code": 40, "exceeds_threshold": True},
],
}
style = {
"total_violations": 3,
"by_rule": {"bare_except": 1, "line_too_long": 2},
"violations": [
{"rule": "bare_except", "line": 10, "message": "裸 except"},
],
}
report = generate_report(analysis, style, "test-project")
assert "# 代码审查报告:test-project" in report
assert "bad_func" in report
运行测试:
uv add --dev pytest
uv run pytest test_server.py -v
无需 Claude Code,直接在 Python 中测试:
# debug.py
from server import mcp
# 查看注册的所有原语
print("Tools:", [t.name for t in mcp._tool_manager.tools.values()])
print("Resources:", [r.name for r in mcp._resource_manager.resources.values()])
print("Prompts:", [p.name for p in mcp._prompt_manager.prompts.values()])
# 直接调用 Tool
result = mcp._tool_manager.call_tool("analyze_code", {
"source_code": "def hello(): pass"
})
print("Result:", result)
graph TD
A["MCP 服务器异常"] --> B{"Claude Code<br/>能看到工具?"}
B -->|"看不到"| C["检查 claude mcp list"]
C --> C1["路径是否绝对?"]
C --> C2["uv sync 是否执行?"]
C --> C3["Python 版本 3.10+?"]
B -->|"看到但调用失败"| D["查看 Claude Code 日志"]
D --> D1["参数类型不匹配?"]
D --> D2["返回值序列化失败?"]
D --> D3["异常被吞掉了?"]
D1 --> E["添加类型注解"]
D2 --> F["确保返回 dict/str"]
D3 --> G["添加 try/except 日志"]
当你需要远程部署或多客户端共享时,使用 Streamable HTTP 传输。
# server.py 末尾修改
if __name__ == "__main__":
mcp.run(transport="streamable-http", host="0.0.0.0", port=8080)
启动:
uv run python server.py
# 服务器监听 http://0.0.0.0:8080/mcp
{
"mcpServers": {
"code-review-remote": {
"url": "http://your-server:8080/mcp"
}
}
}
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY pyproject.toml .
RUN pip install uv && uv sync --no-dev
COPY server.py .
EXPOSE 8080
CMD ["uv", "run", "python", "server.py"]
# docker-compose.yml
services:
code-review-mcp:
build: .
ports:
- "8080:8080"
environment:
- REVIEW_STRICTNESS=high
restart: unless-stopped
docker compose up -d
sequenceDiagram
participant User as 开发者
participant CC as Claude Code
participant MCP as code-review MCP
participant FS as 文件系统
User->>CC: /review src/auth/login.py
CC->>MCP: 调用 review_template Prompt
MCP-->>CC: 返回审查流程提示
CC->>MCP: 读取 config://rules
MCP-->>CC: 返回审查规则配置
CC->>FS: 读取 src/auth/login.py
FS-->>CC: 返回源代码内容
CC->>MCP: 调用 analyze_code(source_code)
MCP-->>CC: 返回复杂度分析结果
CC->>MCP: 调用 check_style(source_code)
MCP-->>CC: 返回规范检查结果
CC->>MCP: 调用 generate_report(analysis, style)
MCP-->>CC: 返回 Markdown 报告
CC->>User: 展示审查报告 + 改进建议
扩展 Tool 支持不同语言的复杂度分析:
LANGUAGE_ANALYZERS = {
"python": _analyze_python,
"javascript": _analyze_javascript,
"go": _analyze_go,
}
@mcp.tool()
def analyze_code_multilang(
source_code: Annotated[str, Field(description="源代码")],
language: Annotated[str, Field(description="语言: python/javascript/go")],
threshold: Annotated[int, Field(description="复杂度阈值")] = 10,
) -> dict:
"""分析多种编程语言的代码复杂度"""
analyzer = LANGUAGE_ANALYZERS.get(language)
if not analyzer:
return {"error": f"不支持的语言: {language},支持: {list(LANGUAGE_ANALYZERS.keys())}"}
return analyzer(source_code, threshold)
对于长时间操作,使用 Progress 通知:
@mcp.tool()
async def analyze_large_project(
directory: Annotated[str, Field(description="项目目录路径")],
ctx: Annotated[Context, Field(description="MCP 上下文")] = None,
) -> dict:
"""分析整个项目的代码质量(带进度通知)"""
import os
py_files = []
for root, _, files in os.walk(directory):
py_files.extend(
os.path.join(root, f) for f in files if f.endswith(".py")
)
all_results = []
total = len(py_files)
for i, filepath in enumerate(py_files):
# 发送进度通知
if ctx:
await ctx.report_progress(i + 1, total)
with open(filepath) as f:
result = analyze_code(f.read())
result["file"] = filepath
all_results.append(result)
return {
"files_analyzed": total,
"results": all_results,
}
from fastmcp import Context
@mcp.tool()
async def smart_review(
source_code: str,
ctx: Context,
) -> str:
"""带日志的智能审查"""
# 记录日志(Claude Code 可见)
await ctx.info(f"开始审查 {len(source_code)} 字符的代码")
analysis = analyze_code(source_code)
style = check_style(source_code)
await ctx.info(f"发现 {analysis['exceeding_threshold']} 个高复杂度函数")
await ctx.info(f"发现 {style['total_violations']} 处规范问题")
report = generate_report(analysis, style)
return report
from fastmcp import FastMCP
mcp = FastMCP("code-review",
# 错误不暴露内部堆栈
mask_error_details=True
)
@mcp.tool()
def safe_analyze(code: str) -> dict:
"""安全的代码分析,错误友好返回"""
try:
result = analyze_code(code)
except MemoryError:
return {"error": "代码过大,请分段分析"}
except RecursionError:
return {"error": "代码嵌套层级过深"}
except Exception as e:
return {"error": f"分析失败: {type(e).__name__}"}
return result
import functools
# 缓存 Resource 数据(规则配置不常变)
@mcp.resource("config://rules")
@functools.lru_cache(maxsize=1)
def get_review_rules() -> str:
"""获取审查规则(缓存)"""
return json.dumps(REVIEW_RULES, indent=2, ensure_ascii=False)
# 大文件分块处理
@mcp.tool()
def analyze_code_chunked(
source_code: str,
chunk_size: Annotated[int, Field(description="每块行数")] = 200,
) -> dict:
"""分块分析大文件"""
lines = source_code.splitlines()
chunks = [lines[i:i+chunk_size] for i in range(0, len(lines), chunk_size)]
results = []
for i, chunk in enumerate(chunks):
chunk_code = "\n".join(chunk)
result = analyze_code(chunk_code)
result["chunk"] = i + 1
results.append(result)
return {
"total_chunks": len(chunks),
"chunk_results": results,
}
import os
@mcp.tool()
def analyze_file(
file_path: Annotated[str, Field(description="文件路径")],
) -> dict:
"""安全地分析指定文件"""
# 防止路径穿越
base_dir = os.getenv("ALLOWED_DIR", ".")
abs_path = os.path.abspath(os.path.join(base_dir, file_path))
if not abs_path.startswith(os.path.abspath(base_dir)):
return {"error": "路径越界,拒绝访问"}
if not os.path.exists(abs_path):
return {"error": f"文件不存在: {file_path}"}
# 限制文件大小
if os.path.getsize(abs_path) > 1_000_000: # 1MB
return {"error": "文件过大(>1MB),请分段处理"}
with open(abs_path) as f:
return analyze_code(f.read())
code-review-mcp/
├── pyproject.toml # 项目配置
├── server.py # MCP 服务器主入口
├── analyzers/ # 分析器模块
│ ├── __init__.py
│ ├── complexity.py # 复杂度分析
│ ├── style.py # 规范检查
│ └── security.py # 安全检查
├── config/ # 配置文件
│ ├── rules.json # 审查规则
│ └── templates.json # 报告模板
├── tests/ # 测试
│ ├── test_complexity.py
│ ├── test_style.py
│ └── test_server.py
├── Dockerfile # Docker 部署
├── docker-compose.yml # 编排配置
└── .mcp.json # Claude Code 项目级配置
graph LR
A["1. uv init"] --> B["2. 安装 FastMCP"]
B --> C["3. 实现 Tool"]
C --> D["4. 实现 Resource"]
D --> E["5. 实现 Prompt"]
E --> F["6. 编写测试"]
F --> G["7. Inspector 调试"]
G --> H["8. claude mcp add"]
H --> I["9. 集成验证"]
I --> J["10. Docker 部署"]
| 步骤 | 命令 | 预期结果 |
|---|---|---|
| 1 | uv init && cd code-review-mcp |
项目创建成功 |
| 2 | uv add fastmcp |
依赖安装完成 |
| 3 | 编写 server.py 中的 Tool 函数 |
函数可被 @mcp.tool() 注册 |
| 4 | 添加 Resource 装饰器 | URI 可访问 |
| 5 | 添加 Prompt 模板 | 模板可触发 |
| 6 | uv run pytest tests/ -v |
全部测试通过 |
| 7 | npx @modelcontextprotocol/inspector uv run python server.py |
浏览器可交互测试 |
| 8 | claude mcp add code-review -- uv run python server.py |
服务器出现在列表 |
| 9 | Claude Code 中调用 Tool | 返回正确结果 |
| 10 | docker compose up -d |
HTTP 模式正常监听 |
| 维度 | Python (FastMCP) | TypeScript (官方 SDK) |
|---|---|---|
| 上手速度 | 极快(装饰器驱动) | 较快(面向对象) |
| 生态兼容 | ML/AI/数据处理 | Web 开发/Node.js 生态 |
| 类型安全 | Pydantic 运行时 | Zod + TS 编译时 |
| 性能 | 够用(I/O 密集型场景) | 更优(CPU 密集型) |
| 部署 | Docker / Serverless | Docker / Edge / Serverless |
| 适用场景 | 数据分析、ML Pipeline、脚本工具 | Web 服务、API 网关、前后端统一 |
建议:已有 Python 代码库或涉及数据/ML → 选 FastMCP;已有 TypeScript 项目或需要 Web 集成 → 选官方 SDK。
| 项目 | 评估 |
|---|---|
| 适合训练营类型 | AI 工具开发、Python 进阶、DevOps 自动化 |
| 教学时长 | 3-4 小时(含动手实验) |
| 难度等级 | 中级(需要 Python 基础) |
| 实验环境要求 | Python 3.10+、Claude Code、Node.js(Inspector) |
| 可拆分模块 | 基础篇(1-5节,2h)+ 进阶篇(6-10节,2h) |
[!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 等场景全覆盖。
