Writing ·

How to enforce MCP tool policy at an HTTP gateway in 2026

Use the MCP 2026-07-28 Streamable HTTP headers to make a narrow edge classification decision — version, RPC method, and named tool or resource — then let the MCP server reject header/body mismatches, validate the request and token, authorize the operation, and enforce argument- and side-effect-specific controls.

By Youssef Hemimy · MCP · gateway · AgentOps

Use the MCP 2026-07-28 Streamable HTTP headers to make a narrow edge classification decision — version, RPC method, and named tool or resource — then let the MCP server reject header/body mismatches, validate the request and token, authorize the requested operation, and enforce argument- and side-effect-specific controls. The gateway can remove request classes that have no business reaching a server and can rate-limit and observe the rest by operation. It cannot make a tool call safe by itself.

3
header fields available for edge classification: version, method, name
400
status a header/body protocol-version mismatch must return
3
named operations that require Mcp-Name: tools/call, resources/read, prompts/get
1
layer that can validate a token and authorize an operation: the MCP server

Why the gateway can now see an MCP operation

The stable MCP 2026-07-28 revision requires Streamable HTTP clients to send every JSON-RPC request as its own HTTP POST to a single MCP endpoint. The protocol mirrors selected JSON-RPC body fields into HTTP headers so intermediaries can route and inspect a request without parsing its body — the body remains the source of truth, and bindings define how a mismatch is rejected.

For a compliant Streamable HTTP request, MCP-Protocol-Version is required on every POST, Mcp-Method is required on every request, and Mcp-Name is required for tools/call, resources/read, and prompts/get. The version header must agree with the request body's _meta protocol version; if it does not, the server must reject the request with 400 Bad Request and a HeaderMismatch error.

Cloudflare's implementation analysis describes the operational use plainly: a gateway, rate limiter, or WAF can build rules from these headers without parsing arbitrary JSON, and can record tool-level metrics using ordinary HTTP controls. That is one vendor's implementation experience, not a claim that every gateway ships the same feature set.

The gateway classifies on three header fields and proxies. The server stays the final authority for consistency, tokens, authorization, and arguments.

Make the edge decision deliberately narrow

Start with an allowlist whose entries are recognizable to both the gateway and the server. A useful policy record has four fields — the first three built directly from the protocol's mirrored metadata, the fourth a deliberate operating choice layered on top:

Policy fieldEdge decisionBackend decision
Protocol versionAccept only versions the endpoint is prepared to serve; route legacy traffic separately or reject it.Reject unsupported or body/header-inconsistent versions as the protocol requires.
RPC methodAllow only expected methods, such as tools/list, tools/call, or a documented discovery operation.Confirm the JSON-RPC method and apply the method's protocol rules.
Operation nameFor a named request, allow only the tool, prompt, or resource names intended for that endpoint.Resolve the operation in the authenticated caller's permitted set.
Operation classRate-limit, log, and alert differently for discovery, read, and consequential invocation classes.Validate arguments, authorization, preconditions, idempotency, and any approval requirement.

A gateway might allow tools/list at a modest discovery rate, allow a read-only tools/call name under a per-user limit, and deny an unrecognized name before it consumes server capacity. It should still send the accepted request to a server that repeats the authoritative checks. A gateway allowlist is a traffic-admission control; it is not permission to perform the underlying action.

Keep header classification consistent with the JSON-RPC request

Do not let the edge rule become a second, loosely synchronized protocol implementation. The protocol says request metadata lives in the message body and that the HTTP binding mirrors selected fields into headers; the body is the source of truth. The Streamable HTTP specification requires the server to reject a mismatch between the protocol-version header and the body.

Treat the same principle as a design rule for gateway policy:

  1. Classify at the edge. Read the required protocol, method, and name headers; reject malformed, unknown, or unallowed combinations before proxying.
  2. Preserve the request. Do not rewrite a method or tool name to make a request fit an allowlist. Pass it to an MCP-aware backend that can compare the wire representation with the JSON-RPC payload.
  3. Reject disagreement. Make mismatched or incomplete metadata a visible failure class, not a fallback to a more permissive rule.
  4. Test the negative cases. Exercise a valid request, an unknown method, an unknown tool name, a header/body mismatch, an unsupported version, and a valid name with invalid arguments. Record which layer rejected each case.

That test plan is Bonfire guidance: a policy is only as credible as the behavior at the boundary where its classification and the server's semantics disagree.

Put authorization and argument controls behind the gateway

MCP's authorization specification defines authorization capabilities for HTTP-based transports but makes authorization optional for MCP implementations. When it is supported, a protected MCP server is an OAuth 2.1 resource server; it must validate access tokens and accept only tokens valid for its own resources, and clients must send authorization on every HTTP request.

That is server-side work. A gateway can enforce a coarse identity or route traffic to a tenant boundary, but a method/name header cannot establish that a token is valid for the target MCP server, that the caller has the right scope for one specific tool, or that the arguments satisfy the tool's business rules. The tools specification makes the gap concrete: a tools/call request includes a tool name and an argumentsobject, tool definitions provide JSON Schema for expected input, and a server's available tool set may vary by the authorization presented on a request.

Use two complementary checks:

  • Gateway: Is this version/method/name combination allowed to enter this endpoint, at this rate, from this coarse traffic class?
  • Server: Is the caller authenticated and authorized for this operation now? Do the arguments satisfy the schema and business preconditions? Is an approval, idempotency key, state check, or compensating path required before an effect occurs?

The second list is broader than MCP's headers on purpose — production safety depends on an operation's inputs and effects, not only its name. For the deeper tool-contract boundary, see production agent tool contracts.

Use custom parameter headers carefully

MCP 2026-07-28 also permits a server to designate selected primitive tool parameters with x-mcp-header. A conforming Streamable HTTP client must mirror those values into Mcp-Param-* headers, subject to defined schema and encoding constraints. The tools specification warns server developers not to mark sensitive parameters — passwords, API keys, tokens, or PII — with x-mcp-header, because headers are visible to network intermediaries.

Keep a parameter mirrored only when all of these are true:

  • it is non-sensitive and has a documented edge-policy use;
  • the client and server both enforce the protocol's header-encoding and schema constraints;
  • the server still validates the original argument; and
  • gateway telemetry and retention for the header are acceptable for that field.

Those four gates are Bonfire guidance. They turn the specification's transport feature into a reviewable operating decision rather than an accidental data export.

Design rate limits and telemetry around operation classes

A single endpoint budget hides the behavior you need to manage. tools/list can be a discovery path; a named tools/call may be a read, an expensive computation, or a consequential write. The method and name headers give an HTTP intermediary stable labels for separate rate limits and operation-level telemetry on Streamable HTTP.

SignalWhy retain itDo not infer from it
Protocol version, method, and operation nameWhich policy branch handled the requestWhether the arguments were valid or the caller was authorized
Policy outcome and reason codeWhether the edge allowed, denied, or rate-limited trafficWhether a server-side action completed
Server outcome class and latencyWhether a permitted request reached a successful backend resultThe contents of the tool arguments or result
Approval or idempotency reference, when applicableWhich downstream control governed a consequential actionThat the gateway itself provided that control

This is a Bonfire observability pattern, not a prescribed MCP log schema. It pairs well with an agent observability dashboard: the edge and the server should make their decisions joinable without turning operation logs into an unrestricted argument archive.

Roll out the policy without breaking legitimate clients

The 2026-07-28 revision changed Streamable HTTP behavior, including removal of protocol-level sessions and the GET stream endpoint. The specification's changelog says this revision requires standard Mcp-Method and Mcp-Name request headers on Streamable HTTP POST requests.

Before enforcing a strict edge allowlist, inventory the protocol versions and methods your deployed clients actually use, then stage the policy:

  1. Observe first. Record the method/name/version combinations the endpoint receives and identify legacy or unknown traffic without silently treating it as safe.
  2. Define explicit compatibility behavior. Route a supported earlier protocol version to a separate endpoint or policy, or reject it with a documented migration path. Do not let a 2026-07-28 policy accidentally authorize legacy traffic that lacks the same metadata.
  3. Enforce known combinations. Deny unknown version/method/name combinations and give operators a durable reason code.
  4. Exercise failure paths. Verify rate-limit responses, mismatch rejection, unsupported-version handling, expired-token handling, invalid arguments, and the downstream approval path for consequential operations.
  5. Review after change. Compare edge denials, server rejections, and completed outcomes. A large mismatch between those views is a policy or integration problem to investigate.

What this boundary does — and does not — solve

An HTTP gateway is valuable because it can remove clearly unallowed request classes before they hit an MCP server and can make the remaining operation traffic easier to rate-limit and observe. It does not substitute for the server controls that make a tool call legitimate. Keep the boundaries separate:

That separation is less glamorous than “the gateway secures MCP.” It is also substantially more honest.

Caveats

This draft is scoped to the stable MCP 2026-07-28 specification and Streamable HTTP; other transports do not necessarily expose the same HTTP metadata. The specification treats the body as the source of truth for mirrored metadata, so this draft does not claim a header-only gateway can validate all JSON-RPC semantics or arguments. MCP authorization is optional, and its authorization specification does not prove that any particular gateway, OAuth deployment, tool schema, or policy configuration is secure. Cloudflare is cited as one implementation example for HTTP-native operation classification; its product claims are not generalized to other gateways or deployments.

Sources

FAQ

Can an HTTP gateway authorize an MCP tool call on its own?

No. MCP's Streamable HTTP headers give a gateway three classification fields — protocol version, RPC method, and (for named operations) the tool, resource, or prompt name. That is enough to admit or reject a request class. It is not a token check, a scope check, or an argument check. The MCP server remains the OAuth 2.1 resource server when authorization is used, and it is the only layer that can validate a token for itself, decide whether a specific caller may use a specific tool, and validate that tool's arguments.

What happens if the MCP-Protocol-Version header disagrees with the request body?

The Streamable HTTP specification requires the server to reject the request with 400 Bad Request and a HeaderMismatch error. A gateway that rewrites a header without the corresponding body field — or vice versa — will start breaking requests that were previously passing through untouched.

Is Mcp-Name required on every MCP request?

No. It is required specifically for tools/call, resources/read, and prompts/get — the named operations. Mcp-Method is required on every Streamable HTTP POST request, and MCP-Protocol-Version is required on every POST.

Should sensitive tool arguments be mirrored into Mcp-Param-* headers?

No. The MCP tools specification warns server developers not to mark sensitive parameters — passwords, API keys, tokens, or PII — with x-mcp-header, because HTTP headers are visible to network intermediaries. Reserve that mechanism for non-sensitive, edge-routing-relevant values, and keep the server validating the original argument regardless.

Does a gateway allowlist replace a human approval gate for consequential tool calls?

No. Allowing a version/method/name combination through the edge is a traffic-admission decision, not a review decision. A consequential action — one with a side effect that is hard to reverse — still needs the reviewer or approval-gate logic described separately from gateway policy.

Building something that has to hold up?

We do this work for teams — agent reliability hardening, custom MCP servers, and full-stack AI systems built to survive production.