最终版标准轨道
| Field | Value |
|---|---|
| SEP | 2243 |
| Title | 用于可流式 HTTP 传输的 HTTP 头标准化 |
| Status | 最终版 |
| Type | 标准轨道 |
| Created | 2026-02-04 |
| Author(s) | MCP Transports 工作组 |
| Sponsor | 无 |
| PR | #2243 |
摘要
本 SEP 提议为可流式 HTTP 传输在标准 HTTP 头位置中暴露关键路由和上下文信息。通过将 JSON-RPC 载荷中的关键字段镜像到 HTTP 头中,负载均衡器、代理和可观测性工具等网络中介可以在无需深度包检测的情况下对 MCP 流量进行路由和处理,从而降低延迟和计算开销。动机
当前通过 HTTP 实现的 MCP 将所有路由信息都隐藏在 JSON-RPC 载荷中。这给网络基础设施带来了摩擦:- 负载均衡器 必须终止 TLS 并解析整个 JSON 正文才能提取路由信息(例如区域、工具名称)
- 代理和网关 无法在不进行深度包检测的情况下做出路由决策
- 可观测性工具 对 MCP 流量模式的可见性有限
- 限流器和 WAF 无法基于 MCP 特定字段应用策略
规范
标准头
可流式 HTTP 传输将要求 POST 请求包含以下从请求体镜像而来的头:| Header Name | Source Field | Required For |
|---|---|---|
Mcp-Method | method | 所有请求和通知 |
Mcp-Name | params.name or params.uri | tools/call、resources/read、prompts/get 请求 |
理由:该要求可防止当网络中的不同组件依赖不同事实来源时可能出现的安全漏洞和错误条件。例如,负载均衡器或网关可能使用头值做路由决策,而 MCP 服务器使用正文值执行操作。该要求适用于任何处理消息正文的网络中介,以及 MCP 服务器本身。
实施说明:在验证整数参数值时,服务器 SHOULD 按数值而不是按字符串比较头值和正文值(例如,大小写敏感性:头名称(在 RFC 9110 中称为“字段名”)不区分大小写。客户端和服务器 MUST 对头名称使用不区分大小写的比较。42.0和42被视为相等)。
示例:tools/call 请求
示例:resources/read 请求
示例:prompts/get 请求
示例:其他请求方法
对于不涉及 tools、resources 或 prompts 的请求,只需要Mcp-Method 头:
示例:通知
通知同样需要Mcp-Method 头:
来自工具参数的自定义头
MCP 服务器 MAY 使用工具的inputSchema 中参数 schema 里的 x-mcp-header 扩展属性,将特定工具参数指定为镜像到 HTTP 头中。
客户端要求:虽然 x-mcp-header 的使用对服务器而言是可选的,但客户端 MUST 支持此功能。当服务器的工具定义包含 x-mcp-header 注解时,符合规范的客户端 MUST 按照本文档所述,将指定参数值镜像到 HTTP 头中。
Schema 扩展
x-mcp-header 属性指定用于构造头名称 Mcp-Param-{name} 的名称部分。
x-mcp-header 值的约束:
- MUST NOT be empty
- MUST match HTTP field-name token syntax (
1*tchar, RFC 9110 Section 5.1) - MUST NOT contain control characters, including carriage return (CR,
\r) or line feed (LF,\n) - MUST be case-insensitively unique among all
x-mcp-headervalues in theinputSchema - MUST only be applied to parameters with primitive types (integer, string, boolean). Parameters with type
numberare not permitted. Integer values MUST be within the safe range for JavaScript (−2^53+1 to 2^53−1) - MAY be applied to properties at any nesting depth within the
inputSchema, not only top-level properties
x-mcp-header 值违反这些约束的工具定义。拒绝意味着客户端 MUST 将无效工具从 tools/list 的结果中排除。客户端 SHOULD 在拒绝工具定义时记录警告,包括工具名称和拒绝原因。此行为可确保单个格式错误的工具定义不会阻止其他有效工具的使用。使用其他传输方式(例如 stdio)的客户端 MAY 完全忽略 x-mcp-header 注解。
工具定义示例:
示例:地理分布式数据库
考虑一个暴露execute_sql 工具的服务器,例如用于 Google Cloud Spanner,并且需要 region 参数。
工具定义:
us-west1 中执行 SQL。
当前痛点:全局负载均衡器接收到请求,但必须终止 TLS 并解析整个 JSON 正文,才能在知道是否应将数据包路由到 Oregon 还是 Belgium 集群之前找到 "region": "us-west1"。
采用本提案后:客户端检测到 x-mcp-header 注解,并自动将 Mcp-Param-Region: us-west1 头添加到 HTTP 请求中。负载均衡器现在可以基于该头进行路由,而无需解析正文。
请求:
示例:多租户 SaaS 应用
某 SaaS 平台暴露在不同客户租户上运行的工具。通过将租户 ID 暴露在头中,平台可以将请求路由到租户专属基础设施。 工具定义:示例:基于优先级的请求处理
服务器可以暴露一个优先级参数,以便基础设施对某些请求进行优先处理。 工具定义:头处理
值编码
客户端 MUST 在将参数值包含到 HTTP 头中之前对其进行编码,以确保安全传输并防止注入攻击。 字符限制 根据 RFC 9110,HTTP 头字段值必须由可见 ASCII 字符(0x21-0x7E)、空格(0x20)和水平制表符(0x09)组成。以下字符被明确禁止:- 回车符(
\r,0x0D) - 换行符(
\n,0x0A) - 空字符(
\0,0x00) - ASCII 范围之外的任何字符(> 0x7F)
- 以空格(0x20)或水平制表符(0x09)开头
- 以空格(0x20)或水平制表符(0x09)结尾
-
Type conversion: Convert the parameter value to its string representation:
string: Use the value as-isinteger: Convert to decimal string representation (e.g.,42,-7)boolean: Convert to lowercase"true"or"false"
-
空白检查:如果字符串以空白字符(空格或制表符)开头或结尾:
- 应用 Base64 编码(见下文)
-
ASCII 校验:检查字符串是否仅包含有效 ASCII 字符(0x20-0x7E):
- 如果有效,继续执行第 4 步
- 如果无效(包含非 ASCII 字符),应用 Base64 编码(见下文)
-
控制字符检查:如果字符串包含任何控制字符(0x00-0x1F 或 0x7F):
- 应用 Base64 编码(见下文)
=?base64? 和后缀 ?= 表示该值已进行 Base64 编码。这些标记区分大小写,并且 MUST 按照所示形式精确出现(小写)。需要检查这些值的服务器和中介 MUST 相应地对其解码。
为避免歧义,客户端 MUST 还对任何匹配哨兵模式的纯 ASCII 值进行 Base64 编码(即以 =?base64? 开头并以 ?= 结尾)。
示例:
| Original Value | Reason | Encoded Header Value |
|---|---|---|
"us-west1" | Plain ASCII | Mcp-Param-Region: us-west1 |
"Hello, 世界" | Contains non-ASCII | Mcp-Param-Greeting: =?base64?SGVsbG8sIOS4lueVjA==?= |
" padded " | Leading/trailing spaces | Mcp-Param-Text: =?base64?IHBhZGRlZCA=?= |
"line1\nline2" | Contains newline | Mcp-Param-Text: =?base64?bGluZTEKbGluZTI=?= |
"=?base64?literal?=" | Matches sentinel pattern | Mcp-Param-Val: =?base64?PT9iYXNlNjQ/bGl0ZXJhbD89?= |
客户端行为
当通过 HTTP 传输构造tools/call 请求时,客户端 MUST:
- 从请求体中提取任何标准头的值(例如,
method、params.name、params.uri) - 将
Mcp-Method头以及(如适用)Mcp-Name头追加到请求中 - 检查工具的
inputSchema中标记有x-mcp-header的属性,并提取每个参数的值 - 按照 值编码 中的规则对这些值进行编码
- 将
Mcp-Param-{Name}: {Value}头追加到请求中:
实现说明:如果客户端没有工具的inputSchema(例如尚未调用tools/list)或者缓存的 schema 已过期(例如 TTL 已到期),客户端 SHOULD 在不带自定义Mcp-Param-*头的情况下发送请求。如果服务器因为缺少必需的自定义头而拒绝该请求,客户端 SHOULD 调用tools/list以获取当前的inputSchema,然后使用适当的头重试原始请求。客户端 MAY 通过其他方式预加载工具定义(例如来自先前会话或配置),以便在未先调用tools/list的情况下也能发送头。
Server Behavior
在接收请求时,服务器 MUST 拒绝包含无效字符的Mcp-Param-{Name} 头(见 值编码 部分中的“字符限制”)。
任何处理消息正文(而不仅仅是转发它)的服务器 MUST 验证编码后的头值在 Base64 解码(如适用)后与请求体中的对应值匹配。若任何验证失败,服务器 MUST 以 400 Bad Request HTTP 状态拒绝请求。
错误代码
当由于头验证失败而拒绝请求时,服务器 MUST 返回具有以下错误代码的 JSON-RPC 错误响应:
| Code | Name | Description |
|---|---|---|
-32001 | HeaderMismatch | HTTP 头与请求体中的对应值不匹配,或所需头缺失/格式错误。 |
-32000 到 -32099)。
错误响应格式:
- 缺少必需的标准头(
Mcp-Method、Mcp-Name等) - 头值与请求体值不匹配
- Base64 编码的值无法解码
- 头值包含无效字符
注意:中介 MUST 在验证失败时返回适当的 HTTP 错误状态(例如 400 Bad Request),但不要求返回 JSON-RPC 错误响应。
注意:基于镜像头执行策略的中介(例如按租户进行路由或限流)SHOULD 验证 MCP-Protocol-Version 头是否指示了一个需要头-正文验证的版本。如果版本较旧或该头缺失,中介 SHOULD 拒绝该请求,而不是信任未验证的头值。
自定义头处理:
自定义头(通过 x-mcp-header 定义的头)遵循与标准头相同的验证规则:
| Scenario | Client Behavior | Server Behavior |
|---|---|---|
| 提供了参数值 | 客户端 MUST 包含该头 | 服务器 MUST 验证头与正文匹配 |
参数值为 null | 客户端 MUST 省略该头 | 服务器 MUST NOT 期待该头 |
| 参数不在 arguments 中 | 客户端 MUST 省略该头 | 服务器 MUST NOT 期待该头 |
| 客户端省略了头但正文中存在值 | 不符合规范的客户端 | 服务器 MUST 拒绝该请求 |
400 Bad Request,并带有 JSON-RPC 错误代码 -32001(HeaderMismatch)。
理由
Header 与 Path
本提案将请求数据镜像到 header 中,而不是将其编码到 URL path 中。 Header 的优势:- 简单性:所有广泛使用的网络负载均衡器都支持基于 HTTP header 的路由
- 多版本支持:在客户端和服务器中更容易支持多个 MCP 版本
- 兼容性:Header 可与现有的 Streamable HTTP 传输设计配合使用,而无需更改 endpoint 结构
- 值无限制:Header 值可以包含在 URL 中需要编码的字符(例如
/、?、#) - 无 URL 长度限制:很长的值也可以传输,而不会触及 URL 长度限制
- 框架简单性:许多 Web 框架(Flask、Express、Django、Rails)都内置支持基于 path 的路由,配置极少
- 日志记录:URL path 通常默认会被记录,便于调试
| 框架 | 基于 Header 的路由 | 基于 Path 的路由 |
|---|---|---|
| Flask(Python) | 需要中间件或装饰器在路由前提取 header | 原生支持 @app.route('/mcp/<method>') |
| Express(Node.js) | 可通过 req.headers 轻松实现,但需要自定义路由逻辑 | 原生支持 app.post('/mcp/:method') |
| Django(Python) | 需要自定义中间件 | 原生 URL 模式 |
| Go(net/http) | 可通过 r.Header.Get() 轻松实现 | 可通过 path 模式原生支持 |
| ASP.NET Core | 可通过 [FromHeader] 属性轻松实现 | 可通过路由模板原生支持 |
- 向后兼容:引入基于 path 的路由将要求所有现有 MCP Server 进行重大更新,并且可能需要同时支持两套 endpoint 来支持多个版本。即使 SDK 可以在一定程度上掩盖这些问题,测试、指标等额外运维关注点仍然需要处理。基于 header 的路由只需极少的客户端改动。未选择 opt in 的客户端也仍可正常工作。
- 基础设施收益大于框架复杂度:主要目标是让网络基础设施(负载均衡器、代理、WAF)无需解析 body 就能路由和处理请求。这一收益与服务器所使用的框架无关。
基础设施支持
基于 HTTP header 的路由和处理已被以下组件支持:- 负载均衡器:所有主流负载均衡器(HAProxy、NGINX、Cloudflare、F5、Envoy/Istio)
- 限流:11 个流行限流方案中的 9 个
- 授权:Kong、Tyk、AWS API Gateway、Google Cloud Apigee、Azure API Gateway、NGINX、Apache APISIX、Istio/Envoy
- Web 应用防火墙:Cloudflare WAF、AWS WAF、Azure WAF、F5 Advanced WAF、FortiWeb、Imperva WAF、Barracuda WAF、ModSecurity、Akamai、Wallarm
- 可观测性:大多数可观测性方案都可以从 HTTP header 中提取数据
x-mcp-header 中显式 Header 名称
该设计在x-mcp-header 中使用显式名称值,而不是从参数名推导 header 名称,原因如下:
- 大小写敏感性不匹配:Header 名称不区分大小写,但 JSON Schema 属性名区分大小写
- 字符集限制:Header 名称仅限 ASCII 字符,而工具参数名可能包含任意 Unicode
- 简单性:无需用复杂方案从嵌套属性构造 header 名称
在 JSON Schema 中的位置
x-mcp-header 扩展直接放置在要镜像的属性的 JSON Schema 内部,而不是放在 schema 外部的单独元数据字段中。该设计选择有几个优点:
- 共置性:header 映射与其影响的属性定义在一起,使其立即清楚哪个参数会被镜像。开发者无需在 schema 与单独的元数据结构之间来回查找。
-
成熟模式:JSON Schema 明确支持扩展关键字(以
x-开头的属性),这一模式在 OpenAPI 等生态中被广泛使用。工具作者和 SDK 开发者对此方式已经很熟悉。 -
Schema 可组合性:当 schema 被组合、扩展或通过
$ref引用时,x-mcp-header注释会随属性定义一起传递。单独的元数据结构则需要复杂的同步逻辑来保持一致性。 -
工具兼容性:现有 JSON Schema 校验器默认会忽略未知关键字,因此添加
x-mcp-header不会破坏现有 schema 校验。不理解此扩展的工具会直接跳过它。 - 降低复杂度:单独的元数据结构需要定义一种映射机制(例如 JSON Pointer 或属性路径)来将 headers 与属性关联起来,这会增加实现复杂度并带来出错风险。
范围:仅适用于 Tools
x-mcp-header 机制目前仅适用于 tools/call 请求,因为 tools 是唯一带有 inputSchema 且支持 JSON Schema 扩展关键字的 MCP 原语。Resources 和 prompts 没有等价的 schema 结构:resources/read 只接收一个 uri(已通过 Mcp-Name 暴露),而 prompts/get 将参数定义为一个简单的 {name, description, required} 数组,不具备 JSON Schema 可扩展性。若要将自定义 header 映射泛化到这些原语,需要为 resources 和 prompts 增加类似 inputSchema 的定义,这属于更大的规范变更。这被记录为未来可能的扩展。
不定义规范层面的 Header 大小限制
本规范有意不定义单个 header 值长度、MCP header 总大小或自定义 header 数量的限制。Header 纯粹是 HTTP 概念,而 HTTP 本身(RFC 9110)并未规定 header 大小限制。常见 HTTP 基础设施会施加自己的限制——从某些服务器的 4–8 KB(例如 Apache 约 8190 字节)到其他系统的 128 KB(例如 Cloudflare)不等——但合适的限制取决于部署环境,而只有服务运营者才能确定这一点。 定义规范层面的限制(例如“省略超过 8192 字节的 header”)会带来问题:- 任意阈值:无论选择什么数值,对某些部署来说都太低,对另一些则无关紧要。合适的“正确”限制因基础设施而异。
- 适得其反的省略:如果客户端因为某个 header 超过规范定义的限制而省略它,那么依赖该 header 进行路由的服务器和中间件就必须解析 body 或拒绝请求——这会削弱将值暴露在 header 中的核心目的。
- 不必要的 SDK 负担:SDK 维护者需要为一个在实践中很少适用的约束实现并测试限制检查逻辑。
- 与 HTTP 重复:服务器和中间件已经会使用标准 HTTP 状态码拒绝过大的 header(
413 Request Entity Too Large、431 Request Header Fields Too Large),客户端无论如何都必须处理这些响应。
给实现者的注记:服务器、中间件和客户端可以根据各自的部署环境独立对单个 header 大小、MCP header 总大小或自定义 header 数量施加限制。服务器应记录其施加的任何限制。客户端应优雅地处理413 Request Entity Too Large或431 Request Header Fields Too Large响应。工具作者应将x-mcp-header注释限制在那些能带来明确基础设施收益的参数上。
不安全值的编码方式
对于无法安全表示为普通 ASCII header 值的参数值(非 ASCII 字符、前导/尾随空白字符、控制字符),我们考虑了四种编码方式:-
Sentinel 包裹(所选方案):在同一个
Mcp-Param-{Name}header 内使用=?base64?{value}?=前缀/后缀来标识 Base64 编码值。 -
单独的 header 名称:为编码值使用不同的 header 名称,例如
Mcp-ParamEncoded-{Name},通过 header 名称而不是值格式来表示编码。 -
隐式编码:让解析器根据工具 schema 推断编码,例如在工具定义中使用
"x-mcp-header-encoding": "base64"注释。 -
始终编码:对每个
Mcp-Param-{Name}值都无条件进行 Base64 编码。
| 方案 | 优点 | 缺点 |
|---|---|---|
| Sentinel 包裹 | 每个参数只需一个 header 名称;常见情况(纯 ASCII)可读性强;中间件无需解码即可基于普通值进行路由 | 带内信号在理论上可能与字面值冲突;每个读取方都必须检查该前缀 |
| 单独的 header 名称 | 不存在带内歧义;编码方式可从 header 名称自解释 | header 命名空间翻倍;每个中间件都必须为每个参数检查两个 header 名称;如果两者都存在,还需要冲突规则 |
| 隐式编码 | 最简单的线格式;无需 sentinel 或额外 header | 中间件需要访问工具 schema 才知道是否解码——这违背了在 header 中暴露值的目的;按参数静态决定无法很好处理混合情况 |
| 始终编码 | 规则最简单;无需条件逻辑或歧义 | 纯 ASCII 值会变得不可读;中间件必须解码 Base64 才能检查任何值,这会显著削弱本 SEP 的核心动机 |
=?base64?...?= 在实践中成为字面参数值的可能性极低。
向后兼容性
标准头
在使用新的 MCP 版本时,现有客户端和 SDK 将被要求包含标准头。这是一个小幅度的新增,因为客户端已经包含了诸如Mcp-Protocol-Version 之类的头,因此每条消息只需额外增加一到两个新头。
实现新版本的服务器 MUST 拒绝缺少必需头的请求。服务器 MAY 在协商较旧协议版本时,通过接受不带头的请求来支持旧客户端。
来自工具参数的自定义头
x-mcp-header 扩展对服务器而言是可选的。没有此属性的现有工具将继续按原样工作。不过,实现了包含本规范的 MCP 版本的客户端 MUST 支持该特性。不支持 x-mcp-header 的旧客户端仍可正常工作,但无法提供服务器可能依赖的基于头的路由优势。
安全影响
头注入
当包含控制字符(尤其是\r\n)的恶意值被包含在头中时,就会发生头注入攻击,这可能允许攻击者注入额外的头或提前终止头部区域。
客户端 MUST 遵循本规范中定义的 值编码 规则。这些规则确保:
- 控制字符绝不会包含在头值中
- 非 ASCII 值会使用 Base64 安全编码
- 超过安全长度限制的值会被省略
头伪造
服务器 MUST 验证头值与请求体中的对应值一致。这可防止客户端发送不匹配的头,以在执行不同操作时操纵路由。 例如,恶意客户端可能会尝试:- 在执行面向高安全区域的操作时,将请求路由到安全性较低的区域
- 通过伪造租户标识来绕过速率限制
- 通过虚报正在执行的操作来规避安全策略
信息泄露
为头指定的工具参数值将对网络中间设备(负载均衡器、代理、日志系统)可见。服务器开发者:- SHOULD NOT 将敏感参数(密码、API 密钥、令牌、PII)标记为
x-mcp-header - SHOULD 记录哪些参数会作为头暴露
- SHOULD 考虑到 Base64 编码不提供机密性——它只是编码,不是加密
信任头值
头值来源于工具调用参数,这些参数可能受到 LLM 或恶意客户端的影响。中间设备和服务器 MUST NOT 将这些值视为用于安全敏感决策的可信输入。尤其是:- 暗示可访问特定资源的头值(例如租户 ID、区域名称)在授予对这些资源的访问权限之前,MUST 先由身份验证用户的权限进行独立验证。
- 头值 MUST NOT 作为授予提升权限的唯一依据;必须由服务器端强制执行速率限制和配额。
- 部署 SHOULD 尽早在流水线中拒绝带有过大或过多头的请求——在执行 Base64 解码或正文解析之前——以缓解精心构造的载荷带来的拒绝服务风险。
一致性测试用例
本节定义了一致性测试 MUST 覆盖的边界情况,以确保实现之间的互操作性。标准头边界情况
大小写敏感性
| 测试用例 | 输入 | 预期行为 |
|---|---|---|
| Header 名称大小写变化 | mcp-method: tools/call | 服务器 MUST 接受(header 名称不区分大小写) |
| Header 名称混合大小写 | MCP-METHOD: tools/call | 服务器 MUST 接受 |
| 方法值大小写 | Mcp-Method: TOOLS/CALL | 服务器 MUST 拒绝(方法值区分大小写) |
头/正文不匹配
| 测试用例 | Header 值 | 正文值 | 预期行为 |
|---|---|---|---|
| 方法不匹配 | Mcp-Method: tools/call | "method": "prompts/get" | 服务器 MUST 拒绝,返回 400 和错误码 -32001 |
| 工具名称不匹配 | Mcp-Name: foo | "params": {"name": "bar"} | 服务器 MUST 拒绝,返回 400 和错误码 -32001 |
| 缺少必需头 | (无 Mcp-Method) | 有效正文 | 服务器 MUST 拒绝,返回 400 和错误码 -32001 |
| Header 中多余空白 | Mcp-Name: foo | "params": {"name": "foo"} | 服务器 MUST 接受(按 HTTP 规范去除空白) |
值中的特殊字符
| 测试用例 | 值 | 预期行为 |
|---|---|---|
| 带连字符的工具名称 | my-tool-name | 客户端按原样发送;服务器接受 |
| 带下划线的工具名称 | my_tool_name | 客户端按原样发送;服务器接受 |
| 带特殊字符的资源 URI | file:///path/to/file%20name.txt | 客户端按原样发送;服务器接受 |
| 带查询字符串的资源 URI | https://example.com/resource?id=123 | 客户端按原样发送;服务器接受 |
自定义头边界情况
x-mcp-header 名称冲突
| 测试用例 | Schema | 预期行为 |
|---|---|---|
| 重复的 header 名称(相同大小写) | 两个属性都使用 "x-mcp-header": "Region" | 客户端 MUST 拒绝工具定义 |
| 重复的 header 名称(不同大小写) | "x-mcp-header": "Region" 和 "x-mcp-header": "REGION" | 客户端 MUST 拒绝工具定义(不区分大小写唯一性) |
| Header 名称与标准头同名 | "x-mcp-header": "Method" | 允许(生成的是 Mcp-Param-Method,不是 Mcp-Method) |
| 空 Header 名称 | "x-mcp-header": "" | 客户端 MUST 拒绝工具定义 |
无效的 x-mcp-header 值
| 测试用例 | x-mcp-header 值 | 预期行为 |
|---|---|---|
| 包含空格 | "x-mcp-header": "My Region" | 客户端 MUST 拒绝工具定义 |
| 包含冒号 | "x-mcp-header": "Region:Primary" | 客户端 MUST 拒绝工具定义 |
| 包含非 ASCII 字符 | "x-mcp-header": "Région" | 客户端 MUST 拒绝工具定义 |
| 包含控制字符 | "x-mcp-header": "Region\t1" | 客户端 MUST 拒绝工具定义 |
值编码边界情况
| 测试用例 | 参数值 | 预期 Header 值 |
|---|---|---|
| 纯 ASCII 字符串 | "us-west1" | Mcp-Param-Region: us-west1 |
| 以空格开头的字符串 | " us-west1" | Mcp-Param-Region: =?base64?IHVzLXdlc3Qx?= |
| 以空格结尾的字符串 | "us-west1 " | Mcp-Param-Region: =?base64?dXMtd2VzdDEg?= |
| 前后都有空格的字符串 | " us-west1 " | Mcp-Param-Region: =?base64?IHVzLXdlc3QxIA==?= |
| 仅包含内部空格的字符串 | "us west 1" | Mcp-Param-Region: us west 1 |
| 布尔值 true | true | Mcp-Param-Flag: true |
| 布尔值 false | false | Mcp-Param-Flag: false |
| 整数 | 42 | Mcp-Param-Count: 42 |
| 浮点数 | 3.14159 | Mcp-Param-Value: 3.14159 |
| 非 ASCII 字符 | "日本語" | Mcp-Param-Text: =?base64?5pel5pys6Kqe?= |
| 包含换行符的字符串 | "line1\nline2" | Mcp-Param-Text: =?base64?bGluZTEKbGluZTI=?= |
| 包含回车符的字符串 | "line1\r\nline2" | Mcp-Param-Text: =?base64?bGluZTENCmxpbmUy?= |
| 以 tab 开头的字符串 | "\tindented" | Mcp-Param-Text: =?base64?CWluZGVudGVk?= |
| 空字符串 | "" | Mcp-Param-Name: (空值) |
类型限制违规
| 测试用例 | 属性类型 | 存在 x-mcp-header | 预期行为 |
|---|---|---|---|
| 数组类型 | "type": "array" | 是 | 客户端 MUST 拒绝工具定义 |
| 对象类型 | "type": "object" | 是 | 客户端 MUST 拒绝工具定义 |
| 空类型 | "type": "null" | 是 | 客户端 MUST 拒绝工具定义 |
| 嵌套属性 | 对象内部的属性 | 是 | 客户端 MUST 拒绝工具定义 |
服务器验证边界情况
Base64 解码
| 测试用例 | Header 值 | 预期行为 |
|---|---|---|
| 有效的 Base64 | =?base64?SGVsbG8=?= | 服务器解码为 "Hello" 并进行验证 |
| Base64 补位无效 | =?base64?SGVsbG8?= | 服务器 MUST 拒绝,返回 400 和错误码 -32001;中间设备 MAY 返回 400 状态码 |
| Base64 字符无效 | =?base64?SGVs!!!bG8=?= | 服务器 MUST 拒绝,返回 400 和错误码 -32001;中间设备 MAY 返回 400 状态码 |
| 缺少前缀 | SGVsbG8= | 服务器将其视为字面值,而不是 Base64 |
| 缺少后缀 | =?base64?SGVsbG8= | 服务器将其视为字面值,而不是 Base64 |
| 包装格式错误 | =?BASE64?SGVsbG8=?= | 服务器 MUST 接受(前缀大小写不敏感) |
空值与缺失值
| 测试用例 | 场景 | 预期行为 |
|---|---|---|
| 带 x-mcp-header 的参数为 null | "region": null | 客户端 MUST 省略 header |
| 带 x-mcp-header 的参数缺失 | 参数不在 arguments 中 | 客户端 MUST 省略 header |
| 可选参数已提供 | 已提供可选参数 | 客户端 MUST 包含 header |
当正文中存在值但缺少自定义头时
| 测试用例 | 是否存在 Header | 正文值 | 预期行为 |
|---|---|---|---|
| 标准头被省略,但正文中有值 | 没有 Mcp-Name | "params": {"name": "foo"} | 服务器 MUST 拒绝,返回 400 和错误码 -32001;中间设备 MAY 返回 400 状态码 |
| 自定义头被省略,但正文中有值 | 没有 Mcp-Param-Region | "region": "us-west1" | 服务器 MUST 拒绝,返回 400 和错误码 -32001;中间设备 MAY 返回 400 状态码 |
参考实现
将在此 SEP 达到最终状态之前提供。 实现要求:- 服务器 SDK:提供一种机制(属性/装饰器)来标记带有
x-mcp-header的参数 - 客户端 SDK:实现提取和编码头部值的客户端行为
- 验证:双方都必须验证头部/正文一致性