这类问题我又碰上了一次。自己写的 MCP server 返回 {"content":[{"type":"text","text":{"ok":true}}]},Claude Desktop 报 content.text must be a string,连接直接断开。

第一反应是「isError 没设,客户端把业务错误当协议错误」,验证下来不成立。

排查方向其实有限,先把可能性排一排。text 字段塞了对象,协议要求是字符串;没有统一序列化,不同工具返回结构不一致;返回了多个 content 但顺序不稳定。

上来先打印服务端实际返回的 JSON

python -c "import json;print(json.dumps({'content':[{'type':'text','text':json.dumps({'ok':True})}]}))"

接着统一用 json.dumps 序列化 text

python -c "import json;print(json.loads(json.dumps({'ok':True})))"

给失败结果加 isError 标记

python -c "print({'content':[{'type':'text','text':'工单不存在'}],'isError':True})"

剩下的就是用官方 inspector 跑一次握手

npx @modelcontextprotocol/inspector node server.js

白天有业务在跑,能验证的部分都压到了晚上做。

当时还开着另一个排查窗口,两边日志对照着看才定位到。

改完先别撤,确认这几项。inspector 里 tools/call 返回结构合法,Claude Desktop 能正常展示结果,连接不再断开,错误分支也能看到提示文案。

MCP 的 content 是给人看和给模型看的两层结构,text 只能是字符串,结构化数据要自己序列化进去。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189