After MCP, the Harder Problem Is Tool Planning and the Execution Boundary

In the previous article, I put Codex CLI behind an API and built a common Agent Runtime that could be called from different surfaces such as Web, n8n, and Salesforce. The goal was not to automate a Coding Agent for its own sake. It was to shorten the Feedback Latency between an idea from the business and something that actually works.

Once the Runtime existed, the next step seemed natural. If Salesforce, databases, search, and external APIs were exposed as Tools, the Agent could choose the capabilities it needed. MCP, the Model Context Protocol, makes it much easier to expose those capabilities through a common interface.

But when I started thinking about connecting that structure to real business systems, another question appeared.

If an Agent can choose a Tool, should the Agent also receive the authority to execute it?

My conclusion was closer to no.

The Agent should decide what needs to be done. The Application and Runtime should decide whether it is actually allowed to happen.

The more MCP standardizes connectivity, the less this boundary should be treated as an implementation detail.

MCP Makes Tool Connectivity Easier

An Agent that works with external systems needs capabilities. It may need to retrieve customer information, search documents, perform calculations, or change the state of a business process.

MCP provides a common contract for connecting Tools, Resources, and Prompts to AI Applications. The MCP 2026-07-28 Specification expanded the protocol with a stateless core, header-based routing, authorization hardening, and an extension framework, making it easier to operate in production-oriented environments.

That direction is useful. Different Agents no longer need a new API wrapper for every capability. Tool input and output contracts can be reused, and the same interface can be combined with Gateways or Policy Layers.

But one distinction matters.

MCP
= A standardized interface between an Agent and a Capability

Execution Authority
= The decision about who may perform an actual Action, under which Context and permissions

The two are related, but they are not the same problem.

Stronger OAuth/OIDC-based Authorization in MCP does not decide whether a particular salesperson may change the Stage of a particular Opportunity, whether changing contract value requires approval, or whether the same request can safely be executed again after a Retry.

Those responsibilities still belong to the Application and the business system.

Architecture comparison showing MCP tool connectivity as separate from enterprise execution authority and policy enforcement
MCP standardizes access to capabilities, while user identity, record scope, approvals, retries, and execution authority remain inside a separate enterprise control boundary.

“Can Call” and “May Execute” Are Different Questions

Suppose an Agent has the following Tool.

update_opportunity

The user says, “Move this deal to the negotiation stage,” and the Agent produces these arguments.

{
  "opportunity_id": "006...",
  "stage": "Negotiation"
}

The Tool name is valid and the Parameters are structurally correct. From the LLM’s point of view, this looks executable.

From an Enterprise Application’s point of view, however, several questions remain.

  • Who is the current user? Source of truth: Application / Identity Provider.
  • Can this user view the Opportunity? Source of truth: Salesforce / Authorization.
  • Can this user change the Stage? Source of truth: Salesforce / Business Policy.
  • Is this the Record currently selected in the UI? Source of truth: Application.
  • Does the change require approval? Source of truth: Business Policy.
  • Is it safe to execute the same request again after a Retry? Source of truth: Runtime / Tool Contract.
  • Where should the result be recorded? Source of truth: Runtime / Audit Layer.

These are not problems that disappear simply because the LLM becomes more capable.

KEY TAKEAWAY. What the LLM lacks here is not Intelligence. It is Authority.

The Agent deciding that a Tool is appropriate and the system deciding that a user is authorized to perform the Action are different responsibilities.

That is why I find it safer and more extensible to treat a Tool Call as an Execution Proposal, rather than as an instruction that must be executed immediately.

Separate Tool Planning from Tool Execution

This separation does not reduce the role of the Agent. It makes the part that benefits from Agentic reasoning much clearer.

The Agent can interpret user Intent, decide what information is needed, choose the right Tool, and plan how several Tools should be used. If the result is incomplete, it can retrieve more evidence and propose the next Action based on what it found.

But the Tool Intent and proposed Arguments should not be sent directly to the external system.

User Request
    ↓
Application
    ↓
Agent Runtime
    ↓
LLM Reasoning / Planning
    ↓
Tool Intent + Proposed Arguments
    ↓
──────── Execution Boundary ────────
    ↓
Trusted Context Binding
Authorization
Policy Validation
Approval / Idempotency Check
    ↓
Deterministic Executor
    ↓
Salesforce / Azure / DB / API
    ↓
Evidence / Result
    ↓
Agent

In this structure, the Agent owns the Reasoning Plane, while the Runtime owns the Control Plane.

While the Agent determines what should be done, the Runtime determines whether the request can be executed in the current Context. The actual API call is then performed deterministically against a validated contract.

This preserves Agent autonomy where it is useful without making the execution surface equally autonomous.

Agent reasoning and tool planning separated from trusted context binding, authorization, policy validation, and deterministic execution
The Agent proposes Tool Intent and arguments; the Runtime binds trusted Context, validates policy and approval requirements, and executes through a deterministic Executor.

Runtime Context Is Not Something the Agent Should Infer

Runtime Context became especially important as I worked through this architecture.

Imagine that a user is looking at a specific Opportunity in Salesforce. The Application already knows the authenticated User and the current Record. The user’s Role, Tenant, and current Workspace can also be resolved by the Application or Backend.

Asking the Agent to discover those facts again is unnecessary.

{
  "input": "What is the first risk I should check on this deal?",
  "runtime_context": {
    "user_id": "005...",
    "record_id": "006...",
    "workspace_id": "deal-123",
    "allowed_scope": [
      "opportunity",
      "account",
      "proposal"
    ]
  }
}

I separate the two areas like this.

input
= Something the Agent should interpret and reason about

runtime_context
= Facts established and supplied by the Application

Identity, Tenant, Record Scope, and Authorization Scope can be used by the Agent, but the Agent should not be able to expand them on its own.

For example, the Agent may decide that it needs more information. But if allowed_scope currently contains opportunity, account, and proposal, the Agent should not be able to decide, “I will also inspect contract data this time,” and widen the Scope by itself.

The Agent chooses within the Boundary. The Application and Runtime own the Boundary itself.

Design Tools Around Business Meaning, Not Raw APIs

Separating the Execution Boundary also changes how I think about Tool Grain.

The easiest starting point is often to expose existing APIs or SDK functions directly.

run_soql()
get_record()
vector_search()
get_blob()
read_document()

Each Tool is simple in isolation. The downside is that the Agent now has to combine infrastructure primitives and effectively perform Application Logic.

If the Agent has to find an Account ID in Salesforce, load the relevant document list, select a Search Index, run a query, and filter the result every time it needs evidence for a deal, the Tools may be atomic, but the planning burden becomes large.

A business-oriented capability can be more natural.

search_deal_evidence()
retrieve_customer_context()
prepare_next_action_context()

I prefer to think of this as an Agentic-free but business-semantic Tool boundary.

Inside the Tool, authenticated Context, fixed Query Rules, Search scope, and validation can remain deterministic. The Agent only decides which business capability it needs.

The opposite extreme is also a problem.

analyze_everything_and_decide_next_action()

If a single Tool hides another opaque Agent Workflow, the boundary disappears again. If the Tool is too small, the Agent inherits Application Logic. If it is too large, the decision-making hidden inside the Tool becomes difficult to govern.

A useful Grain is one the Agent can choose by business meaning while the execution result remains predictable.

MCP Still Matters, but Its Role Becomes Clearer

This architecture is not an argument for bypassing MCP.

It is an argument for using MCP for a more precise responsibility.

MCP / Tool Contract
= Capability Interface

Agent
= Reasoning / Planning

Application
= Identity / Business Context

Runtime
= Policy / Validation / Control

Executor
= Actual Action

MCP Tool definitions include not only Input and Output Schemas but also Annotations that describe Tool behavior. Signals such as readOnlyHint, destructiveHint, idempotentHint, and openWorldHint can help a Client understand execution characteristics and risk.

But as the MCP Tool Annotations documentation emphasizes, these Annotations are still hints. A Client should not decide whether a Tool is safe to use only from Annotations supplied by an untrusted Server.

That distinction matters.

Tool Metadata
→ Information used for Planning and UX

Execution Policy
→ Enforced rules that allow or deny an actual Action

The same principle applies to stronger Authorization in newer MCP specifications. Protocol-level Authorization is important for establishing a trusted connection between Client and Server. It does not replace the business Policy that decides which Actions a specific user may perform on a specific business Record.

CAVEAT. Authentication and Authorization do not automatically create Business Execution Policy.

Read and Write Do Not Need the Same Tool Policy

Treating every Tool as if it had the same risk profile is inefficient.

For practical design, I find the following classification useful.

  • Read: Retrieve customer Context, documents, or search results. Default control: allow Agent autonomy within the permitted Scope.
  • Assist: Generate candidate Next Actions, summaries, or analysis. Default control: allow Agent execution and validate the result.
  • Mutation: Change an Opportunity Stage or business state. Default control: Policy Validation and approval where required.
  • High-impact: Change contracts or amounts, transmit data externally, or perform other sensitive Actions. Default control: stronger approval, Audit, and a constrained Executor.

This is not a replacement standard for MCP Annotations. It is an Application-level classification for designing Governance.

MCP Metadata such as readOnlyHint, destructiveHint, and idempotentHint can be useful inputs into that Policy, but final Enforcement should remain an explicit Runtime rule.

That makes the Execution Boundary more stable even as new Tools are added or the Agent itself changes.

Give the Agent Freedom, but Only Inside the Boundary

When designing Agentic Architecture, it is natural to want to give the Agent more Tools, more Context, and more autonomy.

In an Enterprise environment, however, the goal is not simply to maximize Agent freedom.

There is still plenty of judgment that can remain Agentic.

  • What information is needed?
  • Which Tool should be used first?
  • Should several Tools be called in parallel or in sequence?
  • Is the current Evidence sufficient?
  • Is more retrieval required?
  • How should the results be synthesized?

There are also facts and permissions the Agent should not be able to redefine.

  • Who am I?
  • Which Tenant and Customer Context do I belong to?
  • Which Record am I currently working from?
  • How far may I access?
  • Which Actions am I allowed to modify?
  • What can be executed without approval?

Separating these two categories keeps the Reasoning Agentic while keeping execution in the business system governed.

Responsibility model separating agent reasoning, application context, and runtime execution control in enterprise AI systems
The Agent owns reasoning and planning, the Application owns user and business Context, and the Runtime owns enforcement, validation, execution, and audit.

In the previous article, I tried to turn the recurring problem of rebuilding every new PoC into a problem of assembling against a shared Agent Runtime.

I applied the same principle inside that Runtime.

There is no reason to hard-code the decisions that LLMs are good at into Application code. But there is also no reason to make the LLM infer Identity, Context, and Permission that the Application already knows and is responsible for enforcing.

The structure I want is ultimately simple.

Agent
= Reasoning

MCP / Tool Contract
= Capability Interface

Application
= Context

Runtime
= Control

Executor
= Action

Before giving the Agent more things it can do, the more important question is how far it should be allowed to go.

A good Agentic Architecture is not one that delegates everything to the Agent. It is one that makes the delegation boundary explicit.