# `AttestoMCP.Server.RequestMeta`
[🔗](https://github.com/XukuLLC/attesto_mcp_server/blob/v2.8.0/lib/attesto_mcp_server/request_meta.ex#L1)

Untrusted request metadata exposed to handlers as `context.request_meta`.

Every handler and per-request callback receives an immutable snapshot of the
incoming request's `params["_meta"]` object with its JSON string keys and
values unchanged. An absent object, which only legacy revisions permit,
produces `%{}`. The snapshot is the same for HTTP, stdio, and direct
dispatch through `AttestoMCP.Server.Test`.

The snapshot is client input. It is never merged into `principal`,
`principal_binding`, `tenant`, `scopes`, claims, sender constraints, or
`host_context`, and the server never derives an issuer, audience,
authorization decision, or outbound destination from it. Protocol-owned keys
such as `io.modelcontextprotocol/protocolVersion` appear exactly as the client
sent them; the server's validated interpretation remains in the normalized
context fields (`:protocol_version`, `:trace_context`, `:logging_level`) and
is not changed by the snapshot. Use `application/1` to read only keys outside
the reserved MCP namespaces.

The complete `_meta` object must encode within `:max_request_meta_bytes`
(65,536 bytes by default, configurable up to `:max_json_bytes`) and within
the server's existing JSON depth and node bounds. Larger metadata is rejected
with an invalid-params error whose reason is `"request_meta_too_large"`;
it is never truncated. String keys and values are copied out of the request
body so a retained snapshot does not keep the body alive.

Metadata values are not added to logs, telemetry, error payloads, or response
metadata. The existing trace-context extraction remains separate.

A multi-round retry exposes its own metadata. The signed retry state binds
operation parameters and all metadata except `traceparent`, `tracestate`,
`baggage`, `progressToken`, and `io.modelcontextprotocol/clientInfo`.
Application keys and protocol settings remain bound to the first round;
tracing, progress, and display values may change. Operation targets and
confirmation-bound values belong in operation parameters, not those volatile
fields. No identity or authority is recovered from earlier metadata.

# `application`

```elixir
@spec application(map()) :: map()
```

Returns the entries whose keys are outside MCP-reserved metadata names.

    iex> AttestoMCP.Server.RequestMeta.application(%{
    ...>   "com.example/request-purpose" => "audit",
    ...>   "io.modelcontextprotocol/protocolVersion" => "2026-07-28",
    ...>   "progressToken" => 7
    ...> })
    %{"com.example/request-purpose" => "audit"}

# `default_max_bytes`

```elixir
@spec default_max_bytes() :: pos_integer()
```

Returns the default metadata byte budget.

# `reserved_key?`

```elixir
@spec reserved_key?(term()) :: boolean()
```

Returns true for keys reserved by MCP: `progressToken`, the trace-context
keys, and any prefix whose second label is `modelcontextprotocol` or `mcp`.

# `valid_key?`

```elixir
@spec valid_key?(term()) :: boolean()
```

Returns true when a key follows the MCP `_meta` key grammar.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
