生产级MCP服务器测试与调试指南
详细阐述MCP服务器在生产环境中容易失败的各类场景(工具返回错误、API超时、租户凭证过期、模型选错工具等),并给出完整的测试策略,包括分层测试、租户隔离和可观测性建设。
完整中文译文
问题:本地 MCP 演示与生产环境的差异
一个在本地演示中运行完美的 MCP 服务器,在生产环境中可能彻底失效。工具返回错误数据、外部 API 超时、阻塞函数冻结事件循环、租户的过期凭证导致重复失败,以及模型本身可能选错工具或生成无效参数。
除非从第一天起就为 MCP 应用构建测试和可观测性,否则这些故障几乎无法诊断。
应该测试什么?
MCP 应用有多个运动部件:
User → AI Client → MCP Server → Tool → External API/Database/Service
故障可能发生在任何一层。完整的测试策略应覆盖:
- 外部集成
- 认证与授权
- 日志、指标和追踪
仅测试 Python 函数是不够的。你需要验证从客户端到外部服务的完整请求行为。
1. 从单元测试开始
单元测试一次验证应用程序的一个小部分。假设你的 MCP 服务器暴露了一个天气工具:

@mcp.tool()
def get_weather(city: str):
if not city.strip():
raise ValueError("City is required")
return weather_client.get(city)
一个基础测试验证空输入被拒绝:
import pytest
def test_get_weather_rejects_empty_city():
with pytest.raises(ValueError):
get_weather("")
另一个测试验证预期响应:
def test_get_weather_returns_result(mocker):
mocker.patch("weather_client.get", return_value={"city": "Toronto", "temperature": 24})
result = get_weather("Toronto")
assert result["city"] == "Toronto"
assert result["temperature"] == 24
有用的单元测试覆盖:有效输入、缺失输入、无效值、权限失败、预期输出结构、错误响应和边界条件。
关键规则:保持工具小而专注。窄职能的工具比执行多个不相关操作的工具更容易测试。
2. Mock 外部服务
MCP 工具通常依赖 API、数据库、云平台和第三方服务。在每次测试中都调用真实服务会使测试套件变慢、昂贵、不可靠、难以复现,并且依赖互联网访问。
相反,应该 mock 外部依赖:
def test_customer_lookup(mocker):
mocker.patch("customer_api.get_customer", return_value={"id": "cust-104", "status": "active"})
result = get_customer("cust-104")
assert result["status"] == "active"
你还应该测试失败响应:
def test_customer_api_timeout(mocker):
mocker.patch("customer_api.get_customer", side_effect=TimeoutError())
result = get_customer("cust-104")
assert result["error"] == "service_unavailable"
不要只测试成功响应。模拟超时、无效凭证、速率限制、空响应、格式错误的 JSON、网络故障和服务器错误。生产系统以多种方式失败——你的测试应该反映这一点。
3. 添加集成测试
单元测试确认单个函数工作正常。集成测试确认多个组件协同工作。
对于 MCP 应用,集成测试验证完整流程:客户端请求 → MCP 服务器接收请求 → 工具被发现 → 工具执行 → 返回结构化响应。
一个有用的集成测试检查:
- 服务器是否正确启动
- 预期工具是否已注册
- 参数是否被正确解析
- 响应是否符合 MCP 协议模式
- 错误是否作为结构化 MCP 错误返回
4. 测试工具选择和无效参数
在生产环境中,模型可能选错工具或生成无效参数。你无法从服务器端完全控制这一点,但可以让你的服务器更加健壮:
- 在工具边界验证所有输入
- 返回模型可以恢复的清晰、结构化错误
- 记录哪个工具被调用以及使用了什么参数
5. 添加可观测性:日志、指标和追踪
没有可观测性的情况下调试 MCP 故障是盲目的。添加:
- 每一次工具调用的结构化日志:时间戳、工具名称、参数、持续时间、结果/错误
- 工具调用频率、错误率和延迟的指标
- 跨越客户端 → 服务器 → 工具 → 外部服务路径的追踪
当租户的过期凭证导致重复失败时,你需要日志来显示是哪个租户和哪个工具失败了。当阻塞函数冻结事件循环时,你需要指标来显示延迟峰值。
这如何应用于 Claude Code
Claude Code 使用 MCP 服务器来扩展其能力。如果你正在为 Claude Code 构建 MCP 服务器——无论是内部工具还是公共服务器——相同的测试原则都适用。
在你信任 Claude Code 工作流中的 MCP 服务器之前:
- 使用有效、无效和边界输入对每个工具进行单元测试
- Mock 外部服务使测试快速可靠
- 集成测试完整流程以捕获协议级别的问题
- 添加可观测性以便在故障发生时进行调试
如果你在为 Claude Code 构建 MCP 服务器,从覆盖这三层的测试套件开始:
# Run unit tests for tool logic
pytest tests/unit/
# Run integration tests against the MCP server
pytest tests/integration/
向每个工具添加结构化日志:
import logging
logger = logging.getLogger("mcp.tool")
@mcp.tool()
def get_customer(customer_id: str):
logger.info(f"get_customer called", extra={"customer_id": customer_id})
# ...
这是你在生产环境中调试 MCP 服务器所需的最低要求。
Originally published on gentic.news