An agent discovers an MCP tool, produces arguments that match its schema, and sends a valid tools/call request.
Has the business action now been executed safely?
For a read-only demo, that distinction may not matter much. It matters immediately when the tool can create a refund, change inventory, disable an account, send a customer notification, or trigger a deployment.
In those cases, a valid tool call is only one event in a longer business-action lifecycle.
Short answer: MCP can standardize tool discovery and invocation. Safe business execution remains an end-to-end property shared across the MCP server, agent runtime, execution controls, enterprise policy systems, and the authoritative business system.
The missing work usually includes:
- resolving the trusted acting subject;
- limiting which capabilities the agent may reach;
- deciding whether human approval is required;
- binding that approval to the exact request;
- preventing duplicate effects;
- handling retries and unknown outcomes;
- producing verifiable audit evidence;
- recovering from partial failure;
- performing final object-level and business-state authorization.
The difficult question is not whether these controls are useful. It is where each responsibility belongs.
A valid tools/call is not business completion
MCP already provides substantial foundations. A server can expose tool names, descriptions, input and output schemas, annotations, and execution-related metadata. A client can discover those tools and invoke them through a common protocol.
MCP also specifies authorization for HTTP transports and publishes security guidance around access control, token handling, scope minimization, session binding, sandboxing, timeouts, confirmation, and audit logging.
So this is not an argument that MCP "forgot security."
It is a distinction between two different outcomes:
Protocol success:
A valid request reached an authorized MCP server.
Business completion:
The intended action was executed once, for the right subject,
against the right object, under current business rules,
with the required approval, evidence, and recovery behavior.
A protocol can carry an action. It cannot independently know whether order ORD-9001 is still refundable, whether employee E-1024 may act for store S-18, whether the requested amount exceeds the remaining refundable balance, or whether another refund has already completed.
Those facts live closer to the business domain and change over time.
Five responsibilities, even when they share one process
Production architectures become easier to reason about when we separate five responsibilities.
| Layer | Primary responsibility | It must not be mistaken for |
|---|---|---|
| Tool protocol and MCP server | Tool discovery, schemas, invocation, protocol authorization, and the tool execution interface | Final authorization for every downstream business object |
| Agent runtime or orchestrator | Interpret the task, select tools, generate arguments, maintain workflow state, and present human interaction | A trusted source of business identity or final permission |
| Shared execution control | Restrict reachable capabilities, validate trusted context, bind approvals, coordinate dispatch, deduplicate requests, and retain traceable task state | The enterprise identity provider, approval authority, transaction coordinator, or business policy owner |
| Enterprise identity, policy, and approval systems | Resolve trusted identities, organization-specific policy, and who may approve which action | The business operation itself |
| Business system | Enforce tenant boundaries, object-level authorization, current state, business invariants, transactions, and the final decision to execute | A passive backend that trusts upstream claims blindly |
These rows do not require five deployments. One service may implement several of them.
The separation is semantic. Security claims should follow responsibility, not topology.
"Permission" is really three decisions
Architecture discussions often use permission as though it were one check. In an agent-to-business path, it usually hides at least three.
1. Can the client access this MCP server?
This is protocol authorization: OAuth scopes, audience validation, token expiry, and protected-resource metadata.
2. Should this capability be reachable in this agent scenario?
A customer-support agent may need order.read and refund.request.create without ever seeing employee.delete or tenant.config.update.
This is a reach decision. It reduces the maximum capability surface before model selection and argument generation can cause harm.
3. Can this subject perform this exact action on this object now?
This is final business authority:
- Does the employee belong to the relevant tenant or store?
- Is the order currently refundable?
- Is the amount within the remaining refundable balance?
- Has another refund already completed?
- Does current organization policy permit the action?
Only the business system, or an authority with equivalent fresh business context, can answer these questions reliably.
MCP authorization
-> Can this client access the server?
Capability reach
-> Can this agent scenario reach this operation?
Business authority
-> Can this subject perform this exact action now?
A valid MCP token is not an order-level refund decision. A capability allowlist is not tenant isolation. A successful business permission check does not remove the value of minimizing which tools the model can reach.
Where do the cross-cutting controls belong?
Human approval
The agent runtime may be the best place to present an approval screen. A shared execution layer can pause dispatch and bind the decision to a canonical request. An enterprise approval system decides who is qualified to approve. The business system still performs final authorization immediately before changing state.
A useful approval binding includes at least:
trusted subject + capability + canonical arguments + task identity
If any of those values change, the previous approval must not silently authorize the new request.
Approval UI is therefore not the approval boundary by itself. The evidence must be bound to what will execute, and the verifier must know which authority produced it.
Idempotency and duplicate prevention
The runtime should preserve a stable request identity across retries. A shared execution layer can deduplicate submissions and retain task state. The business system must enforce domain-level uniqueness where duplicate effects would be harmful.
For a refund, an execution layer can prevent one task from being dispatched twice. Only the payment or order domain can guarantee that the same business refund is not created through another path.
Retries and unknown outcomes
Blind HTTP retry is unsafe for writes because a missing response does not prove that the action did not happen.
A stateful task protocol should distinguish states such as:
accepted -> awaiting_approval -> queued -> running -> succeeded
\-> rejected
\-> failed
After a timeout, the caller should query or resume the same task identity instead of inventing a new business request. Retry policy belongs near execution coordination, but retry safety depends on idempotency all the way to the business boundary.
Audit and evidence
Application logs answer operational questions. An audit trail answers accountability questions:
- Who requested the action?
- Which trusted subject did the agent represent?
- Which capability and arguments were evaluated?
- Which policy or approval decision affected execution?
- What was dispatched, by whom, and when?
- What did the business system finally accept or reject?
If one compromised runtime can both claim that approval happened and author the only audit record, the record is a self-report. Higher-assurance deployments may need independently signed approval evidence, append-only storage, or verification at the business boundary.
A shared control layer can make evidence consistent. Calling its own log an "audit trail" does not make every assertion independently trustworthy.
Rollback and recovery
Rollback is not a generic middleware feature.
Some actions are reversible. Some require compensating operations. Some cannot be undone. Recovery semantics belong to the business operation or to a workflow/Saga layer that understands the domain.
An execution layer can retain state, expose failure, and trigger an explicitly defined compensation path. It must not manufacture atomicity by labeling unrelated tool calls "atomic."
A minimal refund path
Consider an agent asked to refund an order:
1. A user requests a refund.
2. The agent runtime selects refund.create and proposes arguments.
3. The MCP client invokes the trusted server using protocol authorization.
4. Execution control verifies that refund.create is reachable for this route.
5. Trusted subject context is resolved outside model-generated arguments.
6. Request schema and governance conditions are evaluated.
7. If approval is required, execution pauses on an exact parameter snapshot.
8. The same task resumes with verifiable approval evidence.
9. Dispatch uses a stable idempotency identity.
10. The business system rechecks subject, tenant, order state, amount, and invariants.
11. The business system commits or rejects the action.
12. The result and evidence chain are recorded against the same task.
There is no single "agent security check" in this sequence.
The model proposes an action. The protocol carries it. The runtime coordinates it. Enterprise systems establish identity and policy. The business system authorizes and commits the final consequence.
Do you need a shared execution layer?
Not always.
A single-user local tool, a read-only utility, or an application with one runtime and a few low-consequence operations may keep these controls inside its MCP server or host application.
A shared execution boundary becomes more useful when:
- multiple agent frameworks or MCP clients call the same business systems;
- many MCP servers repeat approval, idempotency, and audit logic;
- the organization needs one capability allowlist across channels;
- work must pause and resume across human approval or local executors;
- execution state must survive process restarts;
- governance evidence must be comparable across tools;
- business credentials should not be distributed to every agent application.
The architectural test is not "Are we using agents?"
It is:
Are the same execution guarantees being reimplemented in enough places that a shared control boundary would reduce inconsistency and blast radius?
Even then, the shared layer should remain deliberately limited. It coordinates and enforces common controls. It does not become the source of every identity, policy, transaction, or business truth.
Make failures explicit
The following table is more useful than a general claim that a platform "supports governance."
| Failure | Conservative behavior |
|---|---|
| Trusted subject is missing or unverifiable | Do not dispatch a subject-required action |
| Tool metadata or governance declaration is untrusted | Do not elevate privileges based on it |
| Approval evidence does not match the exact request | Reject it or require new approval |
| Execution state is unknown after timeout | Query the same task; do not create a fresh write blindly |
| Idempotency identity is missing for a retryable write | Refuse automatic retry |
| Business authorization fails | Return a final rejection; upstream approval does not override it |
| Audit sink is unavailable | Follow an explicit fail-open or fail-closed policy; never pretend evidence was persisted |
| Compensation is undefined | Report an irreversible or manual-recovery state; do not claim rollback support |
These behaviors make the architecture testable.
Disclosure: where ACC and BailingHub fit
I maintain two open-source efforts that explore parts of this problem.
Agent Capability Contract (ACC) experiments with a portable, operation-level declaration of capability reach and governance intent. It does not execute tools, define enterprise identity, or replace final business authorization.
BailingHub experiments with a self-hosted execution control plane for reach restrictions, trusted-subject handling, approval binding, task state, dispatch, and traceability around business tool calls.
They are concrete design experiments, not the only answer. The broader responsibility map does not depend on either project. The same boundaries can be implemented inside an MCP server, an agent platform, an API gateway, a workflow engine, a shared control plane, or a combination of them.
What matters is whether the architecture can answer:
- Which component controls tool reach?
- Where does trusted subject identity come from?
- Who decides that approval is required, and who is qualified to approve?
- What exact request did the approval authorize?
- How are retries tied to stable idempotency?
- Which component records evidence, and who can independently verify it?
- Which system performs final object-level and business-state authorization?
- What happens when execution is partial, unknown, rejected, or irreversible?
MCP makes tool interoperability practical. Safe business execution is the end-to-end property that must be constructed around the call.
Where do approval binding, idempotency state, and audit evidence live in your MCP stack today, and which component can independently verify them?
Top comments (0)