MCP 服务器测试的三层体系:从 Inspector 到协议一致性
一句话结论:MCP 服务器测试要按三层搭——单元测试管工具逻辑、 MCP Inspector 管协议交互、 conformance 校验管协议一致性,只在 Inspector 里手动点一遍就宣布”测完了”,是上线后翻车的主要原因。
很多人写完 MCP 服务器的验证方式是:接到 Claude Desktop 里,让模型调一下工具,跑通了就发布。这个流程的问题在于,它验证的是”理想路径在理想客户端下能跑”,而真实世界里模型会传错参数、传输层会断流、版本会升级。三层体系各管一段,缺一层就有一类 bug 逃逸。
第一层:单元测试,工具逻辑的快速反馈
把每个工具函数当普通函数测,不经过协议层,反馈最快。 Python 用 pytest + 模拟上下文:
@pytest.mark.asyncio
async def test_search_returns_text_content():
mock_ctx = MagicMock()
mock_ctx.call_tool = AsyncMock(return_value=[{"id": 1}])
result = await search_handler(mock_ctx, query="test", limit=5)
assert result["content"][0]["type"] == "text"
mock_ctx.call_tool.assert_called_once_with("database", {"query": "test", "limit": 5})
TypeScript 侧可以用 SDK 的 InMemoryTransport 建立内存中的客户端/服务端对,不启动进程就能跑完整协议往返。
第二层:MCP Inspector,协议交互的可视化验证
# stdio 服务器
npx @modelcontextprotocol/inspector npx your-mcp-server
# Streamable HTTP 服务器
npx @modelcontextprotocol/inspector --url http://localhost:3000/mcp
- 目录完整性:确认工具/资源/提示词全部列出,名称无空格和特殊字符(多数客户端会直接拒绝)。
- Schema 校验:重点查每个参数有没有 description——缺了它,模型只能靠猜传参,这是幻觉参数的头号来源。
- 真实调用:带自定义参数调用每个工具,检查原始响应结构和错误分支的表现。
- 消息流观察:盯着 JSON-RPC 消息流跑一遍 initialize 握手,确认能力协商正常。
一条会救命的规则:stdio 服务器日志必须写 stderr,写 stdout 会污染 JSON-RPC 数据流,客户端直接解析失败。
--cli --method tools/list --format json)可以接进 CI 做冒烟检查,这才是把它用满的方式。第三层:协议一致性与 CI 门禁
官方提供了 conformance 框架,连上运行中的服务器录制协议流量并按 wire schema 校验,CI 里应固定版本号运行:
npx @modelcontextprotocol/conformance server --url http://127.0.0.1:3000/mcp --requirements 2026-07-28
用冻结的版本号(rolling suite 会在发布后混入新场景,回答的是另一个问题)。社区还有 MCPJam 这类平台,能在 16 种客户端配置和多个 LLM 上跑评测,把”模型会不会选错工具、传错参数”也纳入回归。 CI 门禁的最小集:schema 契约 diff 、 handler 单测、一次传输冒烟、日志密钥扫描。
传输层差异是集成测试的另一个重点,stdio 与 Streamable HTTP 的故障面完全不同,选型对比见 MCP 传输方式对比。服务器搭好之后先测再接客户端,搭建流程参考 MCP Server 自己搭建教程;跑起来之后连不上的排查手册在 MCP 调试常见问题;对外服务前还要过 MCP 安全风险清单,远程部署的授权流程见 远程 MCP 服务器 OAuth 授权。
只用 MCP Inspector 够吗?
工具描述(description)真有那么重要?
CI 里跑 MCP 测试要注意什么?
参考来源:modelcontextprotocol.io 官方 Inspector 文档、 MCP conformance 官方框架说明、 MCPJam 官方文档。









评论 (0)