MCP vs Native Function Calling: Portability Tax vs Shortest Loop
Native function calling wins for one app's short tool loop; MCP earns the tax when tools must be shared and governed across hosts—not a LangChain swap.
William Spurlock Founder — Spurlock Studios Updated 18 MIN
MCP vs function calling is a boundary decision, not a religion. Native function calling wins when tools live inside one agent loop you own. MCP earns its overhead when the same capabilities must be discovered, scoped, and reused across hosts — IDEs, desktops, and your production agent — without rewriting the integration each time.
This spoke belongs to the Agentic Systems Operating Manual. Pair it with tool schemas agents follow: protocol choice does not replace a schema the model can obey.
The short answer
- Native function calling = provider feature (tools/functions on the model API). Shortest path inside one app.
- MCP = open protocol for hosts to talk to tool/context servers. Not an orchestration framework.
- Pin three roles: host (the AI app), client (one connection per server), server (where tools actually run).
- Default for one agent, few private tools: native function calling + your policy gate.
- Reach for MCP when multiple clients share tools, credentials must stay behind a server boundary, or discovery/governance matters.
What is MCP architecturally?
The 2026-07-28 MCP specification is an open protocol for exchanging context between LLM applications and external tools. The architecture overview is explicit: MCP does not tell you how to loop the model, branch, or evaluate. It only standardizes how a host talks to servers.
| Role | What it is | Example |
|---|---|---|
| MCP Host | AI application that coordinates clients | Claude Desktop, VS Code, your agent worker |
| MCP Client | Connection object the host creates per server | One client ↔ filesystem; another ↔ CRM |
| MCP Server | Program that exposes tools, resources, prompts | Local stdio process or remote Streamable HTTP service |
If someone says “we rewrote our agent in MCP,” they usually mean “we exposed tools over MCP.” The loop is still yours. The host still decides when to call the model. The server still executes the side effect.
MCP’s own scope note is the whole argument against treating it as a framework swap: it focuses on context exchange. Control flow stays in the host.
How do host, client, and server actually connect?
The architecture docs walk a VS Code example: the editor is the host; connecting to Sentry instantiates one client; connecting to a local filesystem server instantiates a second client. One host, many clients, one client per server. Remote servers using Streamable HTTP typically serve many clients. Local stdio servers typically serve one.
| Fact | Why it matters in production |
|---|---|
| Client is 1:1 with a server | You do not “have MCP.” You have N connections. |
| Host owns coordination | Policy, HITL, and the model loop live here |
| Server owns execution | Secrets and side effects belong here |
| Same JSON-RPC on every transport | Transport is a pipe, not a new product |
Messages follow JSON-RPC 2.0. The base protocol requires a string or integer request id — not null — and defines result vs error responses. That is a wire contract. It is not an agent runtime.
Pin the three nouns on a whiteboard before you pick a library. Most “MCP vs tools” arguments collapse once those roles are named.
What does native function calling actually do?
OpenAI’s function calling guide calls the same idea tool calling. You declare functions on the request. The model may return a structured tool call. Your application executes it. You send the output back. Repeat until the model answers in prose.
Anthropic’s tool-use overview splits the same loop into client tools (you execute, then return a tool_result) and server tools (Anthropic executes web_search / code_execution on their infrastructure). Client tools are the native-function-calling cousin. Server tools are a vendor-hosted helper. Neither is MCP.
| Step | OpenAI function / tool call | Anthropic client tool |
|---|---|---|
| 1 | Send tools with JSON Schema parameters | Send tools with input_schema |
| 2 | Model returns a tool call + arguments | Model returns tool_use + input |
| 3 | Your process runs the function | Your process runs the function |
| 4 | You return tool output / call_id | You return tool_result |
| 5 | Model continues or finishes | Model continues or finishes |
How tool use works is blunt about location: if the response contains a tool_use block, your code runs the operation. The model proposed a call. You accepted or rejected it.
That is the shortest loop. No second process. No discovery handshake. No client-per-server object. Schema in, call out, your handler, result in.
When does native function calling win?
Prefer native if most of these are true:
- One production host owns the agent
- Tools are not products for other teams’ IDEs
- Sub-100ms local helpers matter (hash, format, pure transforms)
- You already have an HTTP API for cross-service work and do not need a second wrapper
- Approval UX lives in your app, not in a desktop MCP client
| Signal | Native is enough | Native starts to hurt |
|---|---|---|
| Hosts | One worker | IDE + desktop + overnight agent |
| Tool owners | Same repo as the loop | Another team’s service |
| Secrets | Workload identity on the worker | Must never enter the host process |
| Catalog | 3–8 private tools | Shared platform catalog |
| Audit | App logs you already have | One trail across clients |
Native is not “legacy.” It is the correct application pattern for a closed loop. Most Spurlock Studios pilots start here. After 500+ automations and 20,000+ hours on agentic systems, the expensive mistake is wrapping a private helper in a protocol nobody else will call.
When does MCP earn the portability tax?
MCP costs you process or network hops, catalog management, auth between client and server, and operational ownership of servers. Anthropic’s MCP announcement framed the job as a standard so hosts do not each invent a connector. That is a platform pitch. It is not a reason to wrap format_date.
| Need | Why MCP fits |
|---|---|
| Same tool in IDE + prod agent | Write the server once |
| Credential isolation | Secrets stay in the server; hosts get scoped access |
| Dynamic discovery | Clients learn tools at runtime via server/discover and tools/list |
| Central audit at the tool boundary | Log and approve at the server or gateway |
| Multi-team platform | Tool ownership matches service ownership |
A useful mental model: function calling is an app pattern; MCP is a platform boundary. Mature stacks use both. The tax is justified when a second host is real — or will be real this quarter — and you refuse to maintain two integrations for one capability.
If the second host is a slide in a strategy deck, stay native.
Where does the tool actually execute?
Confusion usually starts here. The model never “runs” the tool. The model proposes a call. Something in your trust boundary executes it.
| Path | Execution location | Who holds secrets |
|---|---|---|
| Native function calling | Your host process, or a service you call from it | The worker / its IAM role |
| Anthropic client tool | Same as native: your process | Your process |
| Anthropic server tool | Anthropic infrastructure | Anthropic + whatever you passed in |
| MCP + stdio server | Child process on the host machine | Server environment on that machine |
| MCP + remote HTTP server | Remote service; host sees protocol responses | Server / its secret store |
OpenAI’s tools overview adds another fork: built-in tools (web search, code, remote MCP) versus function tools you execute. OpenAI can consume a remote MCP server as a host. That does not make MCP a replacement for function calling. It makes OpenAI one more host that can attach to a server you already run.
Put policy on the process that executes. Protocol branding does not sanitize a write.
What transports does MCP actually use?
The architecture page names two current transports. The 2026-07-28 changelog reclassifies HTTP+SSE (deprecated since 2025-03-26) as Deprecated. New remote work is Streamable HTTP.
| Transport | Shape | Auth story | Typical use |
|---|---|---|---|
| stdio | Local process, stdin/stdout | Environment / OS user. No Authorization header | Desktop host, one user, local files |
| Streamable HTTP | HTTP POST, optional SSE streaming | Bearer / API key / headers; OAuth recommended | Remote shared servers |
| HTTP+SSE (legacy) | Old remote transport | Do not start here | Migrate off |
stdio is fast and local. It is not a multi-tenant security model. A pipe has no token. The security boundary is the process that launched the server. If you spawn stdio servers inside a shared cloud worker without isolation, you imported a desktop assumption into a tenancy problem.
Streamable HTTP is the remote product. It is also where authorization exists as a protocol concern. Choose the transport for the trust boundary, not for the blog post you read.
How do credentials stay isolated in MCP?
The MCP authorization spec applies to HTTP transports. Authorization is optional. When you use it: HTTP implementations should follow the spec; stdio implementations should not — they take credentials from the environment.
On HTTP, a protected MCP server is an OAuth 2.1 resource server. The client is an OAuth 2.1 client. The authorization server issues tokens. MCP servers must publish OAuth 2.0 Protected Resource Metadata (RFC 9728) so clients can discover the authorization server. Client ID Metadata Documents are the preferred registration path; Dynamic Client Registration is deprecated and kept for compatibility.
| Rule | Do this | Do not do this |
|---|---|---|
| Secret home | Server env / secret manager | Paste the SaaS key into every host |
| Client identity | Scoped token per host | One god key for desktop + prod |
| Tool authz | Read vs write vs admin per tool | “If you can list it, you can run it” |
| Results | Treat tool output as untrusted model input | Concatenate CRM dumps into the system prompt |
| Many remotes | Gateway: authn, rate limits, allowlists, audit | Every host talks to every server |
If your “MCP server” is a thin wrapper that dumps the company SaaS key into every desktop host, you did not gain isolation. You distributed a blast radius and called it a platform.
What is the token tax of a large MCP catalog?
Tool schemas are context. Whether you load twenty OpenAI functions or twenty MCP tools into the prompt, you pay input tokens for names, descriptions, and JSON schemas. OpenAI’s function-calling guide now pairs large catalogs with tool search so rarely used tools stay deferred. That is an admission: dumping the zoo is expensive and it makes selection worse.
MCP discovery can be broad. The per-run catalog must be narrow.
| Catalog the model sees | Risk | Mitigation |
|---|---|---|
| 3–8 tools | Usually fine | Clear descriptions; no duplicates |
| 15–40 tools | Worse picks; cost climbs | Split servers; filter by job type |
| 100+ tools | Context bloat + tool confusion | Router / gateway; never dump the universe |
Practical rule: the model should see the tools for this job, not the company’s entire MCP zoo. tools/list can return a platform. The host still chooses what enters the next model request. Schema quality still matters — that is the tool-schema spoke.
Is MCP a LangChain swap?
No. MCP does not replace LangChain, LangGraph, CrewAI, or a fifty-line custom loop. Those choose orchestration. MCP chooses how tools are exposed to hosts.
| Layer | Job | Examples |
|---|---|---|
| Orchestration | Plan, branch, revise, stop, HITL | Custom loop, LangGraph, CrewAI |
| Tool protocol | How hosts discover and call tools | Native function schemas, MCP |
| Execution policy | Allow / deny / pending, sandbox, idempotency | Your gate |
You can use MCP tools from a custom loop. You can use native tools inside LangGraph. Mixing is normal. Double-maintaining the same tool twice without a shared module is not.
If a vendor slide says “adopt MCP instead of your framework,” they collapsed two layers. Keep them separate on the design doc. The operating manual owns the loop. This spoke owns the tool boundary.
How do OpenAI and Anthropic treat MCP vs tools?
Vendors now ship both surfaces. That is the trap. Teams see an mcp tool type and conclude native function calling is deprecated. Read the pages.
| Vendor surface | What it is | Who executes |
|---|---|---|
| OpenAI function / custom tools | You declare schemas; model calls them | Your app (function calling) |
| OpenAI built-in tools | Web, code, files, tool search | OpenAI, unless it is your function |
| OpenAI remote MCP / connectors | Host attaches to a remote MCP server | The MCP server (MCP and Connectors) |
| Anthropic client tools | You declare input_schema | Your app |
| Anthropic server tools | web_search, code_execution, … | Anthropic |
| Anthropic MCP hosts | Desktop / Claude as an MCP host | Your MCP server |
OpenAI’s MCP guide is explicit: remote MCP is in addition to function calling. You can require approval on MCP tool calls. You must trust the remote server — a malicious server can exfiltrate whatever entered the model context. That sentence is the whole security review for “just add the URL.”
Anthropic’s client-vs-server split is a different axis than MCP host-vs-server. Do not mash the words. “Server tool” in Claude’s API means Anthropic ran it. “MCP server” means your (or a vendor’s) process exposed tools over the protocol.
What did the 2026-07-28 spec change that operators should pin?
Pin a spec version the way you pin a model. The spec blog for 2026-07-28 and the changelog are the receipts:
| Change | Operator takeaway |
|---|---|
Protocol-level sessions / Mcp-Session-Id removed | Treat requests as self-contained; do not build sticky-session folklore |
server/discover + per-request _meta | Version and capabilities travel on the call |
| HTTP+SSE deprecated | New remotes: Streamable HTTP |
| DCR deprecated; CIMD preferred | Plan client registration on metadata documents |
RFC 9207 iss validation | Clients must check issuer before redeeming a code |
| Sampling / logging deprecated | Log to stderr or OpenTelemetry; do not wait on client sampling |
Mcp-Method / Mcp-Name headers | Gateways can route and authorize without parsing the body |
“MCP is production-ready” is only true if you pin this line (or the line you actually deployed) and run servers like services. Flakiness in 2026 is usually unbounded catalogs, missing auth, or treating MCP as orchestration — not “the protocol cannot work.”
Do not cite unaudited Fortune-500 adoption percentages. Judge readiness by auth, audit, health checks, and eval coverage on your servers.
How do you run both without double maintenance?
Recommended ownership:
- Define the capability once (code module with clear input/output types)
- Adapter A: native tool wrapper for the production agent loop
- Adapter B: MCP server handlers that call the same module
- One eval suite against the module, not against each adapter’s JSON dialect
- Promote sensitive/shared tools to MCP first; keep app-local helpers native
Checklist:
- Single source of truth for business logic
- Adapters stay thin (serialize / deserialize only)
- Version the capability; advertise version in MCP metadata
- Golden cases call the module directly in CI
- Native schema and MCP
inputSchemagenerated from the same source - Per-run allowlist is a host concern, not a second copy of the handler
If the adapters grow if host == desktop branches, the module is lying. Push policy up to the host or down to the server. Do not hide it in the serializer.
Worked example: one CRM write tool, two boundaries
Job: Agent drafts a CRM note. Humans approve high-risk fields.
| Approach | Shape | When it is correct |
|---|---|---|
| Native | crm.upsert_note in the worker; policy gate checks payload; secrets via workload identity | Only the worker will ever call CRM |
| MCP | crm server owns the SaaS token; desktop and prod agent both connect; approvals at client or gateway | Sales’ IDE assistant and the overnight agent share one audit trail |
| OpenAI as MCP host | Worker still native; ChatGPT / Responses attaches to the same remote server | You already paid for a remote server and a second host is real |
| Wrong | MCP server that returns the API key to the model “for flexibility” | Never |
Decision procedure:
- Count hosts that must call this tool in the next quarter (not “someday”).
- Ask whether the SaaS token may enter the agent worker.
- Ask whether desktop users must use the same allowlist and audit log.
- If hosts = 1 and the worker may hold the token: native.
- If hosts ≥ 2 or the token must not enter the worker: MCP server + gateway.
The schema is the same either way. Write it once. See tool schemas agents follow for enums, required, and killing the omnibus do_anything tool. Protocol does not fix a vague note field.
Failure mode: MCP as fashion middleware
What breaks: A team wraps every internal function in MCP “for the future,” including a pure string formatter called forty times per run. Cold starts and JSON-RPC hops show up in p95. Nobody else consumes the servers. The agent is slower and harder to debug.
What it costs: Latency budget, on-call surface area, and a false sense of platform maturity.
What you do instead: Native for private high-frequency helpers. MCP for shared or credentialed capabilities with more than one client (or a clear second client on the roadmap within a quarter).
Second failure we keep seeing: stdio servers copied into a multi-tenant worker because “local is simpler.” Local is simpler for one user on one machine. It is not a tenancy model. Use Streamable HTTP, isolate processes, or do not share the host.
Third failure: attaching an untrusted remote MCP URL to a host that already holds customer context. OpenAI’s MCP guide warns that a malicious server can exfiltrate whatever entered the model. Review the server like you review a dependency with network and data access — because that is what it is.
One-agent / few-tools default
For a single production agent with a handful of tools:
| Choice | Default |
|---|---|
| Protocol | Native function calling |
| Shared company tools later | Extract to MCP when a second host appears |
| Orchestration | Custom loop or graph — independent of MCP |
| Safety | Policy before side effects; treat tool results as untrusted |
| Catalog | Job-sized, not platform-sized |
If your only host is the agent service, MCP is optional. Optional is not forbidden. It is a cost you should justify in the design doc with a second host or a credential boundary.
Default checklist before you add MCP:
- I can name the second host (product, not aspiration)
- I can name the secret that must not enter the first host
- I can name who pages when the server is down
- I can name the per-run subset the model is allowed to see
- I can run the capability’s evals without either adapter
Zero boxes checked: stay native. Two or more: the tax is probably real.
What should the host send the model this turn?
Discovery and the prompt are different jobs. MCP clients may call server/discover and tools/list. That tells the host what exists. It does not obligate you to stuff every advertised tool into the next model request.
| Layer | Question it answers | Who consumes it |
|---|---|---|
server/discover | Which protocol version and capabilities is this server? | Host / client |
tools/list | Which tools could this server run? | Host / gateway |
Per-run tools / filtered set | Which tools may this model call now? | The model |
| Policy gate | Which of those calls may execute? | Your worker |
Procedure for every production turn:
- Resolve the job type (support reply, CRM note, invoice, research).
- Select the server(s) that own that job — not the whole zoo.
- Filter the listed tools to the verbs this job is allowed to use.
- Send that subset as native functions or as the MCP tools the host will honor.
- Execute only after the gate. Return errors the model can correct once.
If step 3 is “send everything,” you are paying the catalog tax on purpose. OpenAI’s own function-calling docs added tool search for the same reason: large schemas crowd out the task.
Who pages when an MCP server dies?
Native function calling fails like the rest of your worker: one process, one deploy, one on-call. MCP adds a second runtime. Treat it like a service or do not ship it.
| Symptom | Native | MCP stdio | MCP remote HTTP |
|---|---|---|---|
| Cold start | Your worker boot | Child process spawn | Server / scale-to-zero |
| Auth expiry | Workload identity refresh | Env on that machine | OAuth token / CIMD client |
| Version skew | One deploy | Host SDK vs server spec | Same, plus gateway |
| Blast radius | This agent | This machine’s hosts | Every host attached |
On-call checklist before the second host goes live:
- Health endpoint or
server/discoverprobe on a schedule - Alert on tool-error rate, not only HTTP 500s
- Pin spec + SDK versions in the deploy manifest
- Rollback plan that leaves the native adapter working
- Named owner for the server (not “the AI team”)
If nobody will page, you do not have a platform. You have a hobby process in the critical path.
Comparison table (paste into a design doc)
| Dimension | Native function calling | MCP |
|---|---|---|
| Abstraction | Provider tool / function API | Host ↔ client ↔ server protocol |
| Best fit | One app, private tools | Multi-client, shared tools |
| Execution | Your process | Server process / service |
| Auth story | App secrets / IAM roles | Client↔server auth (+ gateway) on HTTP |
| Discovery | Static schemas you send | server/discover, tools/list |
| Orchestration | Not included | Not included |
| Main tax | Provider lock-in of schema shape | Ops + catalog + hops |
| Spec to pin | Current vendor tool docs | MCP 2026-07-28 |
Copy that table into the RFC. Fill the “second host” cell. If it stays blank, you already have the answer.
Anti-patterns
“MCP replaces our agent framework.” Category error. Frameworks loop. MCP exposes tools.
Dumping 80 tools into every run. Token tax plus worse tool selection. Filter at the host.
Stdio servers in multi-tenant cloud without isolation. Local transport ≠ multi-tenant security model.
Skipping policy because “MCP is standardized.” Standards do not sanitize side effects.
Returning secrets in a tool result. The model will see them. So will the next host that logs the transcript.
One god token for every client. You built a distribution system for a key.
Treating OpenAI’s mcp tool type as “we no longer write functions.” OpenAI still documents function calling as the way your app exposes your code.
Pinning no spec version. 2025 SSE assumptions will bite a 2026 Streamable HTTP server.
Pilot guidance
On a Spurlock Studios $1,500 · 5-day agentic pilot we usually ship native tools first, with a policy gate and an evaluator. We introduce MCP when a second host is real or when credential isolation at a server boundary is part of the acceptance criteria — not because a keynote said MCP is the future.
Continue with the operating manual. If the schemas are still vague, fix those before you pay the protocol tax.
FAQ
Where does the tool actually execute?
With native function calling, in your application or a service you invoke from it. With MCP, in the MCP server process or remote service the client called. The model only proposes the call; your trust boundary runs it. Anthropic server tools are a third case: Anthropic runs those on their infrastructure, which is still not “the model ran the tool.”
Do I need LangChain if I have MCP?
No. MCP does not run the agent loop. LangChain, LangGraph, CrewAI, or a custom loop decide control flow. MCP exposes tools and context to hosts. You can use MCP with zero LangChain code, and you can use native tools inside a graph.
How do credentials stay isolated in MCP servers?
Keep secrets in the server’s environment or secret manager, authenticate HTTP clients with scoped tokens, and enforce per-tool authorization. Do not ship long-lived god keys to every host. Prefer a gateway when you have many remote servers. stdio has no OAuth header — isolation there is process and OS, not tokens.
What’s the token tax of large MCP catalogs?
Every tool schema you expose to the model consumes context and can confuse tool selection. Keep per-run catalogs small; filter by job type; split servers so hosts connect only to what they need. Discovery can stay broad. The prompt should not.
Is MCP production-ready or still flaky?
The protocol is production-capable in 2026 when you pin a spec and SDK version and run servers with auth, audit, and health checks. The 2026-07-28 line tightened HTTP auth and dropped protocol sessions. Flakiness usually comes from ops gaps and oversized catalogs, not from “MCP cannot work.” Verify the current spec features you depend on before promising them to a client.
What’s the one-agent / few-tools default?
Native function calling inside a thin harness with a policy gate. Add MCP when a second client, shared ownership, or credential boundary makes the portability tax worth paying. If you cannot name that second host, you are not late. You are early.
CTA
Shortest safe loop first. Shared tool platform second.
What questions does this article answer?
- Where does the tool actually execute?
- With native function calling, in your application or a service you invoke from it. With MCP, in the MCP server process or remote service the client called. The model only proposes the call; your trust boundary runs it. Anthropic server tools are a third case: Anthropic runs those on their infrastructure, which is still not “the model ran the tool.”
- Do I need LangChain if I have MCP?
- No. MCP does not run the agent loop. LangChain, LangGraph, CrewAI, or a custom loop decide control flow. MCP exposes tools and context to hosts. You can use MCP with zero LangChain code, and you can use native tools inside a graph.
- How do credentials stay isolated in MCP servers?
- Keep secrets in the server’s environment or secret manager, authenticate HTTP clients with scoped tokens, and enforce per-tool authorization. Do not ship long-lived god keys to every host. Prefer a gateway when you have many remote servers. stdio has no OAuth header — isolation there is process and OS, not tokens.
- What’s the token tax of large MCP catalogs?
- Every tool schema you expose to the model consumes context and can confuse tool selection. Keep per-run catalogs small; filter by job type; split servers so hosts connect only to what they need. Discovery can stay broad. The prompt should not.
- Is MCP production-ready or still flaky?
- The protocol is production-capable in 2026 when you pin a spec and SDK version and run servers with auth, audit, and health checks. The 2026-07-28 line tightened HTTP auth and dropped protocol sessions. Flakiness usually comes from ops gaps and oversized catalogs, not from “MCP cannot work.” Verify the current spec features you depend on before promising them to a client.
- What’s the one-agent / few-tools default?
- Native function calling inside a thin harness with a policy gate. Add MCP when a second client, shared ownership, or credential boundary makes the portability tax worth paying. If you cannot name that second host, you are not late. You are early.
- modelcontextprotocol.io
- modelcontextprotocol.io
- jsonrpc.org
- modelcontextprotocol.io
- developers.openai.com
- platform.claude.com
- platform.claude.com
- anthropic.com
- developers.openai.com
- modelcontextprotocol.io
- modelcontextprotocol.io
- datatracker.ietf.org
- developers.openai.com
- blog.modelcontextprotocol.io
Last reviewed
AI Agents
AI Agents Budtender FAQ that will not invent a strain benefit
A floor FAQ agent answers hours, pickup rules, and SKUs from approved copy — then hard-stops before inventing a medical claim or a COA.
AI Agents Why is my agent 10× more expensive than the chatbot demo
Agents cost more than the chatbot demo because each tool turn re-bills growing context, schemas, and retries. 10× is a complaint to diagnose, not a statistic.
AI Agents Who is accountable when an agent acts (refunds, emails, writes)
A named human owns every agent refund, email, and write. Policy gates sit before irreversible tools; the model is not a person and cannot absorb the blame.
AI Agents Why Pass Rate Lies: Revision Rate, Trajectories, and Coverage
Pass rate flatters bad agents. Gate deploys on revision rate, trajectory scores, eval coverage, and cost per successful task—not a single green percentage.
Will's Journal in your inbox.
What I learned this week building for shops, floors, and houses.
You're on the list.
Sign-up failed — try again.
By subscribing, you agree to the Privacy Policy.