Spurlock Studios
Contact
MCP vs Native Function Calling: Portability Tax vs Shortest Loop

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-use sandboxes: protocol choice does not replace execution policy.

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.
  • Tools execute on the MCP server side (local stdio process or remote HTTP service) — not “inside the model.”
  • 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 MCP is architecturally (host / client / server)

Per the Model Context Protocol docs (architecture overview, current as of the 2026-07-28 docs line):

RoleWhat it isExample
MCP HostAI application that coordinates clientsClaude Desktop, VS Code, your agent service
MCP ClientConnection object the host creates per serverOne client ↔ filesystem server; another ↔ CRM server
MCP ServerProgram that exposes tools, resources, promptsLocal stdio server or remote Streamable HTTP server

Important constraints from the same docs:

  • MCP focuses on context exchange. It does not dictate how you loop the LLM, branch, or evaluate.
  • Transports in common use: stdio (local process) and Streamable HTTP (remote; OAuth recommended for auth tokens).
  • Servers advertise capabilities through discovery; clients pull tools/resources/prompts over JSON-RPC.

If someone says “we rewrote our agent in MCP,” they usually mean “we exposed tools over MCP.” The loop is still yours.

Native function calling: the shortest loop

Provider tool use looks like:

  1. You send tool schemas with the model request
  2. The model returns a structured tool call
  3. Your process executes the function
  4. You return the result in the next message
DimensionNative function calling
Where code runsIn your app / worker
Schema homeYour repo (or generated from code)
AuthWhatever your process already holds
LatencyNo protocol hop beyond the model API
PortabilityRe-declare tools per provider/SDK shape

Use it when the tool is private to this agent, called often, and you want minimal moving parts. Most Spurlock Studios pilots start here.

When native function calling wins

Decision list — prefer native if most are true:

  1. One production host owns the agent
  2. Tools are not products for other teams’ IDEs
  3. Sub-100ms local helpers matter (hash, format, pure transforms)
  4. You already have an HTTP API for cross-service work and do not need a second wrapper
  5. Approval UX lives in your app, not in a desktop MCP client

Native is not “legacy.” It is the correct application pattern for a closed loop.

When MCP earns the portability tax

MCP costs you: process/network hops, catalog management, auth between client and server, and operational ownership of servers. It pays when:

NeedWhy MCP fits
Same tool in IDE + prod agentWrite the server once
Credential isolationSecrets stay in the server; hosts get scoped access
Dynamic discoveryClients learn tools at runtime via server/discover / capability ads
Central audit at the tool boundaryLog/approve at the server or gateway
Multi-team platformTool ownership matches service ownership

A useful mental model from 2026 production writeups: function calling is an app pattern; MCP is a platform boundary. Mature stacks use both.

Where the tool actually executes

Confusion on Ask HN threads usually starts here.

PathExecution location
Native function callingYour host process (or a service you call from that process)
MCP + stdio serverChild process on the host machine, invoked by the MCP client
MCP + remote HTTP serverRemote service; host only sees protocol responses

The model never “runs” the tool. The model proposes a call. Something in your trust boundary executes it. Put sandboxes and policy gates on that something — MCP or native.

Credentials and isolation in MCP servers

Good MCP production hygiene (consistent across enterprise guides and the post–OAuth-2.1 HTTP transport direction):

  • Store API keys and DB creds only in the server environment / secret store
  • Issue scoped tokens to clients (OAuth 2.1 patterns for HTTP transports; don’t share a god key to every host)
  • Enforce least privilege per tool (read vs write vs admin)
  • Treat tool results as untrusted input into the model (injection surface)
  • Prefer a gateway for many remote servers: authn, rate limits, allowlists, audit

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.

Token tax of large MCP catalogs

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.

Catalog sizeRiskMitigation
3–8 toolsUsually fineClear descriptions; no duplicates
15–40 toolsModel picks poorly; cost climbsSplit servers; expose a filtered subset per job
100+ toolsContext bloat + tool confusionRouter/gateway; job-type allowlists; never dump the universe

Practical rule for agents: the model should see the tools for this job, not the company’s entire MCP zoo. Discovery can be broad; the per-run catalog should be narrow.

Is MCP production-ready or still flaky?

As of 2026, the honest characterization is:

  • Protocol maturity: Production-capable. HTTP auth, discovery, and lifecycle have moved past early-2025 “stdio-only toy” status (November 2025 spec work tightened enterprise blockers such as OAuth for HTTP; later docs continue to evolve — check the current specification version you pin).
  • Operational maturity: Still on you. Flaky deployments are usually bad process management, unbounded tool catalogs, missing approvals, or treating MCP as orchestration.
  • Do not cite vanity adoption stats. Ignore unaudited “X% of Fortune 500” claims. Judge readiness by whether your servers have auth, audit, health checks, and eval coverage.

MCP is ready when you are ready to run it like a service. It is flaky when you treat it like a plugin folder.

Do you need LangChain if you have MCP?

No. MCP does not replace LangChain, LangGraph, CrewAI, or a custom loop. Those choose orchestration. MCP chooses how tools are exposed to hosts.

LayerJob
OrchestrationPlan, branch, revise, stop, HITL
Tool protocolMCP and/or native function schemas
Execution policyAllow/deny/pending, sandbox, idempotency

You can use MCP tools from a fifty-line custom loop. You can use native tools inside LangGraph. Mixing is normal; double-maintaining the same tool twice without a reason is not.

Running both without double maintenance

Recommended ownership pattern:

  1. Define the capability once (code module with clear input/output types)
  2. Adapter A: native tool wrapper for the production agent loop
  3. Adapter B: MCP server handlers that call the same module
  4. One eval suite against the module, not against each adapter’s JSON dialect
  5. 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

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).

One-agent / few-tools default

For a single production agent with a handful of tools:

ChoiceDefault
ProtocolNative function calling
Shared company tools laterExtract to MCP when a second host appears
OrchestrationCustom loop or graph — independent of MCP
SafetySandbox + policy before side effects

If your only host is the agent service, MCP is optional. Optional is not forbidden — it is a cost you should justify.

Comparison table (paste into a design doc)

DimensionNative function callingMCP
AbstractionProvider tool/function APIHost ↔ client ↔ server protocol
Best fitOne app, private toolsMulti-client, shared tools
ExecutionYour processServer process/service
Auth storyApp secrets / IAM rolesClient↔server auth (+ gateway)
DiscoveryStatic schemas you sendServer-advertised capabilities
OrchestrationNot includedNot included
Main taxProvider lock-in of schema shapeOps + catalog + hops

Worked example: CRM write tool

Job: Agent drafts a CRM note; humans approve high-risk fields.

ApproachShape
Nativecrm.upsert_note function in the worker; policy gate checks payload; secrets via workload identity
MCPcrm MCP server owns the SaaS token; desktop and prod agent both connect; approvals at client or gateway
WrongMCP server that returns the API key to the model “for flexibility”

If only the worker will ever call CRM, native is enough. If sales’ IDE assistant and the overnight agent both need the same CRM tools with one audit trail, MCP earns its keep.

Anti-patterns

“MCP replaces our agent framework.” Category error.

Dumping 80 tools into every run. Token tax + worse tool selection.

Stdio servers in multi-tenant cloud without isolation. Local transport ≠ multi-tenant security model.

Skipping sandboxes because “MCP is standardized.” Standards do not sanitize side effects.

Pilot guidance

On a Spurlock Studios $1,500 · 5-day agentic pilot we usually ship native tools first, with sandboxes 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 blog post said MCP is the future.

Continue with the operating manual and agent pilot scope.

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.

Do I need LangChain if I have MCP?

No. MCP does not orchestrate agents. LangChain/LangGraph (or a custom loop) decide control flow. MCP exposes tools and context to hosts. You can use MCP with zero LangChain code.

How do credentials stay isolated in MCP servers?

Keep secrets in the server’s environment or secret manager, authenticate 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.

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.

Is MCP production-ready or still flaky?

The protocol is production-capable in 2026 when you pin a spec/SDK version and run servers with auth, audit, and health checks. Flakiness usually comes from ops gaps and oversized catalogs, not from “MCP can’t 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 and sandbox. Add MCP when a second client, shared ownership, or credential boundary makes the portability tax worth paying.

CTA

Shortest safe loop first. Shared tool platform second.

/agentic · /contact?intent=agentic-pilot

Start a pilot