barrel_mcp_headers (barrel_mcp v3.0.1)

View Source

MCP request metadata headers (2026-07-28).

The Streamable HTTP transport mirrors selected JSON-RPC body fields into HTTP headers so load balancers, gateways and observability tooling can route and inspect a request without parsing its body:

  • Mcp-Method: the JSON-RPC method, on every request.
  • Mcp-Name: params.name or params.uri, on tools/call, resources/read and prompts/get.
  • Mcp-Param-{Name}: tool arguments a server opted into mirroring, via x-mcp-header in its inputSchema.

Because two components may then act on different sources of truth, a server that reads the body must check that the headers agree with it, and reject a mismatch with -32020. That check is the reason this module exists, and why encoding is defined so precisely: both sides have to agree byte for byte.

This module is pure. The transport decides when to apply it; the client uses the same functions to build what the server verifies.

Summary

Functions

Recover the original value from a header.

Render a parameter value as an HTTP header value.

Whether a string can travel as a plain header value.

Mirror the arguments a tool's schema opted into.

Collect the x-mcp-header bindings from a tool's inputSchema.

The standard headers for a request: Mcp-Method always, and Mcp-Name for the three methods that name what they act on.

Check that the headers agree with the body.

Types

header/0

-type header() :: {binary(), binary()}.

param_binding/0

-type param_binding() :: {HeaderName :: binary(), Path :: [binary()]}.

Functions

decode_value(V)

-spec decode_value(binary()) -> {ok, binary()} | {error, invalid_encoding}.

Recover the original value from a header.

Returns {error, invalid_encoding} for a sentinel whose payload is not valid Base64, and for a value carrying bytes a header may not hold. Servers decode before comparing against the body.

encode_value(V)

-spec encode_value(binary() | number() | boolean()) -> binary().

Render a parameter value as an HTTP header value.

Strings pass through when they are safe and are Base64-wrapped otherwise; integers become decimal; booleans become true / false.

is_safe_value(V)

-spec is_safe_value(binary()) -> boolean().

Whether a string can travel as a plain header value.

RFC 9110 allows visible ASCII, space and horizontal tab, but a value padded with either would not survive the round trip, and one shaped like the sentinel would be decoded as if it were encoded.

param_headers(Arguments, Bindings)

-spec param_headers(map(), [param_binding()]) -> [header()].

Mirror the arguments a tool's schema opted into.

A binding whose value is absent from the arguments is skipped: the spec has the header omitted rather than sent empty.

scan_header_params(Schema)

-spec scan_header_params(map()) -> {ok, [param_binding()]} | {error, term()}.

Collect the x-mcp-header bindings from a tool's inputSchema.

A binding is only valid on a property reachable from the schema root through a chain of properties keys alone. Anything behind items, a composition or conditional keyword, or a $ref has no single instance path, so a header could not be derived from it unambiguously. Such an annotation invalidates the whole tool definition rather than being ignored, so the failure surfaces at registration instead of on some later call.

standard(Method, Params)

-spec standard(binary(), map()) -> [header()].

The standard headers for a request: Mcp-Method always, and Mcp-Name for the three methods that name what they act on.

validate(Headers, Method, Params, Bindings)

-spec validate([header()], binary(), map(), [param_binding()]) -> ok | {error, binary()}.

Check that the headers agree with the body.

Bindings are the tool's x-mcp-header annotations, empty for anything that is not a tools/call. Returns the message for a -32020 error when they disagree.