MCP 课程文档
模块 1:构建 MCP 服务器
并获得增强的文档体验
开始使用
模块 1:构建 MCP 服务器
CodeCraft Studios 的 PR 混乱
这是您在 CodeCraft Studios 的第一周,您正在目睹一件让每个开发人员都感到不寒而栗的事情。团队的拉取请求看起来是这样的
- “东西”
- “更多更改”
- “修复”
- “更新内容”
同时,代码审查积压越来越多,因为审查人员无法理解更改了什么或为什么更改。来自后端团队的 Sarah 花了 30 分钟试图弄清楚“各种改进”到底意味着什么,而来自前端的 Mike 不得不翻阅 47 个文件才能理解一个“小修复”。
团队知道他们需要更好的 PR 描述,但每个人都忙于交付功能,无暇编写详细的解释。他们需要一个既能提供帮助又不会拖慢他们的解决方案。
您的任务:构建一个智能 PR 代理,自动分析代码更改并建议有用的描述。
截屏:PR 问题实际案例 😬
您将看到什么:CodeCraft Studios 中一个真实的 PR,标题为“各种改进”,描述简单地写着“修复了一些东西并进行了更新”。很经典,对吧?
困惑:观察队友们是如何挣扎的
- Sarah(3 小时前):“修复了什么?我看到了 User 模型的变化,但无法分辨这是在解决 bug 还是在添加功能。”
- Jamie(3 小时前):“有 8 个文件散布在 4 个服务中……这些更改是相关的吗?我审查时应该关注什么?”
痛点:截屏显示了实际的差异——8 个文件散布在多个服务中,零上下文。审查人员必须自己拼凑出故事,浪费宝贵时间,并可能错过关键问题。
为什么这很重要:这正是您的 MCP 服务器将解决的 PR 混乱问题!在本模块结束时,您将把这些神秘的 PR 转化为清晰、可操作的描述,让每个人的工作都变得更轻松。
您将构建什么
在本模块中,您将创建 CodeCraft Studios 自动化系统的基础:一个 MCP 服务器,它将改变团队编写拉取请求的方式。本模块将重点介绍您将在模块 2 和 3 中构建的核心 MCP 概念。
截屏:您的 PR 代理挽救了局面!🚀
解决方案实际案例:观看您的 MCP 服务器如何将 PR 混乱转化为清晰
analyze_file_changes
- 获取所有更改(8 个文件,共 453 行!)get_pr_templates
- 向 Claude 展示 7 个可供选择的模板suggest_template
- Claude 选择“Feature”(明智之举!)
您将看到什么:Claude 不仅仅选择了一个模板——它还:
- 编写了实际更改的清晰摘要
- 发现了安全问题(天哪,未哈希的密码!)
- 创建了一个很好的后续工作待办事项列表
- 甚至优先处理需要首先修复的问题
“哇”时刻 ✨:只需几秒钟,您的 MCP 服务器就帮助 Claude 将同一个分支转化为一个能实际解释发生了什么的 PR。不再有困惑的审查者,不再有“这是干什么用的?”的评论。
这就是您将要构建的:一个将 PR 恐惧转化为 PR 愉悦的工具——让我们开始吧!
您将学到什么
在本基础模块中,您将掌握:
- 如何使用 FastMCP 创建基本的 MCP 服务器 - 模块 2 和 3 的构建块
- 实现 MCP 工具以进行数据检索和分析 - 您将在单元 3 中使用的核心原语
- 让 Claude 基于原始数据做出智能决策 - 所有 MCP 开发的关键原则
- 测试和验证您的 MCP 服务器 - 构建可靠工具的基本技能
概述
您的 PR 代理将使用 MCP 开发的一个关键原则解决 CodeCraft Studios 的问题:您将为 Claude 提供原始 git 数据,而不是硬编码关于如何编写良好 PR 的严格规则,并让它智能地建议适当的描述。
这种方法有效的原因是:
- 灵活分析:Claude 可以理解简单规则遗漏的上下文
- 自然语言:建议感觉像人,而不是机器人
- 适应性强:适用于任何代码库或编码风格
您将实现三个基本工具,为整个自动化系统建立模式:
- analyze_file_changes - 检索 git diff 信息和更改的文件(数据收集)
- get_pr_templates - 列出可用的 PR 模板(资源管理)
- suggest_template - 允许 Claude 推荐最合适的模板(智能决策)
入门
先决条件
- Python 3.10 或更高版本
- 已安装 Git 且有一个 Git 仓库可供测试
- uv 包管理器 (安装指南)
启动代码
克隆启动代码仓库
git clone https://github.com/huggingface/mcp-course.git
导航到启动代码目录
cd mcp-course/projects/unit3/build-mcp-server/starter
安装依赖项
您可能需要为该项目创建一个虚拟环境
uv venv .venv
source .venv/bin/activate # On Windows use: .venv\Scripts\activate
uv sync --all-extras
您的任务
这是您第一次亲手进行 MCP 开发!打开 server.py
并按照 TODO 注释实现这三个工具。启动代码提供了基本结构——您需要:
- 实现
analyze_file_changes
以运行 git 命令并返回 diff 数据- ⚠️ 重要:您可能会遇到令牌限制错误(每个响应最大 25,000 个令牌)
- 这是一个真实的限制,用于教授正确的输出管理
- 请参阅下面的“处理大型输出”部分以获取解决方案
- ⚠️ 注意:Git 命令默认将在 MCP 服务器的目录中运行。有关详细信息,请参阅下面的“工作目录注意事项”
- 实现
get_pr_templates
以管理和返回 PR 模板 - 实现
suggest_template
以将更改类型映射到模板
别担心做得完美——您将在本单元的后续学习中完善这些技能。
设计理念
与根据文件扩展名或严格模式对更改进行分类的传统系统不同,您的实现应:
- 向 Claude 提供原始 git 数据(差异、文件列表、统计数据)
- 让 Claude 分析实际代码更改
- 允许 Claude 做出智能模板建议
- 保持逻辑简单 - Claude 处理复杂性
MCP 理念:不要将复杂的逻辑构建到您的工具中,而是为 Claude 提供丰富的数据,让其智能做出决策。这使您的代码比传统基于规则的系统更简单、更灵活。
测试您的实现
1. 验证您的代码
运行验证脚本以检查您的实现
uv run python validate_starter.py
2. 运行单元测试
使用提供的测试套件测试您的实现
uv run pytest test_server.py -v
3. 使用 Claude Code 进行测试
直接在 Claude Code 中配置您的服务器
# Add the MCP server to Claude Code
claude mcp add pr-agent -- uv --directory /absolute/path/to/starter run server.py
# Verify the server is configured
claude mcp list
然后
- 在 Git 仓库中进行一些更改
- 询问 Claude:“您能分析我的更改并建议一个 PR 模板吗?”
- 观察 Claude 如何使用您的工具提供智能建议
常见首个错误:如果您收到“MCP 工具响应超出最大允许令牌数(25000)”,这是预料之中的!大型仓库会生成大量的差异。这是一个宝贵的学习时刻——请参阅“处理大型输出”部分以获取解决方案。
常见模式
工具实现模式
@mcp.tool()
async def tool_name(param1: str, param2: bool = True) -> str:
"""Tool description for Claude.
Args:
param1: Description of parameter
param2: Optional parameter with default
"""
# Your implementation
result = {"key": "value"}
return json.dumps(result)
错误处理
始终优雅地处理潜在错误
try:
result = subprocess.run(["git", "diff"], capture_output=True, text=True)
return json.dumps({"output": result.stdout})
except Exception as e:
return json.dumps({"error": str(e)})
错误处理:即使出现错误,您的工具也必须返回有效的 JSON。Claude 需要结构化数据来理解错误发生的原因,并向用户提供有用的响应。
处理大型输出(关键学习时刻!)
真实世界限制:MCP 工具的每个响应都有 25,000 个令牌的限制。大型 git diff 很容易超出此限制 10 倍甚至更多!这是生产 MCP 开发的关键一课。
在实现 analyze_file_changes
时,您可能会遇到此错误:
Error: MCP tool response (262521 tokens) exceeds maximum allowed tokens (25000)
为什么会发生这种情况:
- 单个文件更改可能有数千行
- 企业仓库通常有大量重构
- Git diff 默认包含完整上下文
- JSON 编码增加了开销
这教会我们一个重要原则:始终在设计工具时考虑输出限制。以下是解决方案:
@mcp.tool()
async def analyze_file_changes(base_branch: str = "main",
include_diff: bool = True,
max_diff_lines: int = 500) -> str:
"""Analyze file changes with smart output limiting.
Args:
base_branch: Branch to compare against
include_diff: Whether to include the actual diff
max_diff_lines: Maximum diff lines to include (default 500)
"""
try:
# Get the diff
result = subprocess.run(
["git", "diff", f"{base_branch}...HEAD"],
capture_output=True,
text=True
)
diff_output = result.stdout
diff_lines = diff_output.split('\n')
# Smart truncation if needed
if len(diff_lines) > max_diff_lines:
truncated_diff = '\n'.join(diff_lines[:max_diff_lines])
truncated_diff += f"\n\n... Output truncated. Showing {max_diff_lines} of {len(diff_lines)} lines ..."
diff_output = truncated_diff
# Get summary statistics
stats_result = subprocess.run(
["git", "diff", "--stat", f"{base_branch}...HEAD"],
capture_output=True,
text=True
)
return json.dumps({
"stats": stats_result.stdout,
"total_lines": len(diff_lines),
"diff": diff_output if include_diff else "Use include_diff=true to see diff",
"files_changed": self._get_changed_files(base_branch)
})
except Exception as e:
return json.dumps({"error": str(e)})
大型输出的最佳实践:
- 实现分页:将大型结果分成多个页面
- 添加过滤选项:允许用户请求特定文件或目录
- 首先提供摘要:在完整内容之前返回统计信息
- 使用渐进式披露:从高层信息开始,允许深入查看
- 设置合理的默认值:默认设置为适用于大多数情况的合理限制
工作目录注意事项
默认情况下,MCP 服务器在其安装目录中运行命令,而不是在 Claude 的当前工作目录中。这意味着您的 git 命令可能会分析错误的仓库!
为了解决这个问题,MCP 提供了 根目录——一种客户端通知服务器相关目录的方式。Claude Code 会自动将其工作目录作为根目录提供。
以下是您如何在工具中访问它的方法:
@mcp.tool()
async def analyze_file_changes(...):
# Get Claude's working directory from roots
context = mcp.get_context()
roots_result = await context.session.list_roots()
# Extract the path from the FileUrl object
working_dir = roots_result.roots[0].uri.path
# Use it for all git commands
result = subprocess.run(
["git", "diff", "--name-status"],
capture_output=True,
text=True,
cwd=working_dir # Run in Claude's directory!
)
这确保您的工具在 Claude 实际工作的仓库上运行,而不是 MCP 服务器的安装位置。
故障排除
导入错误:确保您已运行
uv sync
Git 错误:确保您在 Git 仓库中
无输出:MCP 服务器通过标准输入输出进行通信 - 使用 Claude Desktop 进行测试
JSON 错误:所有工具都必须返回有效的 JSON 字符串
令牌限制超出:大型差异会发生这种情况!按照上述方法实现输出限制
“响应过大”错误:添加
max_diff_lines
参数或设置include_diff=false
Git 命令在错误目录中运行:MCP 服务器默认在其安装目录中运行,而不是 Claude 的工作目录中。要解决此问题,请使用 MCP roots 访问 Claude 的当前目录
# Get Claude's working directory from roots context = mcp.get_context() roots_result = await context.session.list_roots() working_dir = roots_result.roots[0].uri.path # FileUrl object has .path property # Use it in subprocess calls subprocess.run(["git", "diff"], cwd=working_dir)
Claude Code 自动将其工作目录作为根目录提供,允许您的 MCP 服务器在正确的位置运行。
下一步
恭喜!您已经使用工具构建了您的第一个 MCP 服务器——这是单元 3 中所有后续内容的基础。
您在模块 1 中完成的工作:
- 创建了 MCP 工具,为 Claude 提供了结构化数据
- 实现了核心 MCP 理念——让 Claude 根据原始数据做出智能决策
- 构建了一个实用的 PR 代理,可以分析代码更改并建议模板
- 了解了实际限制——25,000 令牌限制以及如何处理它
- 建立了测试模式,包括验证脚本和单元测试
您可以重用的关键模式:
- 数据收集工具,用于从外部源获取信息
- 智能分析,其中 Claude 处理原始数据以做出决策
- 输出管理——截断大型响应同时保持其有用性
- 错误处理,返回结构化的 JSON 响应
- MCP 服务器开发的测试策略
下一步该怎么做:
- 查看解决方案(位于
/projects/unit3/build-mcp-server/solution/
)以了解不同的实现方法 - 将您的实现与提供的解决方案进行比较——解决问题没有单一的“正确”方法
- 彻底测试您的工具——尝试使用不同类型的代码更改来查看 Claude 如何适应
- 继续学习模块 2,您将在其中添加实时 webhook 功能并了解用于工作流标准化的 MCP 提示
模块 2 将直接基于您在此处创建的服务器,添加动态事件处理以补充您的静态文件分析工具!
故事仍在继续…
有了您的 PR 代理,CodeCraft Studios 的开发人员已经能够编写出更好的拉取请求。但是下周,您将面临一个新挑战:关键的 CI/CD 故障正在悄无声息地溜走。模块 2 将添加实时监控,以便在这些问题到达生产环境之前捕获它们。
额外资源
- MCP 文档
- FastMCP 指南
- 解决方案演练:
unit3/build-mcp-server-solution-walkthrough.md