MCP gateways become enterprise security boundaries

Companies now run MCP in production beyond its original local-tool use case. The 2026 MCP roadmap identifies four enterprise concerns: audit trails, SSO authentication, gateway behavior, and configuration portability. The Enterprise-Managed Authorization extension lets organizations control MCP server access through their identity provider.

The Agentic AI Foundation (AAIF) release analysis frames MCP 2026-07-28 around stateless scale, formal governance, and authorization hardening. Its deprecation policy guarantees a 12-month minimum before removal.

Organizations use MCP gateways to implement these controls. MintMCP centralizes server hosting, OAuth and SSO, role-based access, and audit logs. Open-source Agentgateway, an Apache 2.0 project hosted by AAIF under the Linux Foundation, routes MCP requests, validates JWT and OIDC identities, calls external authorization services, and enforces CEL policies for tool access. Teams can buy this layer, deploy an open-source gateway, or build one into an internal platform.

Agentgateway architecture topology showing CLI and IDE clients, AI agents, and applications connecting through the gateway to MCP and A2A servers, APIs, agents, and model providers Agentgateway connects MCP clients to agents, model providers, MCP/A2A servers, and APIs. Official architecture diagram.

The gateway authenticates the caller, selects an upstream backend, and evaluates tool access. What happens when the backend selection and authorization decision point to different connections?

Agentgateway versions before v1.4.0 had a cross-route session reuse vulnerability. A cached MCP session restored the upstream connection from one route. The current route supplied the authorization context. I found this split in the session handling code and built a two-route reproduction to confirm the impact.

One session, two security contexts

To reproduce the mismatch, I configured two routes and two MCP backends on a vulnerable pre-v1.4.0 Agentgateway build:

Agentgateway Raw Configuration showing the sensitive route with deny true and the permissive route pointing to a public backend The intended boundary: /sensitive denies every MCP tool call; /permissive reaches a separate public backend.

/sensitive pointed to a local MCP server with an export_customer_records tool. Its authorization policy denied every tool call. /permissive allowed tool calls and pointed to a separate public server. Only the sensitive backend exposed export_customer_records.

I initialized a session on /sensitive. Agentgateway returned Mcp-Session-Id: SID-A. Agentgateway applies mcpAuthorization to MCP resources and tool calls. Session initialization falls outside that policy.

I first called export_customer_records on /sensitive with SID-A. Agentgateway returned HTTP 400 with Unknown tool. The policy blocked access to the tool on that route.

The same call to /permissive without a session also returned HTTP 400. The route alone could not reach the tool.

I sent the same JSON-RPC request with the same session ID and changed only the URL:

session created on: POST /sensitive  + Mcp-Session-Id: SID-A
session reused on:  POST /permissive + Mcp-Session-Id: SID-A

The reused-session request returned HTTP 200:

CONFIDENTIAL: customer_id=1842, plan=enterprise

The sensitive backend returned a synthetic customer record through the reused session.

Live terminal reproduction with a red line connecting the reused session ID: the sensitive route returns HTTP 400, while the permissive route returns HTTP 200 and confidential data Live reproduction. The public backend’s tools/call counter stayed at zero; the response came from the sensitive backend.

The zero public-backend counter shows what happened. Agentgateway matched /permissive and applied its policy, then resumed the upstream connection created through /sensitive.

sequenceDiagram
  participant C as MCP Client
  participant G as Agentgateway
  participant S as Sensitive MCP
  participant P as Public MCP

  C->>G: initialize /sensitive
  G->>S: initialize
  S-->>G: session initialized
  G-->>C: Mcp-Session-Id: SID-A
  C->>G: tools/call /sensitive + SID-A
  Note over G: /sensitive policy denies the tool
  G-->>C: HTTP 400: Unknown tool
  C->>G: tools/call /permissive + SID-A
  Note over G: /permissive policy allows the call
SID-A resumes the /sensitive backend G->>S: export_customer_records S-->>G: confidential result G-->>C: HTTP 200 Note over P: No tools/call request

Where Agentgateway split the request

Agentgateway used one session manager for all MCP routes. The cache recovered the original upstream connection from the supplied ID. The session entry omitted the backend identity. The gateway accepted the cached connection without checking it against the backend selected by the new route.

For the reused request, Agentgateway supplied authorization inputs from /permissive. The relay kept the upstream connection already stored in SID-A.

That produced this pairing:

authorization policy = /permissive
upstream backend      = /sensitive

The read operation disclosed data. A state-changing tool could use the same authorization mismatch to modify data.

I reported the issue to Agentgateway. The maintainers published GHSA-mvgg-jvj2-4frq and rated the issue High (CVSS 8.1).

The fix: bind each session to its backend

Agentgateway v1.4.0 adds the missing backend identity to each cached session. When another route presents that session, the gateway compares the selected backend with the stored identity and rejects a mismatch.

The session entry now includes backend_id, and the backend check rejects mismatches. The maintainers added a cross-backend regression test, published the advisory, and documented the issue in the v1.4.0 release. The fix landed in mcp: pin session to backend.

MCP 2026-07-28 moves to a stateless core

The Agentgateway bug illustrates the “gateway behavior” concern in the 2026 MCP roadmap. In MCP 2025-11-25, initialize set the protocol version, client capabilities, and client information. The server returned an Mcp-Session-Id, and later tool calls carried that identifier.

The later request required the gateway to recover the session state and preserve each security binding. Agentgateway restored the upstream connection and chose authorization inputs from the new route. One identifier represented two security contexts.

MCP 2026-07-28 replaces that flow with a self-contained request. MCP-Protocol-Version, Mcp-Method, and Mcp-Name give gateways the protocol version and operation. The client sends its information and capabilities in _meta. The server/discover method returns server capabilities on demand.

sequenceDiagram
  participant C as MCP Client
  participant G as MCP Gateway
  participant S as MCP Server

  Note over C,S: MCP 2025-11-25: sessionful
  C->>G: initialize
  G->>S: initialize
  S-->>G: Mcp-Session-Id
  G-->>C: Mcp-Session-Id
  C->>G: tools/call + Mcp-Session-Id
  Note over G: Recover session state
and security bindings G->>S: tools/call on restored connection Note over C,S: MCP 2026-07-28: stateless core C->>G: tools/call + MCP headers + _meta Note over G: Route from the current request G->>S: self-contained tools/call

Any server instance can process the call. Teams can use standard load balancers, Kubernetes, and existing cloud-native tools. Gateways route on the new headers. Servers reject requests when those headers disagree with the JSON-RPC body. New clients send no protocol session.

Applications carry state through explicit handles. A browser tool can return a browser_id. Tasks can return a durable taskId that survives a client restart. Later calls pass the handle in a tool argument. SEP-2567 defines sessionless MCP through explicit state handles. The server receives the handle and authorization context in the same call.

MCP 2026-07-28 also strengthens core authorization. Clients validate the authorization server issuer and bind registered credentials to that issuer. This check blocks OAuth mix-up attacks. The Enterprise-Managed Authorization extension lets corporate identity providers control server access.

The AAIF migration guide maps the old sessionful flow to self-contained requests and explicit application state.

Agentgateway v1.4.0 checks backend_id when it resumes a sessionful client. MCP 2026-07-28 removes the protocol session for new clients and carries application state through explicit handles. Both changes prevent a protocol session from carrying one backend into another authorization context.

Thanks to Howard John and the Agentgateway maintainers for investigating my report, publishing the advisory, and shipping the fix.