A pattern keeps showing up in conversations with teams shipping agents this year. They adopt the Model Context Protocol, wire their agent to an MCP server, watch it discover tools and call them cleanly — and quietly check the box marked agent integration: done. The protocol is good. The wiring is fast. It feels finished.
Then a security review asks a question the wiring can’t answer: when this agent calls the tool that moves money, what stops it from moving the wrong amount, to the wrong place, at the wrong time?
That question got louder in May, when the NSA’s AI Security Center published its first security guidance for MCP. It’s worth reading closely, because almost every recommendation describes something the protocol itself was never built to do. Least-privilege tokens scoped per action and per tool. Auditability of what an agent invoked and why. Governed handling of third-party integrations. These aren’t protocol features waiting to be turned on. They’re a governing layer that has to be wrapped around the protocol — and the guidance is, in effect, a description of the layer most teams haven’t built yet.
A protocol standardizes the call. It doesn’t judge it.
It helps to be precise about what MCP actually is, because the precision is the whole argument.
MCP standardizes how a capability is described and invoked. It gives an agent a uniform way to discover what tools exist, read their schemas, and call them — the same way regardless of who built the tool. That is genuinely valuable. It is the reason an agent that already speaks MCP needs no vendor-specific code to start working. A good protocol removes a category of glue, and MCP removes a real one.
But a protocol that standardizes how to invoke a capability says nothing, by design, about whether a given invocation should be allowed. Those are different questions, at different layers. HTTP standardized how to make a request; it never decided which requests your application should honor. TCP moved bytes reliably; it had no opinion about what the bytes meant. Every protocol that became load-bearing did so precisely by not trying to answer the question one layer up.
MCP is in exactly that lineage. It is the socket. It is not the fuse box.
A protocol that standardizes how to invoke a capability says nothing, by design, about whether a given invocation should be allowed.
“But the tool list is already scoped per agent”
The strongest objection comes from people who know MCP well, so it’s worth taking seriously rather than waving past.
A well-built MCP server already does real security work. It can authenticate every request. It can filter the tool list per agent, so a capability outside an agent’s scope doesn’t even appear in its tools — which is a security property, not just an ergonomic one, because an agent can’t reason about or invoke a tool it can’t see. It can embed risk metadata and annotations in the tool description. If you’ve built that, haven’t you governed the action?
You’ve governed access. You’ve answered which tools may this agent reach for. That’s the first axis of the problem, and it’s necessary. It is not the same as governing the action.
Scoping a tool per agent is a static, ahead-of-time decision: this agent’s scope grants finance.send.invoice, that one’s does not. But an agent’s entire job is to do many different things with the same capability. The same agent that should be cleared to send a $200 invoice should be stopped on a $200,000 one. The same messaging.send.message that’s fine to an internal address is a different proposition to an external domain. None of that is decidable from the tool list. It’s decidable only from the contents of the specific call — and the contents arrive at invocation time, after scoping is long settled.
Governing the action is a per-intent decision
This is where the protocol layer ends and the governing layer has to begin. And it’s why, at Formael, MCP is the front door but never the decision.
We expose each organization’s installed capabilities as standard MCP tools, scope-filtered per agent, with risk metadata carried in the tool description and annotations. An agent that speaks MCP talks to us with no Formael-specific code. So far, that’s the protocol doing its job.
{
"name": "finance.send.invoice",
"description": "Send an invoice to a counterparty.",
"inputSchema": {
"type": "object",
"properties": {
"counterparty": { "type": "string" },
"amount": { "type": "object" /* { value, currency } */ }
},
"required": ["counterparty", "amount"]
},
"annotations": {
"destructiveHint": true,
"idempotentHint": true,
"x-formael-risk-score": 0.72,
"x-formael-hitl-default": "approval_above_threshold",
"x-formael-required-scope": "finance"
// Risk metadata travels with the tool. It informs the agent.
// It does not decide. The decision happens after the call, on the call’s contents.
}
}The moment that tool is called, the invocation stops being a protocol event and becomes an intent. The MCP tools/call translates into an IntentEnvelope and runs the same pipeline every action runs — REST or MCP, no difference, no fast path. Before anything executes, the four-axis policy engine evaluates the specific intent on its contents:
The verdict is the conjunction of all four axes — every one must pass, and no axis compensates for another’s failure. Identity: may this agent invoke this, in this context, in this time window? Semantic: read from the typed slots of the call itself — is this recipient external, is this amount above the threshold, is this content allowed? Fiscal: can the organization and this agent afford the consequence, against a real ledger of the value being moved? Risk: how reversible, how visible, how precedented is this exact action — and does it cross the line that demands a human?
Only on an approving verdict does the Vault expose a credential to the connector and the call go out. The agent never held that credential. The agent never named the provider. It expressed an intent; the boundary decided. That decision is the thing MCP, correctly, leaves to the layer above it.
MCP, on its own
- Standardizes how tools are described and called
- Scopes which tools an agent can reach (by agent scope, ahead of time)
- Carries risk metadata that informs the agent
- No verdict on a specific call’s contents
MCP behind the boundary
- Same protocol, same agent code — the front door
- Every call becomes an intent on one pipeline
- Four-axis verdict on the contents, before execution
- Credentials stay in the Vault; the trace is append-only
Why this is the durable shape, not a Formael preference
It would be easy to read this as a vendor saying our layer is the missing piece. The deeper point survives without us in the picture.
The reason the NSA guidance reads like a checklist of things to build around the protocol — and the reason this year’s findings keep surfacing exposed, unauthenticated MCP servers, with one audit’s count of zero-auth servers nearly tripling in a year, to more than 1,400 — is that a protocol and a policy are different objects with different jobs. A protocol earns adoption by being neutral about meaning. A policy earns trust by being opinionated about it. Asking MCP to govern actions would make it a worse protocol, the way asking TCP to enforce business rules would have made it a worse transport. The right answer was never to bend the protocol. It was to put a governing layer in the one place every action already passes through.
That layer is the boundary between an agent and the systems it acts on. MCP is how the agent reaches the boundary. It is not the boundary itself — and the difference between those two sentences is the difference between an agent that works in a demo and one you can run in production.
Key takeaways
- MCP standardizes how capabilities are described and invoked. By design, it doesn’t decide whether a given invocation should be allowed.
- Scoping tools per agent governs access. Governing the action means a per-intent verdict on the contents of the specific call.
- Use MCP as the front door; put the four-axis decision behind it, on the one pipeline every action passes through.