All articles
AI Agent Security9 min read

The MCP Gateway Pattern: Governing AI Agents at Runtime

The Model Context Protocol is the fastest-spreading interoperability spec in software. The MCP gateway is the pattern that lets you govern agents without slowing them down.

TigerIdentity Team·

MCP started as an Anthropic-only convention for Claude Desktop. Two years later it is the de facto interoperability layer between LLM clients and internal tools. Every serious platform now speaks MCP: your IDE, your terminal, your workflow orchestrator. Which means every one of them needs governance.

The MCP gateway pattern is deceptively simple: put a proxy between the agent and the tool servers, enforce policy on every call, log everything. What is hard is doing it without adding a hundred milliseconds to every LLM turn.

Before the MCP gateway pattern existed as an architectural convention, enterprises tried two alternatives: govern at the tool server, or govern at the agent client. Governing at the tool server means adding policy enforcement to every internal service that exposes an MCP endpoint — ten services, ten integrations, ten policy schemas, ten places where a misconfiguration creates an unguarded path. Governing at the agent client means trusting the client to enforce its own constraints, which is definitionally not governance. The gateway is the only pattern that gives you a single enforcement point, uniform auditability, and composability with the rest of your identity infrastructure.

TL;DR

The MCP gateway sits between agent clients and tool servers, enforcing per-call policy, logging every action, and closing the loop with the decision-service in under 50 ms. It is the only pattern that gives you uniform governance across every agent in your estate without requiring changes to each tool server.

15 ms

p95 gateway latency — cached decision

TigerIdentity MCP gateway

40 ms

p95 gateway latency — fresh policy eval

TigerIdentity MCP gateway

100%

Tool calls in the audit log

Zero sampling, full fidelity

1

Integration point per agent estate

vs. N per tool server

Why gate at MCP, not at the tool

One choke point

An agent may hit ten different MCP servers in a session. Gating at each server means ten integrations. Gating at MCP is one.

Rich identity context

MCP carries the agent identity, the client identity, and the tool identity. Perfect substrate for policy.

Composable with existing enforcement

The gateway is just another workload calling `decision-service`. Reuse the policy DSL you already run.

Portable audit

A single log format (MCP JSON-RPC) across every agent your enterprise runs.

The identity context argument deserves expansion. An MCP call carries three identity dimensions simultaneously: the agent identity (which agent is making the call), the client identity (which MCP client is running the agent), and the tool identity (which server is being invoked). This three-dimensional identity context is richer than anything available at the tool server level — the tool server only sees the inbound call, not who originated the session upstream.

That context richness is what enables policy to be genuinely expressive. "An agent in role `customer-support` may read Jira tickets in project `SUPPORT` but not in project `INFRA`" requires knowing both the agent's role and the specific resource being accessed. The gateway has both; the tool server alone has only the latter.

Anatomy of the gateway

┌──────────────────┐        ┌────────────────────┐        ┌────────────────┐
│  MCP client      │        │  MCP gateway       │        │  MCP tool      │
│  (Claude, IDE,   │  ───▶  │  ─ authenticate    │  ───▶  │  server        │
│   internal app)  │        │  ─ authorize (RT)  │        │  (jira, gh, …) │
│                  │  ◀───  │  ─ record          │  ◀───  │                │
└──────────────────┘        │  ─ transform       │        └────────────────┘
                            └────────────────────┘
                                     │
                                     ▼
                            decision-service (<50 ms)
                                     │
                                     ▼
                             audit + TIDR pipeline

The gateway's four responsibilities — authenticate, authorise, record, transform — are distinct and need to be kept architecturally separate. Authentication (is this the agent it claims to be?) is a JWT verification step that should be cached for the session. Authorisation (may this agent make this specific call?) is a fresh policy evaluation for every call. Recording (log the call and its outcome) should be asynchronous so it does not add to the hot-path latency. Transformation (modify the call or response for policy compliance) is optional and should be declared in policy, not implemented in gateway middleware.

Per-call policy, not per-session

Session-level policy ("this agent may access Jira") is not enough. Real governance is per-call: "this agent may create issues but not delete them; may search but not export attachments; may act only in project ABC." The gateway evaluates each tool call independently, using the agent identity, the tool identity, the arguments, and the surrounding session context.

The argument-level evaluation is particularly important for destructive operations. A policy that says "this agent may call the `database` MCP server" without inspecting the arguments permits both `query_table` and `drop_table`. A gateway that performs argument-level evaluation can distinguish between them and block the destructive call while permitting the benign one.

# Per-call policy example — TigerIdentity policy DSL
policy:
  name: customer-support-agent-tools
  applies_to:
    agent_roles: [customer-support]

  rules:
    - tool: mcp-jira
      allow:
        - method: search_issues
          # no argument restriction
        - method: create_issue
          args:
            project: {in: [SUPPORT, CS]}      # restrict to support projects
      deny:
        - method: delete_issue
        - method: export_issues

    - tool: mcp-github
      allow:
        - method: get_file
          args:
            repo: {in: [docs, runbooks]}        # read-only, docs repos only
      deny:
        - method: create_pull_request
        - method: push_commit

    - tool: "*"
      deny:
        - method: "*"
          args:
            data_classification: {above: confidential}

Latency: where every millisecond hides

  • Warm auth cache. The agent identity does not change between calls. Cache the JWT verification result for the session.
  • Compiled policy. As with the decision engine — compile YAML DSL to a Go struct at deploy time; do not evaluate a rule engine on the hot path.
  • Async logging. Fire the audit event to NATS; do not wait for durable ack before returning to the agent.
  • Streaming pass-through. For tools that return streamed content, wrap the response, do not buffer it.

The async logging point is worth dwelling on because it is counter-intuitive from a durability perspective. The natural instinct is to write the audit log before returning a success response — if the log write fails, you know about it before the call proceeds. In practice, at the call volumes an active agent estate generates, synchronous logging adds 20–40 ms to every tool call. At fifteen tool calls per LLM turn, that is 300–600 ms of added latency per turn — enough to make agents feel unacceptably slow.

The right approach is to use a durable, ordered queue (NATS JetStream is the natural choice here) for async log delivery, with a consumer that writes to the audit store with at-least-once semantics. In the rare case of a queue delivery failure, the log is replayed — not dropped. Durability is preserved; hot-path latency is not taxed.

Handling adversarial inputs

One of the most important and underappreciated functions of the MCP gateway is protection against prompt injection. An agent reading a document, a web page, or an email may encounter adversarial content designed to hijack the agent's subsequent tool calls. The gateway is the last line of defence when the agent's reasoning has been compromised.

  • Argument content scanning. For destructive methods, scan the arguments for patterns that suggest the call was constructed from user-controlled content rather than agent reasoning.
  • Signed action manifests. For high-risk tool calls, require the caller to submit a signed intent alongside the call. The gateway checks that the intent was established before the potentially adversarial input was encountered.
  • Data-exfiltration pattern detection. A tool call that reads sensitive data and simultaneously writes to an external endpoint is a standard exfiltration pattern. The gateway can detect this across a session's call sequence even if each individual call appears legitimate.
  • Rate limits on destructive actions. An agent should not be calling `delete_file` thirty times in a minute unless something has gone very wrong. Rate-limiting destructive methods at the gateway catches compromised agents before significant damage occurs.

The 100 ms rule

If your gateway adds more than 100 ms to a tool call, agents will silently route around it. Enforce this in your service SLOs. TigerIdentity's gateway targets 15 ms p95 for cached decisions and 40 ms p95 for fresh policy evaluation.

The gateway as an identity graph input

A commonly missed architectural benefit of the MCP gateway is its role as a discovery and attribution signal. Every call that passes through the gateway is an observation about an agent's behaviour, resource footprint, and ownership chain. These observations feed the identity graph continuously — not just at provisioning time.

An agent that has never called the `database` MCP server starts calling it. The graph records the new edge. If it is unexpected — the agent's registered manifest does not include database access — the next evaluation of the agent's posture score will reflect it. The ownership attribution worker will notify the agent's registered owner. The TIDR module will log the deviation for review.

This feedback loop turns the gateway from a simple proxy into an active identity sensor. The longer it runs, the more accurate the identity graph becomes — because agent behaviour is continuously refined against the policy and the baseline.

What to standardise

  1. Agent identity spec. Every agent gets an internal ID that is separate from its OAuth client. Rotate OAuth without renaming.
  2. Tool call schema. Enforce that every tool call carries agent ID, session ID, and human-owner ID. Reject calls that omit them.
  3. Signed action manifests. For destructive tools, require the caller to submit a signed intent alongside the call. The gateway checks the intent before proxying.
  4. Escape hatch. A "dry-run" header that returns the policy decision without executing the call. Priceless during onboarding.
  5. A gateway health SLO. 99.9% uptime and p95 latency under 50 ms should be tracked in your primary observability dashboard alongside application SLOs. The gateway is infrastructure — treat it like infrastructure.

The dry-run header deserves special emphasis. When onboarding a new agent, being able to run it in dry-run mode — where every tool call is evaluated against policy and the decision is returned, but the call is not executed — gives teams a way to validate policy before granting live access. It eliminates the pattern of "let it run in prod and see what breaks," which is how shadow agents accumulate.

Build on continuous identity

See how TigerIdentity delivers NHI security, secrets governance, and AI agent control in one platform.