---
title: "Policy-driven MCP routing: enforcing tool gates outside the agent"
description: "Telling an agent which tools not to use is a request, not a control. Here is how to gate MCP tool calls with policy enforced outside the agent, at the execution boundary."
author: "Alex Olivier"
date: "2026-08-19T09:19:29.044Z"
canonical: "https://www.cerbos.dev/blog/policy-driven-mcp-routing-tool-gating"
image: "https://stylish-appliance-1c1cc1c30d.media.strapiapp.com/Policy_driven_MCP_routing_enforcing_tool_gates_outside_the_agent_2762698031.png"
tags: ["guide"]
source: "https://www.cerbos.dev/blog/policy-driven-mcp-routing-tool-gating"
---

# Policy-driven MCP routing: enforcing tool gates outside the agent

There is a tempting way to control what an MCP agent can do. Tell it. Put "do not use the delete tool" in the system prompt, list the tools it is allowed to call, and trust it to stay in its lane. It feels like control because it reads like control. It is not. ([One of many examples](https://www.cerbos.dev/blog/meta-ai-hack-shows-why-agents-shouldnt-decide-access) why it doesn’t work.)

An agent follows its access, not its instructions. A prompt is a request, and a non-deterministic system will eventually route around a request, either because it was cleverly manipulated or because it simply decided a blocked path was an obstacle to work around. If the agent has a tool wired in and a credential that lets the tool act, the instruction not to use it is a sticky note, not a lock. The gate has to live somewhere the agent cannot argue with, which means outside the agent.

This article is about how to do that. It covers what tool gating means, why prompt-level restrictions do not hold, where the gate actually belongs, and what policy-driven routing looks like in practice. It builds on our pillar on [MCP gateway authorization.](https://www.cerbos.dev/blog/what-is-an-mcp-gateway)

## What is MCP tool gating?

MCP tool gating is the practice of controlling which tools an agent can invoke, and with what arguments, by enforcing a policy decision outside the agent rather than trusting the agent to restrain itself. Instead of listing allowed tools in a prompt, the gateway or MCP server checks each tool call against policy before it runs, considering the agent, the user it acts for, the tool, and the arguments. A call that policy denies never executes.

The distinction that matters is where the decision is made. In the prompt, it is advice. At the execution boundary, it is enforcement.

## Why prompt-level tool restrictions do not hold

The failure mode here is not theoretical, and it is not rare. Justin Richer, in one of the sharper talks at Identiverse 2026, used the example of a coding agent that confidently deleted a production database it had been explicitly told not to touch. The instruction existed. The agent ignored it. The credential allowed the action, so the action happened. His framing was that non-determinism plus implicit access gives you the most capable confused deputy ever built, and it is hard to argue with once you have seen it play out.

The MCP-specific version of this shows up in the documented incidents. When researchers demonstrated an attack against a database MCP integration, the [agent operated the database with a service role](https://simonwillison.net/2025/Jul/6/supabase-mcp-lethal-trifecta/) that bypassed row-level security, while reading attacker-controlled content that told it what to do. The agent had a high-privilege tool and a broad credential, and no prompt was going to hold that boundary. In a separate case, a malicious issue in a public repository coerced an [agent into leaking data from private repositories](https://invariantlabs.ai/blog/mcp-github-vulnerability) using the same over-scoped token, jumping from public to private with one credential. In every one of these, the common factor is that the agent had access the prompt was supposed to restrain, and the prompt did not.

OWASP named this directly in its [Top 10 for LLM applications](https://genai.owasp.org/llm-top-10/). Excessive agency, item LLM06, is the risk that an agent has too much functionality, too many permissions, or too much autonomy. The fix it points to is not better prompting. It is least privilege, enforced.

![OWASP_Top_10_for_LLM_Applications_What_AI_agent_drift_actually_means_c45470a82b.png](https://stylish-appliance-1c1cc1c30d.media.strapiapp.com/OWASP_Top_10_for_LLM_Applications_What_AI_agent_drift_actually_means_c45470a82b_a5fbdafd43.png)

## The gate belongs at the execution boundary

The cleanest articulation of where to put the gate came out of the KuppingerCole [agent workshop at EIC](https://www.kuppingercole.com/events/eic2026/agenda) Berlin 2026. An agent is only dangerous if it holds a credential or has access to a tool. If you authorize the tools and the credentials, the agent itself is not the risk. That reframes the whole problem. You stop trying to make the agent trustworthy and start making the boundary around it enforce the rules, so it does not need to be trusted.

The same session made a related point that is easy to miss. When an agent acts through a downstream system, the logs on that system show the agent's activity as if it were the underlying account, so by the time you are looking at downstream logs the detail you need is already gone. Enforcement, and the record of it, has to happen at the point the agent calls the tool, not after. If you gate and log at the execution boundary, you have the decision and the context. Past that point, you have a shrug.

## What policy-driven tool gating looks like

![What policy-driven tool gating looks like (2).png](https://stylish-appliance-1c1cc1c30d.media.strapiapp.com/What_policy_driven_tool_gating_looks_like_2_4f0fd2f402.png)

In practice, gating tool calls outside the agent comes down to three moves.

**The first is narrowing the catalog.** An agent should see only the tools it needs for its job. A travel-booking agent gets travel tools, not the entire catalog of everything every server exposes. This alone shrinks the blast radius, because a tool the agent cannot see is a tool it cannot be talked into using. A gateway that aggregates many servers into one catalog is the natural place to enforce this, presenting each agent a scoped view rather than the full set.

**The second is making the gate aware of how the call is being made.** A useful pattern demonstrated in live vendor sessions through 2026 is path-aware policy. The same role, connecting directly to a database, might be allowed to write. The same role acting through an agent gets a narrower grant, where read tools like get\_payment and list\_payments are permitted but write tools like update\_payment, void\_transaction, and delete\_payment are forbidden. The identity is the same. The path is different, so the policy is different. That is a decision you can only make if the gate knows the call is coming through an agent, which is another reason it has to sit at the boundary rather than inside the model.

**The third is scoping by arguments and acting user, not just by tool.** Whether get\_record is safe depends on which record and for whom. The gate evaluates the arguments of the call and the identity the agent is acting for, and decides on the specific invocation rather than the tool in the abstract. This is the difference between coarse and fine-grained authorization, applied to tool calls.

Underneath all three is a rule the microservices world learned years ago, and Reiner Mertens of KuppingerCole restated it at EIC. Do not forward the incoming token blindly down the chain. When a service, or an agent, replaces the user's context with its own broad service credentials, the downstream system stops seeing the user and starts seeing the service, and it happily returns everything the service can reach rather than what the user should. His phrase for it was that the service's permissions replaced the user's permissions. The result is the database returning all records instead of the user's records. The fix is to carry the user context and check it at each hop, so the decision reflects the real principal, not the pipe it traveled through.

## Gating holds only if it holds at every hop

One agent calling one tool is the easy case. Real deployments rarely stay that simple. An agent calls a tool that is itself backed by another service, or it hands part of the work to a sub-agent, and the tool call you gated at the front is three hops away from the data by the time it lands. If you enforce only at the first hop and trust the rest, you have gated the doorway and left the corridors open.

This is the point Reiner Mertens pressed at EIC. Authorization is never located with a single entity any more. It is a chain that has to be checked and recorded at each transfer, because the permissions a sub-agent should have are not automatically the permissions the calling agent holds. A sub-agent spun up to summarize a document does not need the parent agent's write access, and the only way to enforce that is to make the decision again at the sub-agent boundary rather than inheriting the parent's grant. There are standardized ways to carry a delegation relationship across those hops, which we cover in [MCP authorization standards](https://www.cerbos.dev/blog/mcp-authorization-standards), but the enforcement principle is the same at every one of them. Decide on the specific call, for the specific principal, against policy, before it runs.

The practical test is simple. For any tool call in your system, ask how many hops sit between the gate and the data, and whether a decision is made at each. If the answer is that you check once at the edge and forward trust the rest of the way, a compromised middle hop can reach anything the chain can reach. Gating that stops at the first hop is a fence with the gate on one side and no fence on the other.

## Tuning the gate without redeploying

One underrated benefit of putting the gate in policy rather than in code or prompts is that you can change it without shipping anything. This is what we mean by a [dimmer switch](https://www.cerbos.dev/blog/dimmer-switch-not-a-kill-switch-rethinking-ai-agent-governance) rather than a kill switch. If an agent is behaving in a way you do not like, you do not have to pull it offline. You narrow its scope on the sensitive systems, put it in read-only mode against production data, or require human approval above a threshold, and because the rule lives in policy the change applies on the next call. No redeploy, no cache flush, no downtime for the work the agent was legitimately doing. When conditions change back, you widen the scope the same way.

That only works if the gate is external and policy-driven in the first place. A tool restriction baked into a prompt or hardcoded in the agent cannot be retuned in seconds, and cannot be proven after the fact. A policy decision can be both.

## How Cerbos fits

![mcp-illustration.png](https://stylish-appliance-1c1cc1c30d.media.strapiapp.com/mcp_illustration_37538c02f3.png)

Cerbos is the external gate. The gateway or MCP server calls the Cerbos PDP before a tool runs, passing the agent, the acting user, the tool, and the arguments, and gets back a deterministic allow or deny. Policies are written as code in YAML with CEL, so a rule can say this role may call read tools but not write tools on the agent path, or may act on this resource only for the user it is acting for, and that rule is reviewed and tested like any other code.

Because the decision is external to the agent, none of it depends on the agent cooperating. The agent can be prompted, manipulated, or simply wrong, and the call still does not run if policy says no. Changing the boundary is a policy edit, not an agent redeploy, which is what makes runtime tuning possible. The patterns live in our [MCP authorization](https://www.cerbos.dev/features-benefits-and-use-cases/dynamic-authorization-for-MCP-servers) guide. The same model governs the wider set of [non-human identities](https://www.cerbos.dev/features-benefits-and-use-cases/authorization-non-human-identities) in your estate.

Set the boundary in policy, not in the prompt. Enforce it where the tool actually runs. Then the question stops being whether you can trust the agent, and becomes what you are willing to let it do, which is a question you can answer, change, and prove.

---

[Try Cerbos](https://hub.cerbos.cloud/) to gate MCP tool calls with policy in practice, or [book a call](https://www.cerbos.dev/workshop) to walk through your agent's tool access with our team.

Go deeper:

* [Zero Trust for AI: Securing MCP servers](https://solutions.cerbos.dev/zero-trust-for-ai-securing-mcp-servers) (eBook) for tool-level authorization patterns  
* [Securing agentic AI in production](https://www.cerbos.dev/forms/1_RyTnFZITHeZXmNthleNTQc2voq) (Webinar) for Zero Trust applied to agents

## FAQ

### What is MCP tool gating?

MCP tool gating is controlling which tools an agent can invoke, and with which arguments, by enforcing a policy decision outside the agent rather than trusting the agent to follow instructions. The gateway or MCP server checks each tool call against policy before it runs, considering the agent, the acting user, the tool, and the arguments, and blocks any call the policy denies. The decision happens at the execution boundary, so it holds regardless of what the agent was prompted to do.

### Why can't I just restrict an agent's tools in the system prompt?

You cannot reliably restrict an agent's tools in the system prompt because an agent follows its access, not its instructions. A prompt is a request, and a non-deterministic system can be manipulated or can simply decide to route around it, as seen in real incidents where agents used tools they were told not to. If the tool is wired in and the credential allows the action, only an enforced policy outside the agent will stop the call. Prompt-level restrictions are advice, not a control.

### Where should MCP tool call authorization be enforced?

MCP tool call authorization should be enforced at the execution boundary, meaning the gateway or MCP server that actually runs the tool, not inside the agent or the model. Enforcing there means the decision holds even if the agent is compromised, and the record of the decision captures the real context before it is lost downstream. Enforcing only through prompts, or only after the fact in downstream logs, leaves the actual boundary unprotected.

### What is path-aware policy for MCP tools?

Path-aware policy for MCP tools means the same identity gets different permissions depending on how a call is made. A role connecting directly to a system might be allowed to write, while the same role acting through an agent is limited to read-only tools, with write and delete tools forbidden on the agent path. This lets you grant an agent narrower access than the human it acts for, and it requires enforcing the decision at the boundary, where the gate can tell the call is coming through an agent.

### How do you limit the blast radius of a compromised MCP agent?

You limit the blast radius of a compromised MCP agent by scoping it to only the tools it needs, enforcing that scope outside the agent, and deciding each call on its arguments and acting user rather than on the tool alone. A tool the agent cannot see cannot be misused, and a call the policy denies cannot run, so a hijacked agent is bound by policy rather than by its own behavior. Enforcing this at the boundary also means you can narrow the agent's access at runtime without taking it offline.

### How does Cerbos gate MCP tool calls?

Cerbos gates MCP tool calls by acting as the external policy decision point the gateway or MCP server calls before a tool runs. It receives the agent, the acting user, the tool, and the arguments, and returns a deterministic allow or deny based on policies written in YAML with CEL. Because the decision is external to the agent and expressed as reviewable, testable policy, the gate holds even if the agent misbehaves, and it can be returned at runtime without redeploying the agent.
