先记住这个答案
MCP 2025-11-25 的 Tool 定义要求 inputSchema 存在且根 type 为 object,工具调用的 arguments 以命名参数对象传递。这样客户端能围绕字段名展示、生成和检查输入,而不是猜位置参数。客户端可在提交前检查工具声明与实参,服务端仍必须验证所有工具输入并执行业务授权。还要区分协议外层 CallToolRequest 的结构校验与具体工具参数校验:前者失败属于协议问题,后者可以作为 isError 工具结果提供可修正反馈。
- inputSchema 是参数契约,不是一次调用的实际值
- 根对象与内部字段分别定义类型约束
- Schema 方言、报文格式和业务规则分层验证
对象根类型便于为参数建立稳定名称
搜索工具可以把查询词与返回上限分别命名,客户端表单和模型都能看到同一组字段。若直接把根类型改成数组,即使某个 JSON Schema 校验器认为这份 Schema 合法,也不等于它符合 MCP 的 Tool 输入声明结构。
下面是工具定义中的一个条目,可以出现在 tools/list 的 tools 数组里。它不是 tools/call 请求;调用时需要把实际值放入 params.arguments,不能把整份 inputSchema 原封不动作为实际参数传给搜索函数。
{
"name": "search_notes",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string", "minLength": 1 },
"limit": { "type": "integer", "minimum": 1, "maximum": 10 }
},
"required": ["query"],
"additionalProperties": false
}
}query 必填,limit 可省略但提供时必须为范围内整数。Schema 没有自动设置 limit 默认值,也没有证明调用者可读取任何笔记;这两项仍由工具实现明确处理。
无参数也需要明确接受的对象范围
没有业务参数的工具仍应给出对象 Schema。type: object 配合 additionalProperties: false 可以表达只接受空对象;只有 type: object 则仍允许附带属性,不能把两种声明说成完全等价。null 或省略 inputSchema 不符合这里的工具定义。
若 arguments 省略,服务端如何将它归一化并检查无参数工具,需要和 SDK 行为保持一致;不要让一种入口使用空对象、另一种入口把 undefined 直接传进业务函数。测试应同时覆盖空对象、额外字段、缺失必填值和错误类型。
支持 JSON Schema 需要说清是哪一种方言
这一版本未显式声明 $schema 时默认 2020-12;显式使用其他方言时需要实现确实支持。若旧校验器忽略它不认识的关键字,参数可能错误通过,客户端不能把这种降级包装成所有声明约束均已执行。
服务端发现 query 类型错误或 limit 越界时,可返回带 isError 的工具结果并说明字段问题;而整个 params 缺少工具名,则是调用报文结构错误。两者都应在副作用前发现,但不能单靠“发生在执行前”来选择错误通道。授权与当前业务状态还需单独校验。
容易答错的地方
- Schema 本身是合法 JSON 就能作为 MCP 工具声明
- 合法 JSON 只通过语法层;还要符合工具定义、所声明的 JSON Schema 方言和参数规则,三者不能互相替代。
- 工具参数校验发生在执行前,所以必须用协议错误
- 错误层次由违反的是报文契约还是具体工具输入决定,而不是时间先后;工具输入校验反馈可以走 isError 结果通道帮助修正。
面试官还会怎么问?
客户端已经检查过参数,服务端为什么还要检查?
其他客户端、直接调用入口和过期缓存都可能绕开本地检查。服务端必须在自己的信任边界验证输入,不能依赖某个前端页面永远存在。
inputSchema 通过后能否直接获得资源访问权限?
不能,Schema 主要约束数据形状和部分取值,用户身份、资源归属和当前状态仍需要服务端用可信上下文判定,不能由参数自报证明。
如何处理不支持的 Schema 方言?
应返回明确的不支持信息或禁用依赖该契约的调用,不能静默按另一个方言校验。若提供兼容转换,必须测试约束含义没有因此丢失。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。