ARTICLE / 安全

你的 MCP 客户端在服务端出错时会怎样:一个故意使坏的开源测试服务器

MCP 生态里的大部分测试工具方向是反的:MCP Inspector、MCP Playground 这些客户端是用来测试你在写的 MCP 服务器的——浏览工具、发起调用、看 JSON-RPC 日志,被测对象是服务器。但真正让网关和客户端开发者夜里睡不着觉的问题是另一个:当服务器不按规矩来,你的客户端会做什么? 一个返回畸形载荷的服务器、一次传输层错误、一个藏在成功响应里的失败结果——客户端是优雅降级、重试、还是把错误当正常内容塞给用户?

2026 年 10 月,一家叫 Cakewalk 的安全团队把他们内部用的答案开源了:MCP Test Kitchen,一个故意使坏的 MCP 服务器,MIT 协议,带托管版和 Docker 自部署。他们的动机很直接:自建 MCP 网关时拿一流服务器测试,一开始一切正常,直到 elicitation 机制在他们脚下被重新设计、客户端支持参差不齐,而测试用的服务器既不提供 resources 也不提供 prompts——规矩的服务器不会按请求使坏,也暴露不出它没有的东西。

六种故障场景,打在协议栈的不同层

Test Kitchen 的价值在于故障是分层的,每种层断掉客户端的方式不同。HTTP 传输错误——故障位于 MCP 之下,可配置连续状态码序列打 successive 请求。JSON-RPC 错误信封——HTTP 200 但响应体里是错误对象,打在你解析响应的地方。Tool error(isError)——最隐蔽的一种:失败藏在一次成功的响应里面,传输层全程 200,任何只看状态码的监控都抓不到。

三种场景之外还有 elicitation(服务器反向向客户端要输入)、多轮往返请求(MRTR,C# SDK v2 兼容场景)、带可配置延迟的基线。JSON-RPC 和工具错误都可以指定只在第 N 次调用时失败——第一次成功、第二次失败,这是固定 mock 表达不了的情况:用户已经被建立信任之后才爆的雷,才是贵的雷。

使用方式对客户端零侵入:任何接受 URL 加 Authorization 头的客户端(Cursor、Claude Desktop 或自研网关)直接把端点贴进 MCP 配置就行,不需要 wrapper、子进程或代码改动。控制台按行记录每个请求:时间、方法、耗时、状态、活跃场景、协议版本——服务器同时应答 2025-11-25 和 2026-07-28 两个协议修订版,并记录每个请求声明的是哪个版本。

看客户端做了什么,而不是看日志说了什么

官方教程里有个值得记住的测试方法论:日志告诉你服务器发了什么,但它不能告诉你客户端接着做了什么——而后者才是被测对象。你配置了第二次调用带 isError,自己当然知道;真正的问题是失败的结果有没有被当成内容传给用户。如果有,这是你代码里的结果处理缺陷,两行日志状态码都是 200,没有任何盯着状态码的东西能抓到它。

边界也要说清:这个东西不测服务器;它不告诉你客户端是否正确(那是官方 conformance suite 的事,两者不重叠);传输是无状态的,跨连接的有状态路径不在范围内。作者自己也很诚实:“一个使坏的服务器就几百行代码,你愿意自己写当然更好——你用我们的,省的是维护这些故障场景的功夫,以及日志告诉你客户端实际发了什么。”

对做 MCP 网关、客户端 SDK 或企业 MCP 接入层的团队,这类故障注入工具值得进 CI:elicitation 重设计这种事会一再发生,与其等真实服务器花样翻新地坑你,不如在每次发版前把六种坏法全过一遍。

(事实依据 Cakewalk 官方产品页、教程页及 Hacker News 发布帖,均于 2026-10-16 采集核验;项目开源地址 github.com/cakewalk-security/cakewalk-mcp-test-kitchen。)

本文面向授权安全研究与防御建设,未经授权对任何系统实施文中技术属违法行为。