自建 MCP server 用 pydantic 生成 inputSchema,嵌套模型被展开成 $defs 加 $ref,Claude Desktop 0.9 能连上,tools/list 也正常,真正调用时报 -32602,原文 Invalid params: unsupported schema keyword $defs。

一开始怀疑是「嵌套对象越多,$ref 层级越深」,查了一圈,方向不对。

把日志和配置对完,能解释这个现象的基本就这几处。部分客户端只认扁平 schema,不支持引用。还有一种是pydantic v2 生成 schema 时默认拆分定义。

另外,anyOf 在旧客户端上也有兼容问题。

上来先把 tools/list 的原始返回保存下来检查

python -c "import json;print(json.dumps(json.load(open('tools.json'))['tools'][0]['inputSchema'])[:300])"

再往下用 ref_template 让 pydantic 直接内联定义

python -c "from pydantic import BaseModel;print(BaseModel.model_json_schema(ref_template='{model}'))"

接着用 jsonref 展开所有引用再下发

python -c "import jsonref,json;print(json.dumps(jsonref.replace_refs(json.load(open('schema.json'))),ensure_ascii=False)[:200])"

展开后实际调用一次工具确认可用

python mcp_call.py --tool search --args '{"q":"退款"}'

报错是间歇性的,我蹲守了半小时才抓到一次完整现场。

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

恢复的判定其实很直接。客户端调用返回正常结果,inputSchema 里不再出现 $defs 与 $ref,嵌套参数也能正确传递。

MCP 的 schema 兼容性取决于客户端实现,服务端主动内联定义,比要求用户升级客户端现实。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189