Streamable HTTP carries a tool call as a JSON body, so anything between the client and the server
has to parse that body to know what is being asked. The x-mcp-header extension,
introduced in specification revision 2026-07-28, lets a server nominate individual parameters to be
copied into HTTP headers, so proxies, load balancers and firewalls can route on them without reading
the payload.
The annotation goes inside the JSON Schema of the property being mirrored, and its value is the
name portion of the resulting Mcp-Param-{name} header:
{
"name": "execute_sql",
"description": "Execute SQL on Google Cloud Spanner",
"inputSchema": {
"type": "object",
"properties": {
"region": { "type": "string", "description": "The region to execute the query in", "x-mcp-header": "Region" },
"query": { "type": "string", "description": "The SQL query to execute" }
},
"required": ["region", "query"]
}
}
Called with "region": "us-west1", the client adds
Mcp-Param-Region: us-west1 to the HTTP request.
1*tchar from RFC 9110 section 5.1.x-mcp-header values in that
inputSchema.number is not
permitted. Integers must be within the IEEE754 double-precision safe range.A client on streamable HTTP MUST reject a tool definition that violates any of these, and rejection
is defined precisely: the client MUST exclude the invalid tool from the result of
tools/list. It SHOULD log a warning naming the tool and the reason. The stated purpose is
that one malformed definition does not prevent the other tools from being used.
So the symptom of a mistake here is a tool that simply is not there, on some transports and not others, with the explanation in a log you may not be reading. Clients on stdio MAY ignore the annotation entirely, which means a server tested locally over stdio can lose tools the moment it is deployed behind HTTP.
The specification says server developers SHOULD NOT mark passwords, API keys, tokens or personal
data with x-mcp-header, because header values are visible to network intermediaries. That
is the entire point of the feature, and it is the reason to use it sparingly: a value you mirror is a
value you have chosen to show to every hop.
The honest answer is rarely, and only when something in your network path needs to make a decision before the body is available. Region or tenant routing, per-parameter rate limiting at the edge, and firewall rules that depend on an argument are the cases the design is aimed at. If your server reads the value itself and nothing between you and the client cares, the argument in the body is already enough.
Source: the tools section of the MCP specification, revision 2026-07-28, at modelcontextprotocol.io, fetched 2026-09-09. The example is the specification's own. This extension is new in that revision, so a client speaking an earlier version will not implement it and your tool has to work without it.
Floating point values do not round-trip through a text header predictably, so the value a proxy reads could differ from the value the server receives. Integers are constrained to the IEEE754 safe range for the same reason.
Yes. The header is a mirror, not a move. Your handler reads arguments exactly as before, and the specification points at its own section on extracting header values from call arguments for the precise rules.
The uniqueness requirement is case-insensitive, so Region and region collide. A client on streamable HTTP must then reject the whole tool definition and leave that tool out of tools/list.
Only if the property is statically reachable from the schema root. A property behind a oneOf branch or a dynamic reference is not, and marking one is a violation that removes the tool.
Log the incoming headers on your server and call the tool through the client you care about. A client on stdio may ignore the annotation entirely, which is allowed, so the absence of the header is not necessarily a bug.
All MCP servers and prices · All guides · Buy the bundle $39