"Do we still need APIs after MCP" keeps coming up, and the framing is off in a way that's worth unpicking. MCP and function calling aren't two options you choose between. They're two layers of the same request, and a system built on MCP runs function calling underneath it every single time.
The two gaps
A model can't act on its own. It reads text and predicts more text. Two separate gaps sit between it and anything useful, and each needs its own fix.
The first gap is expression — the model needs a structured way to say what it wants done. Function calling fills that. It's a capability of the model provider's API, not a protocol: your application sends tool definitions with the request, and the model returns a structured call naming one of them.
The part people skip: the model doesn't run anything. It hands back a request. Your code executes the function and feeds the result into the next turn.
The second gap is reach. Your application still has to find the tool, get its schema, and call it correctly — usually across a lot of tools. That's MCP's job. Client-server, JSON-RPC 2.0, discovery at runtime via tools/list.
Function calling links the model to your app. MCP links your app to the tool server.
What actually happens when both are in play
Five steps, fixed order:
- The MCP client calls
tools/liston a server and gets tool definitions back, each with a JSON Schema. - Your application hands those definitions to the model through the provider's function-calling mechanism.
- The model emits a function call — tool name, arguments.
- Your application routes that call to the MCP server as
tools/call. - The server executes it, and the result goes back into the conversation.
Steps 2 and 3 are function calling. Adopting MCP doesn't remove them, it feeds them. Note also that the model never talks to the MCP server directly — your application sits in the middle the whole time, translating between a function call and a tools/call.
So what is MCP actually for
Not model capability. Models could call functions long before MCP existed.
It's the N×M problem. Without a shared protocol, wiring N applications to M tools means N×M integrations — three apps each needing five tools is fifteen separate pieces of work, none of which carry over. Wrap each tool once as a server, implement the client once per application, and the total becomes N+M.
That's the real argument, and it's a good one. It just has nothing to do with whether a model can express a tool call.
The part that gets overstated
This is the bit I'd most want people to check themselves, because plenty of write-ups claim MCP ships approval workflows and audit logging out of the box.
Here's the specification text:
the protocol itself does not mandate any specific user interaction model. For trust & safety and security, there SHOULD always be a human in the loop with the ability to deny tool invocations.
SHOULD. The spec states up front that its key words are to be read per RFC 2119, so that's a recommendation aimed at client implementers, not something the protocol enforces. Nothing in MCP stops a client skipping the check.
What you do get is a seam. Tools sit behind a server boundary, which is a natural place to put authentication, logging and policy. That part is real and genuinely useful. But you build it yourself. And the boundary means trusting a new party — the server is now part of your threat model, which isn't a free win.
Where I'd leave it
Reach for function calling whenever a model needs to act. That's every agentic flow, MCP or not.
Reach for MCP once tools need reuse across applications, or once they live behind a server you don't control. A single script calling one local function probably doesn't need it.
Most production systems end up running both, because they're solving different problems. "Do we still need APIs after MCP" has the same answer as "do we still need function calling after MCP" — yes, underneath, every time.
Longer version with the full comparison table at diffstudy.com. Spec quote from the MCP specification, 2025-06-18, Server/Tools.
Top comments (1)
This distinction clears up a lot of confusion. MCP standardizes how tools and context are exposed, while the model still has to choose a call and the client still has to execute it. Treating those as separate layers should make debugging much easier, especially when a failure could come from discovery, argument validation, or the tool runtime. A small trace across all three would be useful in production.