The fight over Model Context Protocol (MCP) versus direct API integration is a fight about the wrong boundary. The line that matters runs between reasoning and execution, and once you draw it correctly the real question becomes whether your execution layer is private code or shared infrastructure.
Why can’t the model just call the API itself?
Start here, because almost every confused MCP argument traces back to skipping this. A language model does not open sockets. It emits tokens. When you give a model tools, what you are actually doing is putting a description of an action space into its context and asking it to emit a structured request naming one of those actions and its arguments. Your application, ordinary code you wrote and deploy, parses that request, performs the operation, and feeds the result back in as more tokens.
This split is architectural, not a limitation of any one provider. It falls directly out of how tool use is specified in the major inference APIs: Anthropic’s Messages API tool use documentation and OpenAI’s function calling documentation both define a contract in which the model returns a tool call block and the client is responsible for executing it and returning a result message. The pattern of interleaving a reasoning step with an acting step, then feeding the observation back, is the ReAct loop from Yao et al., ReAct: Synergizing Reasoning and Acting in Language Models (arXiv:2210.03629, 2022). What each provider standardized is the serialization format, not the idea.
Give that executing code a name and the rest of this gets easier. Call it the execution layer. It holds credentials, makes requests, handles retries and pagination, normalizes responses, and hands clean text or structured data back to the model. Every design in this space, direct integration and MCP alike, is a different answer to one question: who builds and owns that layer.modeldecides onlyexecution layercredentials, retries,pagination, shapingservice APIunchangedtool callresult tokensHTTPpayloadsecrets never cross the left boundaryThe model’s output is a request, not an effect. Everything to the right of the first boundary is normal software with normal failure modes.
Why does integration work multiply as you add AI applications?
Take a support agent that needs Slack, Gmail, Jira, Notion, and an internal database. You write auth, request construction, error handling, retries, and response shaping for each one. Then next quarter a second agent needs the same five systems, and unless you deliberately factored that work out, someone writes it again.
This is the N times M argument for a shared protocol, and it is the honest core of the MCP pitch: with a common client and server contract, you build M servers and N clients rather than N times M bespoke integrations. Treat the arithmetic as illustrative, not as a cost model. Counting “20 integrations versus 12 pieces” compares units that are not comparable. Clients are usually supplied by your agent framework rather than written. Servers for popular SaaS products may already be published by the vendor, while servers for your internal systems are software you now own, version, deploy, monitor, and patch. And maintenance cost tracks upstream API churn and traffic, not the number of edges in a diagram.
The sharper version of the claim: MCP does not reduce the amount of integration logic in the world. It relocates it behind a public interface so it can be written once and reused by any compatible client. The alternative, an internal service that fronts your APIs for all your agents, is a completely reasonable design. Just notice what you have built when you do it: a private protocol for describing actions, invoking them, and returning results. MCP is that same design with the interface published.
Source for the protocol itself: the Model Context Protocol specification at modelcontextprotocol.io. As of this writing the current stable revision is 2025-11-25, with revision 2026-07-28 in release candidate and scheduled to ship as final on 28 July 2026. That revision is a breaking change: it moves the protocol core to a stateless model, removing the initialize handshake and the protocol-level session. Governance moved to the Agentic AI Foundation under the Linux Foundation in December 2025. Pin the revision your client and servers negotiate before quoting any behavior in this article as current.
Can’t I skip MCP and give the agent an OpenAPI spec instead?
You can, and it works. It is worth being precise about what it gets you, because the two things are not substitutes.
Run a concrete task through both. Fetch yesterday’s messages from a Slack channel named #incidents and summarize them.
Route one: documentation plus a code sandbox
You load the API description into context and give the model a sandboxed runtime with credentials injected. The model writes a script. That script resolves the channel name to a channel ID, converts “yesterday” into the timestamp format the API expects, calls the history endpoint, pages through results, and maps raw user IDs to display names. The sandbox runs it. Clean messages come back and the model summarizes.
This works, and for a single application it is often the right call. But look at what you own: the sandbox, the credential injection, the egress policy, and whatever the model wrote. Model-authored code executing with real credentials is its own risk surface, covered as insecure output handling and excessive agency in the OWASP Top 10 for LLM Applications (version 2.0, 2025). If a second agent needs Slack, you either promote that script to a shared service or write it again.
Cost ledger: docs plus sandboxTokensLarge. A full API description for a mature SaaS product is easily the biggest single block in your prompt. Trimming it to relevant endpoints reintroduces a retrieval step with its own recall failure mode.LatencyOften good on the happy path: many chained calls execute inside one generated script, so one model turn can cover the whole task. Bad on failure, where each error round trips through the model to be debugged.CacheFavourable if the spec block is static and sits at the front of the prompt, since provider prompt caching keys on exact prefixes. Any per request trimming of that block breaks the prefix.Eval surfaceWide. The unit under test is generated code, so you are evaluating an open-ended program space rather than a bounded set of calls.Failure modeSilently wrong scripts. Off by one date windows, unhandled pagination, and partial results that look complete to the summarizer.
Route two: an MCP server in front of the same API
The server publishes a small set of named actions with input schemas: search channels, read channel history, search messages by date, post a message. The model picks one. The server does the ID resolution, the timestamp conversion, the pagination, the auth, and the shaping, then returns readable output.
Two differences carry real weight. First, an OpenAPI document describes an API; it does not implement the execution layer. You still need the process that holds credentials, issues the requests, handles failures, and returns results. MCP standardizes that layer instead of describing the thing beneath it. Second, granularity: raw endpoints are designed for developers who expect to chain calls, while a tool interface can collapse a known chain into one semantically named action, which is a much easier selection problem for a model. When the upstream API changes, that fix lands in the server rather than in every prompt and every generated script.
One qualification on the claim that specs only cover web APIs. OpenAPI (version 3.1 onward, which aligned its schema dialect with JSON Schema 2020-12) does target HTTP APIs, and there is no OpenAPI document for your local filesystem or a shell. But other interface description languages exist for other transports, so read the point as “no single existing description format spans local resources and remote services,” rather than “nothing but MCP can describe non-HTTP capabilities.”
How do agents discover tools without filling the context window?
Discovery is the part most worth understanding, and the part where naive implementations get expensive.
At connect time the client asks each server what it offers. Tool definitions in MCP are declared with JSON Schema for their inputs, the same shape the provider tool-calling APIs expect, which is why framework glue between the two is usually thin. The client then places those definitions into the model’s context so the model can choose.
Here is the cost. Those definitions are input tokens on every single request in the conversation, not just the first. Connect ten servers offering fifteen actions each and you are carrying a permanent tax before the user has said anything. Do not trust any specific token figure you see quoted for this without a version attached, because the number depends entirely on schema verbosity, description length, and how a given provider serializes tools into the prompt. Measure it against your own manifest and your own model version.
The mitigation is to stop loading everything: retrieve or search the tool space and load only the actions plausibly relevant to the current task. This is retrieval applied to the action space rather than to documents, and it inherits retrieval’s problems, which are well characterized going back to Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (arXiv:2005.11401, 2020). If the retriever misses the right tool, the model cannot select it, and the resulting failure looks like a reasoning failure rather than a recall failure. That misattribution will cost you debugging hours.
There is a second, less obvious cost that catches teams by surprise. Tool definitions naturally sit near the front of the prompt, which makes them ideal cached prefix material under provider prompt caching schemes. Both Anthropic and OpenAI document prefix based caching with minimum cacheable lengths and eviction windows that differ by provider and by model, so check the current pricing and caching pages for the exact model you are running rather than trusting a remembered number. The architectural consequence is what matters: dynamic tool loading and prompt caching pull in opposite directions. Every time you swap the tool manifest mid conversation you mutate the prefix and forfeit the cache hit on everything after it. A stable, slightly oversized manifest can be cheaper in practice than a perfectly minimal one that changes every turn. Measure both.
Cost ledger: dynamic tool discoveryTokensSaves input tokens per turn versus loading every server’s full manifest. Savings scale with how many connected servers are irrelevant to the average task.LatencyAdds a retrieval step before the first model call, plus a possible extra turn when the first selection misses and a second search is needed.CacheThe main hidden cost. A mutating tool block invalidates the cached prefix for the rest of the request.Eval surfaceGrows a dimension. You now have to evaluate the retriever and the selector separately, or you cannot tell which one failed.Failure modeUnder distribution shift, tasks phrased unlike your retrieval corpus surface the wrong tool subset and the agent confidently does the wrong adjacent thing.
Does MCP add latency, and where does it actually come from?
It adds a hop. Client to server to upstream API and back is more network than calling the API from your own process. In most production systems that hop is not what you feel, because the dominant term is model time: how many generation turns the task requires and how many result tokens you push back into context.
That reframes the tuning problem. Tool granularity is a latency decision. An action that collapses a five call chain into one invocation costs one model turn; five fine grained actions that the model must sequence cost five turns, each with full prompt processing. This is why well designed servers expose task shaped actions rather than one to one endpoint mirrors.
Session setup is the other term, and this is exactly where you need to separate architecture from a given revision’s implementation. Connection setup and capability listing at session start is a property of how a specific spec revision defines the lifecycle, not a law of protocol design. The 2026-07-28 revision explicitly moves the core to a stateless model and removes the initialize handshake and protocol-level session, so any latency claim about session establishment needs a revision attached to be meaningful.
Where do API keys live once a model is in the loop?
Outside the model, always. Credentials belong to the execution layer, which authenticates on the model’s behalf, so the secret never enters the context window and therefore cannot be regurgitated, logged into a trace, or extracted through prompt injection.
The protocol supports authorization and human approval before consequential actions, but supports is doing real work in that sentence. These are affordances you have to configure correctly, not defaults you inherit. Two risks deserve explicit attention, and neither is unique to MCP.
- Tool results are untrusted input. Content returned from an external system reenters the model’s context as text, which is the standard indirect prompt injection channel, ranked first in the OWASP Top 10 for LLM Applications (v2.0, 2025). A Slack message containing instructions is a payload, not data.
- Excessive agency. Broad token scopes plus a broad action menu means the blast radius of one bad selection is the union of every permission you granted. Scope credentials per server and per action, not per organization.
If you operate under a governance regime, this boundary is also where your evidence comes from. NIST’s AI Risk Management Framework 1.0 (January 2023) and ISO/IEC 42001:2023, the management system standard for AI, both push toward documented control over deployed system behavior, and ISO/IEC 23894:2023 gives the AI specific risk management guidance. For agentic systems specifically, OWASP’s Top 10 for Agentic Applications (2026) covers tool misuse, identity and privilege abuse, and cascading failures as distinct categories. Under the EU AI Act (Regulation (EU) 2024/1689), record keeping and human oversight obligations attach to systems classified as high risk, with duties phasing in on a staged timeline. Whether your system falls in scope is a legal determination, not an architectural one, so treat that as a pointer to the text and to counsel rather than as advice. The engineering observation is simply that a single execution layer is a far better place to attach logging, approval gates, and access control than code scattered across a dozen agents.
What breaks when the model, the server, or the upstream API changes?
Centralizing the execution layer centralizes the fix. It also centralizes the blast radius, and this is the tradeoff people undersell.
When an upstream endpoint changes, one server update repairs every consuming agent. Good. But when a server author renames an action or rewrites a tool description to be clearer, they have silently changed the action space every downstream model reasons over. Tool descriptions are prompt material. Editing them is a prompt change with no code review in your repository, and it lands mid conversation for connected clients.
Three failure patterns worth building alarms for:
- Selection drift. Two similarly described actions from different servers, for example one that searches messages and one that reads history, compete for the same intents. Accuracy degrades as the menu grows, and it degrades unevenly across model versions.
- Distribution shift in phrasing. Tool selection is sensitive to how tasks are worded. Users phrase things differently than your eval set does, and selection quality drops first on the long tail.
- Silent partial success. A server that truncates a paginated result and returns it without signaling truncation produces a summary that is fluent, plausible, and incomplete. Servers should mark truncation explicitly in their output so the model can say so.
How do you evaluate a system whose action space is discovered at runtime?
With a hardcoded integration your action space is a constant checked into version control. With discovery it is data fetched at connect time, which means your eval harness has to pin it or your results are not reproducible.
Practical requirements, in rough order of payoff:
- Record the exact tool manifest, including descriptions and schemas, with every eval run. A regression that traces to a server author’s wording change is invisible otherwise.
- Pin the negotiated protocol revision and the server version alongside the model version. All three are independent variables.
- Score tool selection separately from task completion. An agent can pick the right action and still write a bad summary, and the fixes are unrelated.
- Keep a held out set of paraphrased task statements to detect phrasing sensitivity before your users do.
- Snapshot server responses for replay so you can rerun evals without hammering production systems and without letting upstream data drift masquerade as model regression.
When is a direct integration still the right call?
Frequently. Reach for direct integration when you are building one application against a handful of operations you already understand, when you are running an experiment or a one off task, when no server exists for the system you need, or when the server that exists does not expose the action you want and you would end up wrapping it anyway. Plenty of teams run secure, reusable, direct integrations and have no reason to change.
The protocol starts paying for itself at the point where multiple AI applications need the same systems, or where you would otherwise be inventing an internal action description format that only your own code speaks. That is a scaling threshold, not a maturity ranking.
What is architectural here, and what is just this year’s implementation?
Keep the two columns separate when you evaluate any claim in this space, including the ones above.
Architectural, stable across providers and generations: models emit requests rather than perform effects; an execution layer must exist somewhere; credentials belong outside the context window; tool definitions consume input tokens on every turn; collapsing a call chain into one action saves model turns; tool descriptions are prompt material; a shared execution layer amortizes across applications while concentrating failure.
Implementation specific, needs a version and a date attached: whether session setup requires a handshake, which changes with the spec revision you negotiate; prompt cache minimum lengths, eviction windows, and pricing, which differ per provider and per model; how many tools a given model version selects among reliably; which vendors publish and host official servers, which changes month to month; the serialization overhead of tool definitions in a particular provider’s prompt format.
Anything in the second column that reaches you as a bare number, with no model version, no date, and no benchmark conditions, should be treated as unusable rather than approximately right.
The model gains no new capability from any of this. Underneath, it is still ordinary APIs and ordinary code. What a protocol buys you is a standard, and a standard is what lets ten applications share one execution layer instead of building ten.
So the boundary worth optimizing is not APIs versus MCP. It is reasoning versus execution. Draw that line cleanly and the remaining question is an infrastructure question you already know how to answer: should every application own its execution layer, or should execution become shared, versioned, observable infrastructure with an interface other teams can build against? For one application, owning it is simpler. For a fleet, that is exactly the problem a protocol is for.
Sources referenced
- Model Context Protocol specification, revisions 2025-11-25 (current stable) and 2026-07-28 (release candidate, final scheduled 28 July 2026), modelcontextprotocol.io
- Anthropic Messages API tool use documentation and prompt caching documentation; OpenAI function calling and prompt caching documentation. Check per model, since limits and pricing change.
- JSON Schema 2020-12; OpenAPI Specification 3.1 and later
- Yao et al., ReAct: Synergizing Reasoning and Acting in Language Models, arXiv:2210.03629 (2022)
- Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, arXiv:2005.11401 (2020)
- OWASP Top 10 for LLM Applications v2.0 (2025); OWASP Top 10 for Agentic Applications (2026)
- NIST AI Risk Management Framework 1.0 (January 2023); ISO/IEC 42001:2023; ISO/IEC 23894:2023
- Regulation (EU) 2024/1689 (EU AI Act), staged application timeline
