Policy · architecture
MCP Policy Engine: Governing Tool Access With Policy as Code
Allow and deny are not enough outcomes for a system where the caller decides what to do at runtime. The interesting decisions are transform, escalate and simulate — and none of them can be made by the thing being governed.
The short answer
An MCP policy engine is the component that decides, before execution, whether a tool call may proceed — given the calling identity, the tool, its parameters, the environment and the target. It must be deterministic, versioned and testable, and it needs more outcomes than allow and deny: dry-run and require approval both describe real decisions. Policy that lives in prompt text is not policy, because instructions in a prompt compete with instructions in retrieved content. Ten inputs, four outcomes, and a shadow mode so the first rule you ship is not also the first outage.
Why tool calls need their own policy layer
Traditional authorization answers a question fixed at build time: may this user call this endpoint. Every part of that question is known before the request exists, which is why role checks in application code work as well as they do.
An agent breaks the assumption. The caller decides which tool to invoke at runtime, from content it has just read, and it supplies the parameters. The same tool call is unremarkable at one parameter value and a serious incident at another. Nothing about that decision was known when the code was written, which means nothing about it can be encoded in the code.
So the decision has to happen at call time, at a point that sees the identity, the tool, the values and the context together — and outside the model, because the model is the component that can be persuaded. That point is a policy engine. AI gateway vs API gateway covers why an API gateway’s vocabulary does not stretch this far.
The ten inputs a decision needs
Fewer than these and some legitimate rule becomes inexpressible. We arrived at ten by repeatedly discovering that a rule a customer wanted could not be written.
| Input | Example rule it makes possible |
|---|---|
| Caller identity | Only the reconciliation agent may call ledger_adjust. |
| Roles and entitlements | Requires the payments-operator entitlement, resolved from the IdP. |
| Department or team | Support agents may refund; marketing agents may not. |
| Tool name and version | Deny a tool whose schema changed since the last review. |
| Parameter values | Refunds under 500 proceed; above that, a human decides. |
| Environment | The same rule set, stricter in production than in staging. |
| Target system and region | EU personal data may not route to a US instance. |
| Data classification present | Any payload containing PII gets output redaction applied. |
| Credential mode | Deny if the call arrives on a shared key rather than per-user OAuth. |
| Recent behaviour | Deny the eleventh identical write in a minute — a retry loop, not a decision. |
The last input is the one most engines lack and the one that catches the most real incidents. A single call can be perfectly legitimate while the eleventh identical call in sixty seconds is a runaway loop, and no stateless evaluation can tell those apart.
Four outcomes, not two
Binary outcomes force every conditional case into one of two wrong answers. Deny too much and teams route around the engine; allow too much and the engine is decoration. These four cover the space.
Allow
Proceed, and record it. The record is not optional — an allowed call with no evidence is indistinguishable afterwards from a call that never happened.
Deny
Refuse before execution, with a reason the agent can act on and a record the security team can query. A refusal with no reason produces a retry loop; a refusal with no record produces an unanswerable audit question.
Dry-run
Evaluate and return what would have happened without touching the target system. This is how a rule change gets tested against real traffic patterns, and how an agent can be developed against production-shaped policy safely.
Log the evaluation, not just the verdict. A rule that behaves differently in dry-run than in enforcement is a debugging problem six weeks later.
Require approval
Hold for a human decision, showing the tool, the parameters and the caller. Approval thresholds covers where to set the line so approvers do not become rubber stamps.
This is the outcome for cases where blocking is too blunt and allowing is too permissive — the cost of pausing a legitimate action is lower than the cost of an unreviewed one.
Deterministic, or it is not policy
One property matters more than the rule language, the deployment model or the performance envelope: the same inputs must always produce the same outcome. If they do not, the decision cannot be explained afterwards, cannot be tested before deployment, and cannot be defended to anybody who asks why a particular call was permitted.
This rules out the tempting design where the engine asks a model whether an action looks reasonable. That moves the judgement back inside the component being governed, and it makes every decision unreproducible — the same call at 09:00 and 09:01 can be decided differently, with no way to establish which was correct.
Determinism has a second payoff. It makes the engine testable as ordinary software: a table of input tuples and expected outcomes, run in CI, failing the build when a refactor quietly widens what an agent can reach. That test suite is also, incidentally, the clearest documentation of your governance posture that will ever exist.
Models are useful next to the engine — classifying data sensitivity, summarising a call for an approver, scoring anomaly likelihood as an input. They are not useful as the engine.
Policy as code, and what that actually requires
Policy as code is used loosely enough to be meaningless. Four properties make the term real; a system with three of them is configuration with better marketing.
Version controlled
Rules live in a repository with history, review and rollback. Who changed the refund ceiling, when, and who approved it — answerable by git log.
Testable offline
A rule set that can only be evaluated in production is a rule set nobody dares change. Local evaluation against fixture inputs is the difference between confident and frozen.
Environment-parameterised
One rule set, different thresholds per environment. Two separately maintained rule sets diverge, and they diverge in the direction of the less-reviewed one.
Deployable independently
Changing a threshold should not require redeploying an agent or a server. If it does, thresholds will not be tuned, and untuned thresholds get widened rather than adjusted.
Built on this thinking
Ten inputs, four outcomes, shipped
BarzelVault implements the four outcomes as its policy core — allow, deny, dry-run, require approval — with approval workflow and hash-chained audit behind them. Barzel Central Gateway supplies the ten policy inputs, including credential mode and target region, at the estate edge.
Shadow mode: the only safe way to ship the first rule
The first real policy rule is the dangerous one, because nobody yet knows what production traffic looks like. Deploy it enforcing and you find out by breaking a workflow at the worst moment; deploy it as a warning and it gets ignored.
Shadow mode is the third option: evaluate the rule against live traffic, log what it would have decided, enforce nothing. Run for a week and read the counterfactual. Every rule we have watched go into production this way needed adjusting, and roughly one in three would have refused something legitimate on day one.
The number to look at is not the refusal count but the refusal distribution. A rule that would have refused forty calls all from one agent in one hour is almost certainly correct and has found a loop. A rule that would have refused forty calls spread evenly across nine agents is almost certainly mis-specified.
Promotion criterion, stated up front: enforce when the counterfactual refusals for a full week are all explainable. Not zero — explainable.
Five mistakes worth naming
Policy in prompt text
Instructions in a system prompt compete with instructions in retrieved content, and no wording reliably wins. Prompt text is a preference; the engine is the control.
Tool-name rules with no parameter conditions
Permitting a tool approves its entire range, including the part nobody would have signed off on.
Rules with no owner
An unowned rule is never tuned, so it is eventually either bypassed or deleted during an incident.
No simulate outcome
Without it, testing a rule change means testing in production, so rule changes stop happening.
Engine off the call path
A policy engine agents can avoid governs the agents that chose to comply. Inline, and verified by attempting to bypass it.
Frequently asked questions
What is an MCP policy engine?
The component that decides, before execution, whether a tool call may proceed — given the calling identity, the tool, its parameters, the environment and the target system. It must be deterministic, versioned and testable, and it sits outside the model because the model is the part that can be persuaded.
What inputs does an MCP policy decision need?
Ten: caller identity, roles and entitlements, department or team, tool name and version, parameter values, environment, target system and region, data classification present in the payload, credential mode, and recent behaviour by that identity. The last one catches retry loops that no stateless evaluation can detect.
Why are allow and deny not enough outcomes?
Because most risky calls are risky in one respect only. Dry-run and require approval both describe real decisions. With only two outcomes, conditional cases resolve as over-blocking, which makes teams route around the engine, or over-allowing, which makes it decoration.
Why must a policy engine be deterministic?
Because a decision that cannot be reproduced cannot be explained afterwards, tested before deployment, or defended to anybody who asks why a call was permitted. Determinism also makes the rule set testable in CI, which is what stops a refactor quietly widening what an agent can reach.
Can a policy engine use a model to decide?
Not as the decision itself. Asking a model whether an action looks reasonable moves judgement back inside the component being governed and makes every outcome unreproducible. Models are useful next to the engine — classifying data sensitivity, summarising a call for an approver, scoring anomaly likelihood as an input.
What is shadow mode for MCP policy?
Running a rule against live traffic, logging what it would have decided, and enforcing nothing. Read the counterfactual for a week before promoting it. The useful signal is the distribution: forty refusals from one agent in one hour is a loop the rule caught; forty spread across nine agents means the rule is mis-specified.
What makes policy genuinely policy as code?
Four properties: version controlled with review and rollback, testable offline against fixture inputs, parameterised by environment from a single rule set, and deployable without redeploying agents or servers. A system with three of the four is configuration with better marketing.
Is a system prompt a form of policy?
No. Instructions in a system prompt compete with instructions arriving in retrieved content, and there is no wording that reliably wins. Enforcement has to sit outside the model, where an out-of-scope call is refused regardless of the reasoning that produced it.
Sources and further reading
The policy-decision-point model and policy-as-code practice are established and cited below. The ten-input list and the four outcomes are our own design, implemented in BarzelVault and the Central Gateway; treat them as a working scheme rather than a standard.
- 01 · CNCFOpen Policy Agent — documentation ↗Reference implementation of decoupled policy decisions and policy as code.
- 02 · NISTNIST SP 800-207 — Zero Trust Architecture ↗The policy decision point / policy enforcement point split this architecture borrows directly.
- 03 · MCP projectModel Context Protocol — specification ↗Normative source for tool schemas, capability negotiation and the authorization model.
- 04 · OWASP GenAI Security ProjectOWASP GenAI LLM Top 10 (2026) ↗Consensus risk list; excessive agency and prompt injection are the entries governance exists to bound.
- 05 · NISTNIST SP 800-53 Rev. 5 ↗Access control and audit control families that MCP-layer controls have to satisfy.
- 06 · OWASPOWASP Application Security Verification Standard ↗Input-validation, authorization and logging requirements restated here in MCP terms.
- 07 · ISOISO/IEC 42001 — AI management systems ↗The management-system standard auditors increasingly map AI governance evidence against.
- 08 · NISTNIST AI Risk Management Framework ↗Govern-map-measure-manage; the vocabulary most enterprise AI risk programmes are written against.
Last reviewed 24 August 2026. External links open in a new tab; we do not control their content.
Try the mechanics on a live server
To watch a real tools/list response before you point a client at anything that governs production — Barzel Scripture Intelligence is free and public at scripture-intelligence-server.mcpize.run: no signup, no key, 54 tools. Setup is in the reference.
Buy it on the marketplace
BarzelVault is the pre-execution decision point, sold as a running product
Nine tools, 12 static resources, 3 resource templates and 9 prompts. Four deterministic policy outcomes — allow, deny, dry-run, require approval — with approval workflow, hash-chained audit and guardrail data protection. Streamable HTTP, JSON-RPC 2.0.
Sold on the MCPize marketplace · prices as listed 2 Sep 2026 · the listing is authoritative
Written by
Mark Alex
Founder of Real Biz Digital and architect of the Barzel ecosystem — five MCP servers published and callable in public. Software developer, technology entrepreneur and mechatronics engineer, working across AI agent governance, MCP security, AI infrastructure, FinOps and intelligent operations.