Skip to content
Velaris

Comparison

MCP vs function calling: a protocol, not a replacement

They operate at different layers and people compare them as rivals. What MCP actually standardises, what it doesn't, and when a direct integration wins.

Vithu ·

MCP vs function calling is a comparison between two things that aren’t alternatives. Function calling is a model capability: the model emits a structured request to invoke a tool you described. The Model Context Protocol is a transport and discovery standard for where those tools come from. An MCP-based system still uses function calling underneath.

The genuine question isn’t which to use. It’s whether to define tools directly in your application or behind a protocol boundary.

What function calling gives you

You describe tools in a schema, pass them with the request, and the model responds with a name and arguments. Your code executes it and returns the result.

This is the primitive everything else builds on, and for a small fixed tool set it’s completely sufficient. Three tools defined in your codebase need no protocol — the definitions live next to the code that runs them, which is the simplest arrangement that works.

Its limits appear with scale and reuse. Tools are compiled into your application, so adding one is a deploy. Every application that wants the same integration re-implements it. And a tool set that grows past a few dozen has to fit in context all at once, since there’s no discovery step.

What MCP adds

MCP standardises the boundary between a model application and a tool provider. A server exposes tools, resources and prompts; a client connects and discovers what’s available at runtime.

The wins are architectural rather than capability-based:

Reuse across applications. One Gmail server serves your agent, your IDE and your chat client. Without a protocol, each writes its own.

Runtime discovery. The client asks what tools exist rather than having them hardcoded. New capability appears without a client deploy.

Process isolation. A server runs separately, holds its own credentials, and can be restarted or sandboxed independently of the agent.

An ecosystem. A server someone else wrote works with your client, which is the actual point — it’s the same argument as LSP for editors.

Side by side

CriterionDirect function callingBehind MCP
LayerModel capabilityTransport + discovery
Tool definitions liveIn your codebaseIn a server
Adding a toolApplication deployServer-side, no client deploy
Reuse across appsRe-implement each timeOne server, many clients
LatencyIn-processExtra hop
CredentialsApplication’sServer’s, isolable
DebuggingOne stackTwo processes
Best forSmall, bespoke, latency-criticalMany tools, many clients

What the protocol doesn’t solve

This is where expectations tend to outrun reality.

Tool quality. A badly named tool with a vague description and unhelpful errors is just as bad over MCP. Design still decides whether the agent uses it correctly — the protocol moves the definition, it doesn’t improve it.

Selection at scale. Connecting twelve servers exposing three hundred tools makes discovery worse, not better. You still need retrieval over the tool set; the protocol has no opinion on which tools should be in play this turn.

Authorisation. The protocol carries the call. Whether this user may perform this action is your system’s job, and it belongs at a layer the model can’t influence.

Trust. A third-party server is code you’re granting access to your context and your credentials. Tool descriptions arriving from a server are untrusted input by definition — a malicious description is a prompt injection vector with unusually good placement.

When a direct integration wins

Protocol boundaries are not free, and for a first-party integration you own end to end there’s often nothing to buy.

Prefer direct when latency is tight — an extra process hop matters in a loop that runs dozens of times per task. Prefer direct when the tool is deeply coupled to your application’s internals, where a generic interface adds indirection and no reuse. And prefer direct when you want one deployment artifact rather than a fleet of servers to run, monitor and version.

We build our first-party connectors as internal services with typed contracts for exactly these reasons: latency, deployment simplicity, and enforcing the approval gate inside the runtime rather than at a protocol edge. MCP is how you reach the long tail you didn’t build.

How to choose

Direct function calling when you have a handful of tools, you own them, and latency or coupling argues against a hop.

MCP when the same integration serves several clients, tools must appear without redeploying, or you want a third-party ecosystem you don’t maintain.

Both, usually. First-party integrations direct, where you control quality and latency; MCP for everything else. That’s not a compromise — it’s the boundary falling where the reuse actually is.

The question that settles it: will more than one application use this tool? If no, the protocol is overhead. If yes, it’s the reason protocols exist.

See also: what a client does with hundreds of available tools.