Documentation Index
Fetch the complete documentation index at: https://mcp.zhcndoc.com/llms.txt
Use this file to discover all available pages before exploring further.
草案标准轨道
摘要
本 SEP 提议放宽对inputSchema、outputSchema 和 structuredContent 的限制,以更好地支持 JSON Schema 2020-12。具体来说:
inputSchema:继续要求type: "object"(因为工具参数是对象),但允许任何额外的 JSON Schema 属性,以支持强大的验证组合(anyOf、oneOf、allOf等)outputSchema:由于 MCP 服务器可能返回任何有效 JSON,因此全面支持 JSON Schema 2020-12structuredContent:接受由outputSchema验证的任何 JSON 值
动机
当前的 MCP 规范以几种方式限制了工具 schema,与完整的 JSON Schema 支持相冲突:-
inputSchema 限制:当前只允许
type、properties和required字段。这使得无法使用anyOf、oneOf和allOf等组合关键字来实现复杂的对象验证模式。 -
outputSchema 限制:同样限制为仅能使用
type: "object"、properties和required,尽管规范声称支持 “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 和客户端都需要匹配的包裹/解包逻辑
-
实际 bug 已经由这些变通方案引发:
- Issue #2455:没有
type: object的$refschemas 导致服务器上的所有工具失效 - Issue #2421:意外的
{"result": ...}包装让用户感到困惑
- Issue #2455:没有
OpenAPI 先例
OpenAPI 规范经历过类似的演进。OpenAPI 3.0 使用的是 JSON Schema 的“扩展子集”,带有自定义限制(例如要求使用nullable: true,而不是允许将 "null" 作为类型)。
OpenAPI 3.1 做出了战略性决定,全面对齐 JSON Schema 2020-12,接受破坏性变更以消除这些摩擦。结果是:更好的工具兼容性,以及更少的生态混淆。
| OpenAPI 的问题 | MCP 的对应问题 |
|---|---|
type 必须是字符串,而不是数组 | inputSchema 只允许特定字段 |
| 无法使用标准的 null 处理 | schema 中不能使用 oneOf/anyOf |
自定义 nullable 关键字 | 仅限对象的 structuredContent |
| 导致工具链混乱 | 导致 SDK 变通方案 |
向后兼容性
此更改在线格式上向后兼容,但根据版本不匹配的方向不同,存在一些细微差别。兼容性矩阵
| 新客户端(SEP 后) | 旧客户端(SEP 前) | |
|---|---|---|
| 新服务器(SEP 后) | 完全兼容。 | 仅当服务器返回对象类型的 structuredContent 时兼容。structuredContent 中的数组/原始值可能会导致失败。 |
| 旧服务器(SEP 前) | 完全兼容。现有的仅对象模式仍然有效。 | 不变。 |
structuredContent(或 inputSchema 中的组合关键字)的新服务器,不能假设旧客户端会接受该响应。按照先前线格式编写的旧客户端可能会拒绝不是 JSON 对象的 structuredContent,或者无法验证包含 type/properties/required 之外关键字的 inputSchema。
为了与旧客户端保持互操作性,使用数组或原始值 structuredContent 的服务器还必须输出一个包含序列化 JSON 的 TextContent 块(这也正是工具规范中已经建议的做法)。不理解非对象 structuredContent 的客户端可以回退到文本内容。
TypeScript / SDK 迁移
将structuredContent 字段类型从 { [key: string]: unknown } 扩展为 unknown 对于类型化消费者来说是一个源码破坏性变更,即使线格式本身没有变化。如下代码:
unknown 进行属性访问:
- 在 SDK 发布说明中记录此次迁移。
- 在合适且便于使用的情况下,提供类型化辅助工具(例如基于某个工具
outputSchema的泛型),以便消费者无需手写缩小类型保护。
迁移路径
- 服务器:无需迁移即可继续按原方式工作。若要使用数组或原始值
structuredContent,还应同时输出序列化的TextContent作为回退。 - 客户端:旧客户端在仅对象的服务器上仍可正常工作。要使用新的灵活性,请接受
structuredContent中的任意 JSON 值,并在存在outputSchema时据此进行验证。 - SDK:更新生成的类型以反映新模式(
structuredContent使用unknown,inputSchema/outputSchema为开放式),并在发布说明中指出这一源码破坏性类型变更。
安全影响
JSON Schema 验证已经负责处理类型检查、值约束以及必填字段验证,且实现必须继续根据声明的 schema 验证所有输入和输出。允许完整的 JSON Schema 2020-12 词汇表会暴露出两个需要明确说明的方面。$ref 解引用(SSRF 与 Fetch-DoS)
JSON Schema 2020-12 允许 $ref 指向绝对 URI,而不仅仅是同一文档内的 JSON Pointer。一个天真的实现如果对遇到的每个 $ref 都通过发起 HTTP 请求来解析,就会给攻击者提供服务端请求伪造 / 抓取放大量的原语:恶意的工具定义可以迫使宿主抓取任意 URL,包括内部元数据端点或用于耗尽资源的大型负载。
为缓解这一点:
- 实现不得自动解引用那些解析到网络 URI 的
$ref值(即任何不是同文档 JSON Pointer 的内容,例如#/$defs/Foo或内部$anchor)。 - 这里的“自动”是指“作为正常验证或 schema 处理的一部分,而无需显式的操作员动作”。实现可以提供一个可选开启的模式,用于抓取非本地
$ref,但该模式必须默认关闭,并且应当强制执行主机白名单(或至少拒绝回环、链路本地和私有网络地址),应用超时和大小限制,并记录被解引用的 URI。 - 若由于未解析的外部
$ref导致验证失败,应当拒绝该 schema,而不是悄悄将其视为宽松模式。
组合关键字的资源使用
组合关键字(anyOf、oneOf、allOf、if/then/else)和 $defs 能够表达丰富的 schema,但病态组合在验证时可能代价高昂。实现应当施加合理的边界——例如最大 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 的 Motivation 部分中的精确示例一致
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 定义