Skip to main content
AI Agents

MCP vs Function Calling: What Changes for Builders

Short answer: function calling and MCP are not competitors — MCP is built on the same idea function calling proved out, and most MCP hosts still translate MCP tools into function calls under the hood. What MCP adds is a standard layer above it: tool discovery, a wire protocol, and portability of tool servers across hosts. What it costs is extra moving parts, a young spec that is still settling, and an operational surface you did not have before. The decision is not "MCP or function calling" — it is whether the standardization is worth the layer, for your system, right now.

By Raman Makkar, CEO & Founder··12 min read

The short answer: it is a layer, not a fork

The framing "MCP vs function calling" implies you pick one. In practice you rarely do. Function calling is the mechanism by which a model asks your code to do something; MCP (the Model Context Protocol, introduced by Anthropic in late 2024 as an open specification) is a standardized way to package, describe, and serve those tools so any compliant host can find and use them. Most MCP clients ultimately expose MCP tools to the model as ordinary function-call schemas.

So the real question is narrower and more useful: given that you already have function calling, when does adding the MCP layer pay for itself? The answer depends on how many hosts need the same tools, who maintains the integrations, and whether the tools change hands between teams or vendors.

This article walks through the mechanism of each, what MCP genuinely adds, what it costs in latency and operational surface, and a decision table for when plain function calling is the right call — because often, it still is.

MCP does not replace function calling any more than HTTP replaced sockets. It standardizes a layer above it. Evaluating "MCP vs function calling" as a rivalry leads to the wrong architecture review.

🔧Function calling fundamentals: the mechanism everything sits on

Function calling (tool use in Anthropic terminology, tools in the OpenAI API) works the same way across major providers. You register a set of tool schemas — name, description, and a JSON Schema for the arguments — alongside your prompt. The model, when it decides a tool would help, emits a structured output: the tool name and a JSON argument payload that conforms to your schema. Your code parses that payload, executes the real function, and appends the result to the conversation as a tool message. The model then continues, now grounded in the result.

Three properties of this mechanism matter for everything that follows. First, the model never executes anything — it only emits JSON, and your runtime is the trust boundary. Second, the schema is the contract: argument validation, error messages on malformed calls, and retry behavior are all yours to build. Third, the tool definitions are compiled into your application. Adding a tool means a code change, a deploy, and usually a prompt adjustment.

That third property is the pain MCP was designed to address. In a world where every agent host (IDE assistant, desktop client, internal chatbot, workflow runner) hand-rolls its own integration to the same GitHub API or the same internal knowledge base, you get N hosts times M tools of duplicated integration code, each with its own auth handling and its own bugs.

ConcernPlain function callingWho owns it
Tool definitionJSON Schema registered in your code, per request or per sessionYour application
ExecutionYour runtime parses args, runs the function, returns the resultYour application
Validation & errorsYou validate against the schema and craft error messages the model can recover fromYour application
DiscoveryNone — the model only sees the tools you compiled inN/A
Auth to downstream APIsHandled inside your functions, with your secretsYour application
PortabilityZero — tools are welded to this codebaseN/A

🧩What MCP actually adds

MCP defines a client-server protocol (JSON-RPC based, over stdio for local servers or streamable HTTP for remote ones, as of the current spec — verify before committing, the transport story has already changed once) with three primitives: tools (callable functions), resources (readable data), and prompts (reusable templates). A server implements the protocol once; any compliant host can connect, list what the server offers, and invoke it.

The first real addition is discovery. An MCP host can ask a server "what can you do?" at connection time and receive tool schemas, descriptions, and resource listings dynamically. Adding a capability to a shared internal MCP server makes it available to every connected host without redeploying any of them. For a platform team maintaining tools used by five different internal agents, that alone can justify the layer.

The second addition is standardization of the boring parts: connection lifecycle, capability negotiation, pagination of tool lists, and an increasingly specified authorization flow for remote servers. The boring parts are exactly where hand-rolled integrations accumulate divergent bugs, so a shared spec has real value even when you control both ends.

The third addition is cross-host portability, and this is the one that gets oversold. In principle, an MCP server written for one host works in any other — a database server usable from an IDE assistant, a desktop client, and your own agent runtime. In practice, as of writing, hosts differ meaningfully in which primitives they support, how they surface approvals, and how they handle auth. Portability is real but not free; expect to test per host, not assume conformance.

The cleanest mental model: MCP turns tools from library code into network services with a standard interface. That is a genuine architectural option with genuine benefits — and all the costs that turning library code into network services always brings.

MCP integration is a service we build and operateBuild your first server: how to build an MCP server

🧾What the MCP layer costs you

Every layer you add between the model and the function has a price, and honesty about the bill is what separates a good architecture review from a hype cycle. The costs fall into four buckets.

Extra hops and latency. A remote MCP call is a network round trip before your actual tool logic even runs — connection setup or keep-alive, protocol framing, then the invocation. For a tool that itself calls a fast internal API, the MCP hop can double its latency. In a multi-step agent loop where the model chains five tool calls, that compounds. Local stdio servers avoid the network but add process lifecycle management instead: spawning, supervising, and restarting per-host child processes.

Spec churn. The MCP specification is young and has moved quickly — transport mechanisms, authorization, and capability details have all been revised since the initial release. As of writing, that trajectory is flattening, but treat anything built against it as needing an upgrade budget. Pin SDK versions, write conformance smoke tests for your servers, and verify the current spec before committing to a design that depends on a specific feature.

Operational surface. A function is deployed with your app and scales with it. An MCP server is a service: it needs hosting, health checks, secrets management, versioning, and an answer to "who is on call when it returns garbage to every connected agent at once." A shared server is a shared blast radius.

Context cost. Discovery is not free at inference time. Every tool the host surfaces lands in the model context as schema text, and large tool catalogs degrade selection accuracy and burn tokens. Well-run MCP deployments curate which tools each agent session sees rather than connecting everything to everyone.

CostPlain function callingWith MCP
Latency per tool callIn-process, microseconds of overheadProcess hop (stdio) or network round trip (HTTP), then execution
Deployment unitShips with the appSeparate server artifact per tool set
Upgrade riskYour code, your scheduleSpec and SDK churn plus per-host compatibility, as of writing
Failure blast radiusOne applicationEvery host connected to a shared server
Context/token costOnly the tools you registerFull catalog unless you curate exposure

The most expensive MCP mistake is exposing a whole server catalog to every agent. Tool selection accuracy drops as the tool count grows. Curate the catalog per agent the same way you would scope IAM permissions.

When plain function calling is enough

This section exists because the honest answer to "should we adopt MCP?" is frequently no, and the engineer who says so in the design review is usually right.

Plain function calling is enough when one application owns both the agent and the tools. A support copilot with eight internal tools, all maintained by the same team that maintains the agent, gains nothing from interposing a protocol between its own frontend and its own backend. You would be operating a service boundary to talk to yourself.

It is enough when latency is tight. Voice agents, real-time coding assistants, and anything with a multi-tool hot loop feel every added hop. In-process calls are simply faster than any protocol, and the difference is user-visible.

It is enough when the tool set is small and stable. Discovery solves a problem you only have when tools change frequently or outnumber what a single team can keep in its head. Six tools that change twice a year are a config file, not a platform.

And it is enough — for now — when your organization has one host. MCP portability pays off at the second host, not the first. If the only consumer of your tools is your own agent runtime, build clean functions behind a stable internal interface, and you will have done 80 percent of the future migration work anyway.

Your situationRecommendationWhy
One agent, one team, tools live in the same repoPlain function callingA protocol boundary to yourself is pure overhead
Latency-critical loop (voice, live coding)Plain function callingEvery hop is user-visible in a chained tool sequence
Several internal agents need the same toolsInternal MCP serversOne integration maintained once beats five divergent copies
Tools consumed by third-party or vendor hostsMCP, if the hosts support itPortability is the entire point of the standard
Tools maintained by a platform team for the orgMCP with a curated registryDiscovery and versioning are the platform team product
Regulated environment, strict data boundaryEither — but audit the transportStdio keeps data local; remote servers need an auth story you have verified

🚚Migration considerations: from functions to servers

If you do migrate, the good news is that the path is mechanical for most of the distance. An existing function-calling tool — schema, handler, validation — maps almost directly onto an MCP tool definition. Teams commonly write a thin adapter that wraps their existing tool registry and serves it over MCP, which is a few days of work rather than a rewrite.

The parts that are not mechanical are auth, tenancy, and versioning. In-process functions inherit the request context — the user, their permissions, the trace ID — for free. A remote MCP server needs that context passed explicitly and safely, and the authorization specifications for remote MCP are among the most actively revised parts of the protocol as of writing. Design your context-passing as if the spec will move under you, because it may.

Version your servers from day one. Function APIs break one consumer at a time, at compile time, with the compiler as your witness. MCP servers break every connected host at runtime, with the model as your witness — which means the failure looks like "the agent got dumber," not a stack trace. Schema versioning, changelogs, and deprecation windows are not optional once multiple hosts depend on you.

A pragmatic sequencing that works: keep functions as the source of truth, stand up an MCP adapter as a second consumer of the same registry, run both paths in parallel behind an internal agent, and only cut external hosts over once the adapter has survived a month of real traffic. The functions never go away — the protocol becomes one more view over them.

Wrap, do not rewrite

Your handlers, validation, and tests are the asset. The MCP server is an adapter over them, and it should stay thin enough to delete.

Pass context explicitly

User identity, permissions, and trace IDs that were implicit in-process must become explicit, signed, and verified at the server boundary.

Version the schema, not just the server

Hosts cache tool definitions. A silent argument rename is an agent regression, not a deploy error.

Keep a kill switch to plain functions

The adapter pattern means you can route a host back to direct calls if a server misbehaves. Shared infrastructure needs a per-consumer off-ramp.

🌱The honest state of the ecosystem

Adoption is real. Since the specification was published, the major model providers, the major IDE assistants, and a long tail of tool vendors have shipped MCP support, and community server registries list integrations for most mainstream SaaS products. If you want your tools reachable from a wide range of hosts, MCP is the only candidate with that breadth of support as of writing — verify current host capabilities before committing, because support depth varies.

Quality is uneven. Public registries mix well-maintained servers from first-party vendors with weekend projects of unknown provenance. Installing a community MCP server is granting a stranger code execution inside your agent loop, with your credentials, on your machine or your infrastructure. Treat server selection like dependency selection: read the code, check the maintenance cadence, pin versions, and prefer servers you can audit.

The security model is catching up to the adoption curve. The specification has added progressively stronger authorization requirements for remote servers, but the gap between "the spec says" and "the server you found on a registry does" is where incidents live. Prompt injection through tool descriptions and tool outputs is a documented attack class against agent systems generally; MCP increases the number of parties who can write text your model will read.

Net assessment: the protocol has crossed from experiment to infrastructure, but it is young infrastructure. Build on it where its specific benefits — discovery, shared maintenance, host portability — are the ones you actually need, keep your adapters thin, and budget for the spec to keep moving a little longer.

Securing agents that call toolsOur MCP integration practice

⚖️The verdict

Function calling is the mechanism; MCP is the distribution layer. If your tools and your agent live in one codebase owned by one team, the mechanism is enough and the layer is overhead. The moment your tools have multiple hosts, multiple owners, or a platform team between them and their consumers, the layer starts paying rent.

Build your tools as clean, validated, well-tested functions regardless. That asset survives either choice. Then add MCP as an adapter when — and only when — a second host shows up asking for the same capabilities.

Talk through your agent architecture with us

FAQ

Frequently Asked
Questions.

Common questions on ai agents, answered by the Codazz engineering team.

Ask Us Anything

No. MCP is a protocol layer above the same underlying idea. Most MCP hosts translate the tools an MCP server advertises into ordinary function-call schemas for the model. Function calling is how the model requests an action; MCP is a standardized way to package, discover, and serve those actions across hosts. You choose whether to add the layer, not which one to use.

When your tools have more than one host or more than one owning team: several internal agents consuming the same integrations, tools served by a platform team to the whole organization, or capabilities you want reachable from third-party hosts like IDE assistants. With one agent, one codebase, and one team, plain function calling is simpler, faster, and easier to debug.

Yes. A remote MCP server adds a network round trip before your tool logic runs; a local stdio server adds a process hop and lifecycle management instead. In multi-step agent loops that chain several tool calls, the overhead compounds. Latency-critical surfaces like voice agents are usually better served by in-process function calls.

Stable enough to build on with an upgrade budget, not stable enough to forget about. Transports, authorization, and capability details have been revised since the initial release, and as of writing the spec is still settling. Pin SDK versions, write conformance tests for your servers, and verify the current spec before designing around any specific feature.

Treat them like any third-party dependency that can execute code with your credentials — because that is what they are. Read the source, check maintenance activity, pin versions, scope the credentials you grant, and prefer first-party or auditable servers. A malicious or sloppy server can inject instructions your model will read or leak the data your tools touch.

The mechanical part is easy: schemas and handlers map almost directly onto MCP tool definitions, and a thin adapter can serve an existing registry over MCP in days. The hard parts are auth and context propagation (user identity and permissions were implicit in-process and must become explicit), versioning across hosts that cache tool definitions, and operating the servers as shared infrastructure with a shared blast radius.

Yes, and that is the architecture we recommend most often. Keep functions as the source of truth, expose them over MCP through a thin adapter for hosts that benefit, and call them directly from latency-sensitive or single-host agents. The protocol becomes one view over your tools, not a rewrite of them.

Deciding between MCP and direct tool calls?

We have built agent tool layers both ways. Bring your architecture and we will tell you honestly whether the MCP layer pays for itself in your system — or whether clean functions are the right answer.

Get a Free Quote

Tell us about your project

Or talk to an engineer