Skip to content

Commit 19dae76

Browse files
authored
Merge pull request modelcontextprotocol#2772 from mikekistler/mdk/sep-2243-clarifications
docs: SEP-2243 clarifications for x-mcp-header
2 parents 9d700ed + 54d5e2e commit 19dae76

4 files changed

Lines changed: 124 additions & 47 deletions

File tree

docs/seps/2243-http-standardization.mdx

Lines changed: 22 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/specification/draft/basic/transports.mdx

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -474,17 +474,26 @@ the header name `Mcp-Param-{name}`.
474474
**Constraints on `x-mcp-header` values**:
475475

476476
- **MUST NOT** be empty
477-
- **MUST** contain only ASCII characters (excluding space and `:`)
477+
- **MUST** match HTTP field-name token syntax (`1*tchar`, [RFC 9110 Section 5.1](https://datatracker.ietf.org/doc/html/rfc9110#section-5.1))
478+
- **MUST NOT** contain control characters, including carriage return (CR, `\r`)
479+
or line feed (LF, `\n`)
478480
- **MUST** be case-insensitively unique among all `x-mcp-header` values in
479481
the `inputSchema`
480-
- **MUST** only be applied to parameters with primitive types (number,
481-
string, boolean)
482-
483-
Clients **MUST** reject tool definitions where any `x-mcp-header` value
484-
violates these constraints. Rejection means the client **MUST** exclude the
485-
invalid tool from the result of `tools/list`. Clients **SHOULD** log a
486-
warning when rejecting a tool definition, including the tool name and the
487-
reason for rejection.
482+
- **MUST** only be applied to parameters with primitive types (integer,
483+
string, boolean). Parameters with type `number` are not permitted.
484+
Integer values **MUST** be within the safe range for JavaScript
485+
(−2<sup>53</sup>+1 to 2<sup>53</sup>−1)
486+
- **MAY** be applied to properties at any nesting depth within the
487+
`inputSchema`, not only top-level properties
488+
489+
Clients using the Streamable HTTP transport **MUST** reject tool definitions
490+
where any `x-mcp-header` value violates these constraints. Rejection means
491+
the client **MUST** exclude the invalid tool from the result of `tools/list`.
492+
Clients **SHOULD** log a warning when rejecting a tool definition, including
493+
the tool name and the reason for rejection. This ensures that a single
494+
malformed tool definition does not prevent other valid tools from being used.
495+
Clients using other transports (e.g., stdio) **MAY** ignore `x-mcp-header`
496+
annotations entirely.
488497

489498
**Example tool definition:**
490499

@@ -550,7 +559,7 @@ headers to ensure safe transmission and prevent injection attacks.
550559
**Type conversion**: Convert the parameter value to its string representation:
551560

552561
- `string`: Use the value as-is
553-
- `number`: Convert to decimal string representation (e.g., `42`, `3.14`)
562+
- `integer`: Convert to decimal string representation (e.g., `42`, `-7`)
554563
- `boolean`: Convert to lowercase `"true"` or `"false"`
555564

556565
Per [RFC 9110][rfc9110-values],
@@ -566,17 +575,23 @@ Mcp-Param-{Name}: =?base64?{Base64EncodedValue}?=
566575
```
567576

568577
The prefix `=?base64?` and suffix `?=` indicate that the value is
569-
Base64-encoded. Servers and intermediaries that need to inspect these
578+
Base64-encoded. These markers are case-sensitive and **MUST** appear exactly
579+
as shown (lowercase). Servers and intermediaries that need to inspect these
570580
values **MUST** decode them accordingly.
571581

582+
To avoid ambiguity, clients **MUST** also Base64-encode any plain-ASCII
583+
value that matches the sentinel pattern (i.e., starts with `=?base64?`
584+
and ends with `?=`).
585+
572586
**Encoding examples:**
573587

574-
| Original Value | Reason | Encoded Header Value |
575-
| ---------------- | ----------------------- | ----------------------------------------------------- |
576-
| `"us-west1"` | Plain ASCII | `Mcp-Param-Region: us-west1` |
577-
| `"Hello, 世界"` | Contains non-ASCII | `Mcp-Param-Greeting: =?base64?SGVsbG8sIOS4lueVjA==?=` |
578-
| `" padded "` | Leading/trailing spaces | `Mcp-Param-Text: =?base64?IHBhZGRlZCA=?=` |
579-
| `"line1\nline2"` | Contains newline | `Mcp-Param-Text: =?base64?bGluZTEKbGluZTI=?=` |
588+
| Original Value | Reason | Encoded Header Value |
589+
| ---------------------- | ------------------------ | ----------------------------------------------------- |
590+
| `"us-west1"` | Plain ASCII | `Mcp-Param-Region: us-west1` |
591+
| `"Hello, 世界"` | Contains non-ASCII | `Mcp-Param-Greeting: =?base64?SGVsbG8sIOS4lueVjA==?=` |
592+
| `" padded "` | Leading/trailing spaces | `Mcp-Param-Text: =?base64?IHBhZGRlZCA=?=` |
593+
| `"line1\nline2"` | Contains newline | `Mcp-Param-Text: =?base64?bGluZTEKbGluZTI=?=` |
594+
| `"=?base64?literal?="` | Matches sentinel pattern | `Mcp-Param-Val: =?base64?PT9iYXNlNjQ/bGl0ZXJhbD89?=` |
580595

581596
[rfc9110-values]: https://datatracker.ietf.org/doc/html/rfc9110#name-field-values
582597

@@ -595,6 +610,20 @@ When constructing a `tools/call` request via HTTP transport, the client
595610
rules.
596611
5. Append a `Mcp-Param-{Name}: {Value}` header to the request.
597612

613+
<Note>
614+
615+
If the client does not have the tool's `inputSchema` (e.g., `tools/list`
616+
has not yet been called) or the cached schema is stale (e.g., its TTL has
617+
expired), the client **SHOULD** send the request without custom
618+
`Mcp-Param-*` headers. If the server rejects the request because required
619+
custom headers are missing, the client **SHOULD** call `tools/list` to
620+
obtain the current `inputSchema`, then retry the original request with the
621+
appropriate headers. Clients **MAY** pre-load tool definitions via other
622+
means (e.g., from a previous session or configuration) to enable header
623+
emission without a prior `tools/list` call.
624+
625+
</Note>
626+
598627
##### Server Behavior for Custom Headers
599628

600629
Intermediate servers that do not recognize an `Mcp-Param-{Name}` header
@@ -638,6 +667,14 @@ different components in the network rely on different sources of truth
638667
(e.g., a load balancer routing on the header value while the MCP server
639668
executes based on the body value).
640669

670+
<Note>
671+
672+
When validating integer parameter values, servers **SHOULD** compare the
673+
header value and the body value numerically rather than as strings (e.g.,
674+
`42.0` and `42` are considered equal).
675+
676+
</Note>
677+
641678
When rejecting a request due to header validation failure, servers **MUST**
642679
return HTTP status `400 Bad Request` and **SHOULD** include a JSON-RPC error
643680
response using the following error code:
@@ -677,6 +714,16 @@ a JSON-RPC error response.
677714

678715
</Note>
679716

717+
<Note>
718+
719+
Intermediaries that enforce policy based on mirrored headers (e.g., routing
720+
or rate-limiting by tenant) **SHOULD** verify that the `MCP-Protocol-Version`
721+
header indicates a version that requires header–body validation. If the
722+
version is older or the header is absent, the intermediary **SHOULD** reject
723+
the request rather than trusting unvalidated header values.
724+
725+
</Note>
726+
680727
### Backward Compatibility
681728

682729
A client that supports both modern (per-request-metadata) MCP versions and a

docs/specification/draft/server/tools.mdx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -337,16 +337,24 @@ HTTP header.
337337
**Constraints on `x-mcp-header` values:**
338338

339339
- **MUST NOT** be empty
340-
- **MUST** contain only ASCII characters, excluding space and `:`
340+
- **MUST** match HTTP field-name token syntax (`1*tchar`, [RFC 9110 Section 5.1](https://datatracker.ietf.org/doc/html/rfc9110#section-5.1))
341+
- **MUST NOT** contain control characters, including carriage return (CR, `\r`) or
342+
line feed (LF, `\n`)
341343
- **MUST** be case-insensitively unique among all `x-mcp-header` values in the
342344
`inputSchema`
343-
- **MUST** only be applied to parameters with primitive types (number, string, boolean)
344-
345-
Clients **MUST** reject tool definitions where any `x-mcp-header` value violates these
346-
constraints. Rejection means the client **MUST** exclude the invalid tool from the result
347-
of `tools/list`. Clients **SHOULD** log a warning when rejecting a tool definition,
348-
including the tool name and the reason for rejection. This ensures that a single
349-
malformed tool definition does not prevent other valid tools from being used.
345+
- **MUST** only be applied to parameters with primitive types (integer, string, boolean).
346+
Parameters with type `number` are not permitted. Integer values **MUST** be within the
347+
safe range for integers represented using IEEE754 double-precision floating point numbers (−2<sup>53</sup>+1 to 2<sup>53</sup>−1)
348+
- **MAY** be applied to properties at any nesting depth within the `inputSchema`, not
349+
only top-level properties
350+
351+
Clients using the Streamable HTTP transport **MUST** reject tool definitions where any
352+
`x-mcp-header` value violates these constraints. Rejection means the client **MUST**
353+
exclude the invalid tool from the result of `tools/list`. Clients **SHOULD** log a
354+
warning when rejecting a tool definition, including the tool name and the reason for
355+
rejection. This ensures that a single malformed tool definition does not prevent other
356+
valid tools from being used. Clients using other transports (e.g., stdio) **MAY** ignore
357+
`x-mcp-header` annotations entirely.
350358

351359
**Example tool definition with `x-mcp-header`:**
352360

0 commit comments

Comments
 (0)