October 17, 2026·22 min read·engineeringmcpagentsinterfacesreliability

MCP and the execution contracts agents need

MCP standardizes access to platform capabilities. Efficient and reliable agent interfaces also need explicit workflow semantics, bounded data exchange, and recovery behavior that survives a lost response.

I want a platform interface to give an agent enough information to choose an operation, then let software execute the operation under explicit rules. Pagination, data aggregation, and recovery after a lost response should have implementations that I can inspect and test. Requiring the model to reconstruct those rules during each task introduces work that the platform could already define.

It is often assumed that the Model Context Protocol is fundamentally token-inefficient. However, a closer examination supports a slightly narrower conclusion. MCP permits interfaces that consume excessive context, but it also supports interfaces that avoid those costs. Its compatibility requirements do not establish whether an agent can use an integration efficiently or recover a mutation reliably.

Platforms should define agent-facing execution contracts with explicit workflow semantics, bounded data exchange, and documented recovery behavior. CLIs and SDKs can make those contracts directly executable. MCP can expose the same capabilities, but protocol compatibility is insufficient evidence of an effective agent interface.

The distinction matters when a platform decides what to build. Publishing an MCP server answers how a compatible application can discover and invoke its tools. It leaves open whether those tools express useful work, return appropriate information, or preserve the identity of an operation after a failure. Those questions need their own design and verification.

What MCP originally standardized

Anthropic announced MCP on November 25, 2024, with SDKs, local server support in Claude Desktop, and example integrations. Its stated problem was fragmented connectivity. Each combination of an AI application and an external system otherwise needed its own integration.

A shared protocol offers a practical benefit. A platform can implement one server that multiple compatible applications can use. An application can support a common client mechanism instead of a separate connector for every platform. That reduces duplicated integration work even if the application still needs to decide how to present each capability to its model.

The initial specification, dated November 5, 2024, acknowledged inspiration from the Language Server Protocol. The comparison helps explain its purpose. A common way to connect software components does not require those components to expose identical domain behavior. A release-management platform and a payment platform can speak the same protocol while offering very different operations.

The original architecture separated the host application, its protocol clients, and the servers providing capabilities. Clients maintained stateful sessions and negotiated supported features. Servers exposed resources, prompts, and tools. The host coordinated model interaction and managed context aggregation.

That assignment of responsibility is important to the token argument. The server's response and the model's input are different things. Software in the host can inspect a response, retain it outside the conversation, transform it, or pass it to another operation. The fact that data arrived through MCP does not require every byte to enter inference.

The architecture also places substantial responsibility on the host. A server can offer a capability without knowing how much of its definition or output an application will expose to a model. Interoperability therefore does not produce a uniform context policy. Two hosts using the same server can have different token consumption for the same task.

The protocol has changed beyond its original design

There are five dated specification revisions relevant to this history, beginning with 2024-11-05. They changed both the connection lifecycle and the mechanisms available for building agent interfaces.

The March 2025 revision introduced Streamable HTTP and an OAuth-based authorization framework. It also added tool annotations describing properties such as whether an operation is read-only or destructive. These changes addressed remote integration and made more behavioral information available to clients.

Annotations can help a host decide how to present an operation. They do not establish that a particular implementation behaves as advertised. Describing a tool as safe to repeat and proving that retries preserve its effects are separate obligations. I would expect evidence from the operation's implementation and tests before relying on that description.

The June 2025 revision added structured tool output, resource links, and elicitation. Structured output lets software consume a result through a declared shape. Resource links let a tool refer to material instead of embedding it. These are useful mechanisms for interfaces that keep large datasets outside model context.

The same revision removed JSON-RPC batching, which March had added. That sequence is a reminder to separate protocol batching from programmatic composition. A program can coordinate multiple tool calls even when the protocol does not accept them as one JSON-RPC batch. It can also make many API requests behind one task-level operation.

The November 2025 revision added experimental Tasks for tracking durable requests through polling and deferred result retrieval. That addresses work that cannot be represented conveniently as an immediate result. A durable task handle is useful, but the application still needs to define what happens if the initial submission succeeds and the handle never reaches the caller.

The July 2026 revision changed the architecture more substantially. It removed the initialization handshake and protocol-level sessions. Requests carry their protocol version and client capabilities individually. Cross-call state uses explicit handles, and Tasks moved into an official extension. The revision also added caching information to several result types.

July removed transport stream resumption and message redelivery as well. After a broken response stream, the client reissues the request with a new request identifier. That makes an application-level recovery contract especially important. A new identifier for a network request does not tell the platform whether the caller intends to retry an existing purchase or submit another purchase.

These revisions address different problems. Remote transport, structured results, durable work, and connection state all matter. None automatically determines whether a platform exposes a useful count operation or requires the model to inspect every record. A criticism of the original lifecycle also cannot be applied unchanged to a stateless implementation.

Where token consumption actually comes from

An evaluation needs to distinguish network traffic, model-visible text, and billed inference. They overlap only where the host makes them overlap. Counting JSON-RPC bytes on a connection cannot establish how many tokens entered a model. Counting a tool result once cannot establish how often it appears in later requests.

I would account for at least five sources of model-visible work.

First, capability discovery consumes context when the host exposes descriptions and schemas. A catalogue with hundreds of detailed definitions can be expensive before the agent invokes anything. The cost depends on the definitions selected for the prompt, including any descriptions of constraints that the agent must understand.

Second, invocation consumes tokens when the model writes arguments or executable code. A short direct call may cost less than generating a program for a single operation. A program can become worthwhile when it replaces many model-mediated calls. The comparison must include the program and its repair attempts.

Third, returned data consumes context when the host passes it to the model. For a counting task, full release notes and download metadata are unnecessary. For a task that evaluates changes described in those notes, some of that text may be essential. The required information depends on the task, not just the endpoint.

Fourth, retained history can expose the same material again in subsequent inference requests. Compaction, retrieval, and provider caching affect what happens next. A cached prompt prefix may change processing or billing behavior without removing the text from the logical input. Those effects need separate accounting for the host and provider being tested.

Fifth, failures create additional work. An agent may inspect help, correct arguments, retry a query, or investigate an ambiguous result. Removing descriptions can reduce the initial prompt while increasing failed calls. The useful objective is reliable task completion within a context budget. The smallest schema is not necessarily the best interface.

There is also a concrete protocol-level source of possible duplication. The November tool specification recommends returning serialized JSON in a text block alongside structured content for backward compatibility. A host that forwards both representations can expose the same result twice. A host can instead consume the structured representation programmatically and choose what the model sees.

That compatibility recommendation is a legitimate design tradeoff to examine. It is more specific than claiming that MCP requires every result to be read by a model. It also identifies something a host implementation can improve without replacing the protocol.

Discovery becomes a retrieval problem

The current MCP client guidance recommends progressive discovery and programmatic tool calling. A host can maintain a catalogue outside the prompt, expose a search mechanism, and load detailed definitions when needed. It can execute calls in code and return selected output.

Discovery then has a measurable failure mode. If search misses the operation that implements the requested task, the agent may choose a weaker operation, invent an unsupported workflow, or conclude that the platform lacks the capability. Moving definitions out of context transfers work to retrieval and selection. It does not remove that work.

I would evaluate discovery using representative task descriptions. Can the host find an operation when the user uses different terminology? Can it distinguish updating an existing record from creating another one? Does it retrieve the required read operation before a mutation that needs a revision number? These tests assess whether selective loading preserves the information the agent needs.

Cache correctness matters too. A cached tool definition can outlive a permission change or an interface update. The current tools specification allows the available tool set to depend on the authorization presented on the request. Reusing a catalogue across callers therefore requires attention to its authorization scope.

Cached availability is not authorization. The implementation must still enforce permission on each invocation. A tool disappearing from a catalogue and a caller losing permission to execute it are related events with different responsibilities.

The protocol specifies tool enumeration. A host's ranking, selective loading, and prompt assembly remain implementation choices. My objection is to treating enumeration as a complete discovery experience. A platform may be easy to connect while its useful operations remain difficult to find.

For a small, stable tool set, direct loading can be reasonable. An extra search and inspection step has its own cost. The decision should follow the actual size and ambiguity of the catalogue, with measurements of selection success. Progressive discovery is a strategy to evaluate, not a universal requirement to add more calls.

Schemas do not define the whole operation

MCP provides input schemas and optional output schemas. When an output schema is present, the specification requires the server's structured result to conform to it. Those rules let clients validate data and generate more useful programming interfaces. They do not define every condition under which the operation is correct.

A schema can establish that a customer identifier is a string. The implementation still needs to determine whether the customer belongs to the target account. A schema can require an operation key without ensuring that the server stores it durably. A result containing an integer count can be structurally valid even when pagination stopped early.

Natural-language descriptions can explain those conditions, but explanations do not implement them. If every agent must read a paragraph and reconstruct the same pagination or recovery algorithm, the platform has left repeated work to each caller. Descriptions remain useful for selection and interpretation. Established execution rules should also exist as callable, testable behavior.

Error conversion is one place where that behavior becomes concrete. The tool specification distinguishes protocol errors from tool execution errors reported through isError: true. An adapter that treats every successful JSON-RPC response as successful application work can therefore misinterpret a failed tool call.

A programmatic wrapper needs an explicit mapping from that result to its error model. It might throw a typed exception or return a tagged result. Either way, the mapping should preserve information about completed effects and uncertain outcomes. Converting every error into the same retryable exception would discard the distinctions recovery depends on.

This is a limitation of treating protocol conformance as the quality bar. A server can advertise valid schemas and implement invocation correctly while providing little guidance about completeness or replay. A capable host can compensate for some omissions. Requiring every host to reconstruct the same platform behavior duplicates work and produces more opportunities for disagreement.

The platform is usually best placed to define those semantics because it owns the underlying operations. A host should not need to infer a payment platform's retention policy or a deployment platform's partial-failure behavior from generic error text. It should receive a contract the platform can verify.

A controlled experiment with release data

I built a local fixture to examine result handling without attributing an interface improvement to its transport. It used a frozen snapshot of 50 public GitHub CLI release records, retrieved on October 17, 2026. The task was to count records whose draft and prerelease flags were both false. Every path read the same records in pages of ten.

The comparison used the official MCP TypeScript SDK, Octokit, and the installed GitHub CLI. The MCP server was a study implementation, not GitHub's hosted server. It exposed a page operation and a task-level count operation. MCP SDK version 1.32.1 negotiated protocol 2025-11-25 over an in-memory transport. The study does not measure July 2026 transport behavior.

No language model chose tools or performed the count. Prewritten code executed every path. I recorded the result payloads that each exposure policy would make available to a model, then counted their compact JSON representation with cl100k_base. Each returned payload was counted once.

The six paths produced these results:

  • Returning five complete MCP pages exposed 628,577 payload tokens.

  • Projecting each MCP page to the two flags and pagination state exposed 550 payload tokens.

  • Processing the pages in an MCP client loop and returning only the count exposed seven payload tokens.

  • Calling a task-level MCP count operation also exposed seven payload tokens.

  • GitHub CLI pagination followed by JavaScript aggregation exposed seven payload tokens.

  • Octokit pagination with aggregation exposed seven payload tokens.

All paths computed a count of 50. Tests also covered a mixed dataset and an empty dataset. The summary-only paths returned the same JSON:

{"stableReleases":50}

Their identical token counts follow from that identical output. The result demonstrates where data can be excluded from context. It does not establish a performance ranking among transports.

The unfiltered baseline is intentionally verbose. Release notes and asset metadata account for information the count does not require. Its 628,577 tokens are specific to this snapshot. The projected MCP path removes most of that volume while retaining the same protocol and page-by-page interaction.

Projection and aggregation solve different problems. Projection removes irrelevant fields. Aggregation performs the computation that remains. In this task, projection leaves the model-facing policy with 50 records' worth of relevant flags. Aggregation reduces those records to the requested answer. A compact result can still transfer routine computational responsibility to the model.

The programmatic and task-level MCP paths make another distinction visible. The programmatic path invoked the page tool five times. The task-level path invoked one MCP tool, which performed the same five underlying reads. Both kept pagination in code. The task-level contract reduced coordination required of the caller without reducing the platform's underlying work.

That is useful evidence for operation design. A platform can supply a repeated workflow as a callable operation. It does not need to make a model rediscover the pagination rule whenever someone asks for the same count. Alternatively, an SDK can supply that rule as a reusable iterator or helper when callers need more flexible computation.

The experiment has explicit limits. It excludes schemas, command help, generated programs, provider framing, and repeated history. It measures neither latency nor agent accuracy. It does not show a model successfully reading a 628,577-token transcript. It records how much result text a particular exposure policy would produce.

Catalogue accounting was separate. The study's three functioning tool definitions occupied 231 tokens as compact JSON. The page definition occupied 101, and the count definition occupied 66. That small catalogue cannot establish search quality or the cost of a production library. It illustrates that fetching definitions and presenting definitions to a model are different accounting decisions.

Code execution changes the responsibility of the host

Published implementations show that substantial reductions can retain MCP. Anthropic's code execution example reports reducing token usage from 150,000 to 2,000 through selective discovery and code execution. Cloudflare's Code Mode server exposes discovery and execution through two tools with an initial definition footprint of roughly 1,000 tokens.

These are vendor-reported examples with their own workloads. Cloudflare's initial footprint is not the total cost of performing a task. Search results, inspected schemas, generated code, execution output, and any corrections add further context. The examples demonstrate that a small initial interface can provide access to a much larger API.

Programmatic calling changes which component performs routine coordination. A program can follow cursors, filter records, and construct a final result without returning each intermediate page to inference. The model still chooses what program to write. The runtime then executes its control flow under defined language and interface rules.

That distinction limits claims about determinism. A runtime can execute a program predictably while the generated program implements the wrong task. If the user asks for production releases and the program counts every non-draft release, it may mishandle prereleases. A valid schema and successful execution do not prove that the predicate matches the request.

Reusable operations reduce how often the model needs to reconstruct an established rule. They also make the rule reviewable. In the release example, defining stable as both flags being false is an explicit predicate. It is not a claim about release quality, support status, or suitability for production. A platform must document which meaning it implements.

A code runtime also introduces operational requirements. It needs execution limits and a policy for external access. Permissions must apply to the calls a script actually makes. A successful first call does not authorize every later call in a loop. If a script terminates after several mutations, the result needs to represent those completed effects.

I would therefore distinguish a flexible code interface from a well-defined workflow. Code execution lets callers compose available operations. It does not supply missing transaction boundaries or recovery rules. A five-line loop that creates tickets can still create duplicates when it is restarted after the third ticket.

What an agent-focused CLI or SDK must add

CLIs and SDKs are useful because they make established software mechanisms available directly. An SDK can expose types, iterators, and operations with explicit error values. A CLI can run an operation in an ordinary process and provide output that another program consumes. Both can place routine data processing outside inference.

Those advantages depend on their design. A CLI that prints a large response to the terminal can fill model context just as a direct MCP result can. An SDK that returns an unbounded list can create the same problem when the caller logs it. Changing the invocation format does not establish a better data boundary.

Existing interfaces offer controls worth comparing. The GitHub MCP server supports selecting toolsets or individual tools, and several read tools support field projection. The GitHub CLI supports pagination and output selection. Octokit's pagination plugin can map each page to relevant data or expose an iterator. A fair comparison uses those capabilities.

For a CLI, I would expect a documented machine mode. Results should go to a predictable output channel, with diagnostics that do not corrupt the result. Authentication failures and missing arguments should not turn into interactive prompts during unattended execution. Exit behavior should have a documented meaning, including what it cannot establish about side effects.

For an SDK, static types are useful but insufficient. The runtime must still validate responses where necessary. Pagination needs bounds and explicit termination behavior. Errors need enough structure for the caller to distinguish a rejected request from an operation whose outcome is unknown. Automatic retries need documented limits and operation identity.

Both interfaces need discoverable documentation and version management. CLI help and SDK documentation consume tokens when an agent reads them. Installing a binary or package adds deployment work. A coding environment may already support those dependencies, while another host may only support remote MCP connections. Those differences affect which adapter is practical.

The important design choice is what the platform supplies above a raw API mirror. A generated method for every endpoint can improve coverage without defining any workflow. An agent-focused library should also encode repeated behavior that callers would otherwise reconstruct, such as bounded pagination, scope checks, and recovery of a previously submitted operation.

I would avoid making every user request a new high-level tool. That can create another large and ambiguous catalogue. Useful task operations implement stable, repeated domain behavior. Lower-level operations remain available for unusual work. The platform should make common behavior explicit without claiming to anticipate every task an agent might perform.

Small results still need to explain their scope

The seven-token count is enough for the controlled fixture because the dataset and completion conditions are fixed. A production response needs more information when those conditions can vary. Otherwise, a concise answer can conceal an incomplete scan or an unexpected scope.

For example, an interface should distinguish all releases visible to the caller from the first 50 records returned by an endpoint. It should report when it reached a page limit, exhausted an execution budget, or lost access during traversal. Returning a successful-looking count after silently stopping changes the meaning of the answer.

A proposed response for the frozen release task could make completeness explicit:

{
  "stableReleases": 50,
  "recordsExamined": 50,
  "complete": true,
  "continuation": null
}

This is an interface example, not the measured seven-token payload. A live implementation would also need a documented scope and consistency policy. Following pages while the underlying collection changes is different from reading a frozen snapshot. The interface should state which behavior the platform supports.

Bounded output also needs a continuation mechanism when more evidence is required. A summary can refer to a stored artifact, a query, or a cursor. Its lifetime and access rules must be clear. If the reference expires before a later agent step uses it, recovery should not require guessing which original dataset the summary described.

This is why I would optimize for sufficient evidence. A small answer should retain the information required to interpret it and decide what to do next. For a simple count, that may be a few completion fields. For a consequential mutation, it includes the identity and observed state of the operation.

A lost response exposes the recovery contract

Suppose an agent asks a platform to create a customer. The platform creates the customer, but the connection closes before the response reaches the caller. The caller observes a communication failure. It cannot conclude that customer creation failed.

Repeating the request can create another customer. Refusing to repeat it can leave the workflow incomplete even though the customer exists. The caller needs a way to identify the intended operation and recover its outcome. The transport's request-response mechanism cannot infer that intent from the same arguments alone.

Stripe's HTTP recovery guidance addresses this boundary. SDK retries can preserve a key within an invocation. If retries span separate SDK calls or process restarts, the application must generate and persist an operation key and supply it to each attempt. An agent starting a new tool invocation is exactly the kind of boundary where this distinction matters.

The idempotency reference specifies further limits. In API v1, Stripe retains keys for at least 24 hours and can remove them afterwards. Reusing a removed key can execute a new request. Parameters must match the original operation. API v2 has different replay behavior, so a wrapper needs to identify the contract it actually preserves.

An interface therefore needs more than a boolean saying a call is retryable. It needs to define how long replay is safe, which identity must be reused, and whether parameters can change. It also needs a reconciliation path when replay is no longer appropriate. A timeout cannot become evidence that no side effect occurred.

The distinction between request identity and operation identity is central. A JSON-RPC identifier correlates a protocol response with a request. A durable operation identifier represents a business intent across multiple attempts. Tracing identifiers can help investigate those attempts, but they do not themselves prevent another mutation.

Nor should operation identity be derived solely from equal parameters. Two separately requested customer creations can legitimately have identical descriptions. Conversely, one intended creation can be attempted repeatedly with identical descriptions after failures. The caller must preserve which intent each attempt belongs to.

Testing recovery across process boundaries

I tested this with a local Stripe-shaped fixture. Its customer endpoint saved a result under a supplied key and rejected changed parameters under that key. It was a simplified endpoint, not Stripe's implementation. I compared curl, the official Stripe Node SDK, and a study MCP tool that delegated to the same SDK.

For every interface, the first process submitted a creation request. The fixture committed the creation and dropped every response to that attempt. A second process then invoked the client again. The first process reported an unknown outcome. The second received a completed result.

Without an operation key persisted across the two processes, every interface left two objects in the ledger. With a key written before the first request and reused by the second process, every interface left one object.

The SDK and MCP paths made an additional HTTP attempt because the SDK retried the closed connection internally. That internal retry preserved identity within the first invocation. It did not make the identity available automatically to the next process. The distinction between an SDK retry and an application retry was observable in the request log.

Additional cases checked that changed parameters were rejected before another mutation. Separate intended operations with identical parameters could create separate objects. Together, these cases test the difference between replaying one intent and suppressing every repeated argument set.

The result does not show that MCP creates duplicates or that a CLI prevents them. The same failure and the same protection appeared across all three interfaces. The deciding behavior was whether the caller retained operation identity across the recovery boundary.

The fixture omitted authorization, key expiry, concurrent writers, and partial downstream failures. Its journal survived the separate invocations in the test, but it was not a production journal with power-failure guarantees. The study is not a conformance test of Stripe's hosted MCP server. Its purpose is to make one recovery mechanism observable under controlled conditions.

Across the read and recovery fixtures, 16 tests passed. A clean dependency installation in a separate directory reproduced the recorded counts and outcomes. Those checks support the local mechanism claims. They do not substitute for testing a production platform's concurrency, retention, or failure behavior.

Define the contract that every adapter must preserve

I would start with a versioned operation definition shared by the SDK, CLI, and MCP adapter. It should specify the operation's scope and effects, together with its output and failure behavior. The adapters can have different invocation syntax while preserving those rules.

For a mutation, the contract should distinguish several states. A request can be rejected before effects occur. An operation can be accepted and remain pending. It can complete, or the caller can lose the ability to determine its outcome. Partial completion needs explicit representation when a workflow has multiple effects.

Those distinctions should survive conversion between interfaces. An MCP tool error, an SDK exception, or a nonzero CLI exit code should not erase an available operation identifier. The caller needs that identifier precisely when the ordinary success path has failed.

For example, a proposed application result could represent the lost-response case as follows:

{
  "operationId": "customer-create-17",
  "outcome": "unknown",
  "nextAction": "reconcile"
}

This is a design example, not an existing MCP field or a Stripe response. The operation definition would have to specify what reconciliation does, how the identifier is scoped, and how long its record remains available. A status label without an implemented recovery path would not be enough.

Operation identity should be persisted before the first submission. The recovery record needs to bind that identity to its target and parameters. A retry that silently changes the target account is not the same operation. Where the platform cannot provide a sufficiently durable identity, the interface must state the limitation and avoid promising safe replay.

Task-level operations also need explicit partial-failure behavior. Creating a customer and then attaching metadata may involve two platform writes. If the second fails, the contract should identify the completed creation. Restarting the whole workflow without that information can duplicate the first effect.

Deduplicating the first write does not make the whole workflow atomic. Each downstream effect needs an identity and recovery rule appropriate to the guarantees its platform provides. Where those guarantees do not span the entire workflow, the operation must expose partial completion or an implemented compensation path. It should not claim that one idempotency key makes every effect happen exactly once.

Preconditions provide another useful guarantee. An update can require a specific resource revision so that it fails when another actor has changed the resource. A preview can describe intended effects before execution. If the platform cannot bind execution to the previewed state, the interface should explain that the preview is informational and may become stale.

Authorization belongs to the operation too. A server-side workflow may use several underlying endpoints, each with its own constraints. Exposing them through one convenient command does not establish permission for their combined effects. The implementation needs to enforce the scope under which the operation was requested.

These are the parts of determinism I would claim. Given explicit inputs and preconditions, the execution rules and recovery transitions can be tested. The interface cannot make an external system perfectly predictable or prove that the model understood the user's intent. It can reject unsupported assumptions and represent uncertainty honestly.

Standardize behavior alongside syntax

MCP already standardizes important parts of connection and invocation. My proposal is to add a platform-owned behavioral contract that every adapter must satisfy. A generated wrapper can preserve argument names while accidentally changing pagination, errors, or retry behavior. Schema compatibility alone will not catch those differences.

For reads, contract tests should cover empty and mixed datasets as well as successful large responses. They should establish what happens at page and execution limits. An incomplete result should remain identifiable as incomplete whether it arrives through a CLI, an SDK, or an MCP tool.

For mutations, tests should include a lost response after commit and a retry in another process. They should cover changed parameters under an existing identity and distinct identities with identical parameters. A production contract also needs tests for its retention and concurrency rules, which the local study does not establish.

Behavioral versioning matters because the meaning of an operation can change without a schema change. If stable releases begins excluding unsupported versions as well as drafts and prereleases, the same arguments can produce a different interpretation. That change needs a compatibility decision even if every JSON field remains valid.

This approach gives the platform a reusable implementation of its established rules. The MCP adapter exposes that implementation to compatible hosts. The SDK lets programs compose it. The CLI makes it available to process-oriented environments. Testing the shared behavior reduces the chance that each adapter develops a different recovery policy.

The right evaluation would then compare complete tasks. Measure discovery success and the definitions loaded into context. Include generated code, returned results, and failure recovery in token accounting. Record whether the final answer is correct and whether the final platform state matches the intended effects. A small prompt is not a successful outcome if the operation is wrong.

My recommendation is to define and test these execution contracts before treating any invocation format as the agent interface. MCP provides reusable access, and a host can use it efficiently. Platforms should also supply the workflow rules, bounded results, and recovery mechanisms that let agents use that access reliably.