- 状态(Status): Final
- 类型(Type): Standards Track
- 创建(Created): 2026-01-06
- 作者(Author(s)): John McBride (@jpmcb) —— 原始提案;Ola Hungerford (@olaservo) —— 当前引导者,SEP-1850 转换后
- 担保人(Sponsor): Ola Hungerford (@olaservo)
- PR: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2106
作者身份说明: 原始提案由 John McBride (@jpmcb) 在 PR #881 中撰写,早于 SEP-1850 基于 PR 的工作流。本文件将该提案转换为当前 SEP 格式,并由 Ola Hungerford (@olaservo) 引导,她还根据评审反馈修订了向后兼容性、安全影响和 SDK 迁移章节。原始文字和设计意图仍属 John;转换以来的实质性变更在本 PR 的提交历史中跟踪。
摘要
本 SEP 提议放宽对inputSchema、outputSchema 和 structuredContent 的限制,以更好地支持 JSON Schema 2020-12。具体而言:
inputSchema:保留type: "object"为必需(因为工具参数是对象),但允许任何额外的 JSON Schema 属性,以支持强大的校验组合(anyOf、oneOf、allOf等)outputSchema:完全支持 JSON Schema 2020-12,因为 MCP 服务器可能返回任何有效的 JSONstructuredContent:接受任何经outputSchema校验的 JSON 值
动机
当前的 MCP 规范以与完整 JSON Schema 支持相冲突的方式限制了工具 schema:-
inputSchema 限制:当前只允许
type、properties和required字段。这妨碍了使用anyOf、oneOf和allOf等组合关键字来实现复杂的对象校验模式。 -
outputSchema 限制:同样被限制为带
properties和required的type: "object",尽管规范声称支持”JSON Schema”。 -
structuredContent 限制:被定义为
{ [key: string]: unknown }(一个带字符串键的对象),这妨碍了返回数组——一种常见的 API 响应模式。
现实世界的影响
设想一个返回逐小时预报的天气 API 工具:structuredContent 必须是对象。开发者被迫将数组包裹在不必要的容器对象中:
- 为响应添加了不必要的嵌套
- 与常见的 REST API 模式相冲突
- 妨碍了对数组响应的直接 schema 校验
Schema 组合用例
当前的inputSchema 限制妨碍了合理的 schema 模式。有了本 SEP,工具可以在 type: "object" 旁使用组合关键字:
type、properties 和 required 字段。
规范
1. 放宽 inputSchema
当前定义:inputSchema 字段保留 type: "object" 要求(因为工具参数始终是对象),但现在接受任何额外的 JSON Schema 属性。这支持:
- 组合关键字:
anyOf、oneOf、allOf、not - 条件 schema:
if/then/else - 引用 schema:
$ref、$defs - 任何其他有效的 JSON Schema 2020-12 关键字
2. 放宽 outputSchema
当前定义:outputSchema 字段接受任何有效的 JSON Schema 2020-12 对象,支持校验数组、基本类型或复杂组合的 schema。与 inputSchema 不同,没有 type: "object" 要求,因为工具输出可以是任何有效的 JSON。
3. 放宽 structuredContent
当前定义:structuredContent 字段接受任何符合工具 outputSchema 的有效 JSON 值。这包括:
- 对象:
{ "key": "value" } - 数组:
[1, 2, 3]或[{ "id": "abc" }, { "id": "xyz" }] - 基本类型:
"string"、42、true、null
4. 文档更新
更新docs/specification/draft/server/tools.mdx:
- 移除关于
structuredContent”作为 JSON 对象返回”的陈述 - 澄清
structuredContent可以是符合outputSchema的任何 JSON 值 - 添加演示数组响应的示例
5. 示例
返回对象数组的工具:
带组合 schema 的工具:
理由
为何不只是允许数组?
虽然我们可以简单地扩展structuredContent 以允许数组,但这将是一个不完整的解决方案。根本原因是 schema 类型被人为地限制为 type: "object"。通过允许任何有效的 JSON Schema,我们:
- 支持 JSON Schema 2020-12 的全部能力
- 与规范对 JSON Schema 支持的声称对齐
- 提供一致、有原则的方式,而非零敲碎打的修补
为何不要求封装对象?
曾考虑要求将数组包裹在对象中(例如{ "items": [...] }),但被否决,因为:
- 它为响应增加了不必要的复杂性
- 它与常见的 API 设计模式相冲突
- 它妨碍了对实际响应结构的直接 schema 校验
- JSON Schema 已经优雅地处理数组校验
现实世界的 API 模式
许多生产 API 直接返回数组:- GitHub Events API:返回事件对象数组
- AccuWeather Search API:返回位置匹配数组
- REST 集合端点:标准的
GET /users返回[{...}, {...}]
与 JSON Schema 2020-12 对齐
JSON Schema 2020-12 为 schema 组合和校验提供了强大的特性。通过移除人为限制,MCP 与行业标准对齐(OpenAPI 3.1 使用 JSON Schema 2020-12),并使开发者能够利用既有的 JSON Schema 知识和工具。SDK 生态证据
当前限制造成的摩擦并非理论上的。FastMCP,最流行的 MCP Python SDK 之一,已实现了大量变通办法:-
显式错误消息承认这一局限:
-
自动封装基础设施增加了复杂性:
- 一个
_WrappedResultdataclass 封装非对象返回 - 一个自定义的
x-fastmcp-wrap-result扩展支持客户端侧解封装 - SDK 和客户端都需要匹配的封装/解封装逻辑
- 一个
-
这些变通办法已导致真实缺陷:
- Issue #2455:没有
type: object的$refschema 破坏了服务器上的所有工具 - Issue #2421:意外的
{"result": ...}封装令用户困惑
- Issue #2455:没有
OpenAPI 先例
OpenAPI 规范经历了类似的演进。OpenAPI 3.0 使用 JSON Schema 的一个”扩展子集”,带有自定义限制(例如要求nullable: true 而非允许 "null" 作为一种类型)。
OpenAPI 3.1 作出了完全与 JSON Schema 2020-12 对齐的战略决定,接受破坏性变更以消除摩擦。结果:更好的工具兼容性和更少的生态困惑。
MCP 可以从 OpenAPI 的经验中学习,而非在数年间重复相同的演进。
向后兼容性
此变更线路格式向后兼容,但根据版本不匹配的方向存在细微差别。兼容性矩阵
不对称性:利用数组或基本类型
structuredContent(或 inputSchema 中组合关键字)的新服务器,不能假定旧客户端会接受该响应。针对旧线路格式编写的旧客户端可能拒绝非 JSON 对象的 structuredContent,或无法校验包含 type/properties/required 之外关键字的 inputSchema。
为与较旧客户端保持互操作,使用数组或基本类型 structuredContent 的服务器还必须(MUST)发出一个包含序列化 JSON 的 TextContent 块(如工具规范中已建议的)。不理解非对象 structuredContent 的客户端可以回退到文本内容。
TypeScript / SDK 迁移
将structuredContent 字段类型从 { [key: string]: unknown } 拓宽为 unknown,对于类型化的消费者而言是一个源码破坏性变更,即便线路格式不变。诸如以下代码:
unknown 进行属性访问:
- 在 SDK 发布说明中记录该迁移。
- 在符合工效学之处,提供类型化辅助工具(例如对工具
outputSchema的泛型),使消费者无需手写收窄守卫。
迁移路径
- 服务器:无需迁移即可像以前一样工作。要使用数组或基本类型
structuredContent,还需发出一个序列化的TextContent回退。 - 客户端:旧客户端继续针对仅对象服务器工作。要消费新的灵活性,应在
structuredContent中接受任何 JSON 值,并在存在outputSchema时对照校验。 - SDK:更新生成的类型以反映新 schema(
structuredContent为unknown,开放式的inputSchema/outputSchema),并在发布说明中指出源码破坏性的类型变更。
安全影响
JSON Schema 校验已经处理类型检查、值约束和必填字段校验,实现**必须(MUST)**继续对照声明的 schema 校验所有输入和输出。允许完整的 JSON Schema 2020-12 词汇表带来两个值得明确指导的方面。$ref 解引用(SSRF 与 Fetch-DoS)
JSON Schema 2020-12 允许 $ref 指向绝对 URI,而不仅是同一文档中的 JSON 指针。天真地对遇到的每个 $ref 发起 HTTP 请求来解析的实现,给了攻击者一个服务器端请求伪造/获取放大的原语:恶意的工具定义可以致使宿主获取任意 URL,包括内部元数据端点或旨在耗尽资源的大型载荷。
为缓解这一点:
- 实现**不得(MUST NOT)**自动解引用解析为网络 URI 的
$ref值(即任何不是同文档 JSON 指针,如#/$defs/Foo或内部$anchor的东西)。 - 此处”自动”意为”作为正常校验或 schema 处理的一部分,无需显式的操作员动作”。实现**可以(MAY)提供一个获取非本地
$ref的选择加入模式,但它必须默认禁用,并应当(SHOULD)**强制执行主机允许列表(或至少拒绝环回、链路本地和私有网络地址)、应用超时和大小限制,并记录解引用的 URI。 - 因未解析的外部
$ref而校验失败的 schema **应当(SHOULD)**被拒绝,而非默默地被当作宽松处理。
组合关键字的资源使用
组合关键字(anyOf、oneOf、allOf、if/then/else)和 $defs 支持有表达力的 schema,但病态组合校验起来可能代价高昂。实现**应当(SHOULD)**应用合理的界限——例如最大 schema 深度、子 schema 总数的上限,或每次校验的时间预算——以防止恶意的工具定义充当针对校验器的 CPU DoS 向量。
参考实现
TypeScript SDK
一个演示放宽后类型限制的参考实现:- 分支:olaservo/typescript-sdk@sep-834-v1x
- npm:
@olaservo/mcp-sdk@1.25.2-sep834.4 - 关键变更:
inputSchema:保留type: "object"但允许任何额外的 JSON Schema 属性(如oneOf/anyOf组合)outputSchema:任何有效的 JSON Schema 对象(数组、基本类型、对象、组合)structuredContent:任何 JSON 值(对象、数组或基本类型)- McpServer 高层 API 更新以支持数组和基本类型 outputSchema
Everything Server 演示工具
向everything 服务器添加了三个演示工具,展示 SEP-2106 能力:
- 分支:olaservo/servers@sep-834-json-schema-2020-12
- npm:
@olaservo/mcp-server-everything-sep834@1.1.0-sep834.1 - 工具:
get-weather-forecast:直接在structuredContent中返回逐小时预报的原始数组- 与 SEP-2106 动机章节中的确切示例匹配
outputSchema:z.array(HourlyForecastSchema)—— 根为数组类型structuredContent:[{hour, temp, conditions}, ...]—— 直接数组
find-by-id-or-name:演示灵活的输入模式(接受id或name)get-count:直接在structuredContent中返回原始数字(不封装在对象中)outputSchema:z.number()—— 根为基本类型structuredContent:42—— 直接基本类型
相关链接
- 原始 PR:https://github.com/modelcontextprotocol/modelcontextprotocol/pull/881
- 相关 issue:https://github.com/modelcontextprotocol/modelcontextprotocol/issues/834
outputSchema类型限制不一致:https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1906- TypeScript SDK schema 类型:https://github.com/modelcontextprotocol/typescript-sdk/issues/1149
- SEP-2200(澄清工具结果内容与模型可见性):https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2200
实现指南
SDK 实现将需要:- 更新
inputSchema类型,保留type: "object"但允许任何额外的 JSON Schema 属性 - 更新
outputSchema类型,允许任何有效的 JSON Schema(移除type: "object"约束) - 更新
structuredContent类型,接受任何有效的 JSON 值 - 相应地更新 JSON Schema 定义