“Function calling” and “MCP” both end with a model invoking some code and getting a result back, so it’s easy to treat them as two names for the same thing. They’re not. Function calling is a model capability: an API feature where you hand the model a list of tool schemas with each request, and it can choose to respond with a structured call instead of plain text. MCP is a protocol: a standard way for a separate server process to describe its tools, resources, and prompts to any client that connects to it, over a connection that outlives a single request. One is a feature inside a model API. The other is the thing that can sit in front of several model APIs at once.
What function calling actually is
When people say “function calling,” they usually mean the pattern most model APIs support directly: you send a request with a tools array of JSON Schema definitions, the model returns either text or a structured call naming one of those tools with arguments, your code runs the actual function, and you send the result back as the next message in the conversation. The schemas live in your application code. There’s no server, no handshake, no persistent connection — just a list you build and pass with every request, and a function you wrote and call yourself when the model asks for it.
That’s simple, and for a single app calling its own functions, it’s often enough. The limits show up once more than one thing needs those tools. The schemas and the functions behind them live inside one codebase. A second application that wants the same capability — read this calendar, search this ticket tracker — has to reimplement the tool definitions and the glue code itself, against whatever API it’s wrapping, from scratch.
What MCP actually is
MCP moves the tool definitions out of the calling application and into a standalone server. The server declares its tools (and optionally resources and prompts) once, over a standard protocol, to whichever client connects — Claude, Cursor, ChatGPT, or anything else that speaks MCP. The client still ends up handing the model something that looks like a function-calling schema under the hood; MCP doesn’t replace the model’s own function-calling mechanism, it standardizes where the schema comes from and who maintains it. See MCP tools, resources, and prompts for what a server can expose beyond a plain callable function.
The practical difference is reuse. Write one MCP server for your ticket tracker, and every client that supports MCP can connect to it without anyone reimplementing the tool definitions. That’s the whole premise behind one server, several AI clients: the server is the reusable unit, not the client integration.
Where the line actually gets drawn
A few concrete differences follow from that split:
Where the schema lives. In plain function calling, the tool schema is part of your application’s code, versioned and deployed with it. In MCP, the schema is served by the MCP server at connection time, via tools/list. A client discovers what’s available instead of having it hardcoded — which is also why a server can change a tool’s definition after you’ve already connected, a behavior worth understanding on its own; see MCP rug pulls.
Who runs the code. With function calling, your own backend executes the function once the model asks for it — you own that code and its access. With MCP, the server that defines the tool is usually the one that executes it too, often as a separate process or a remote endpoint you don’t control, authenticated over OAuth rather than a key baked into your own backend.
Connection lifecycle. Function calling has no concept of a session beyond the request-response pair it’s embedded in. MCP defines a real handshake (initialize), capability negotiation, and for remote servers, a standing connection a client authenticates once and keeps using. That’s also what makes things like resource subscriptions, sampling, and elicitation possible — none of them make sense in a stateless, per-request function call.
Scope of what’s exposed. A function-calling schema is just a function signature. MCP’s primitives separate three different things a server can offer: tools the model decides to invoke, resources a client can read directly, and prompts a user can select — three different control surfaces instead of one.
What doesn’t change
Underneath an MCP tool call, the model is still doing function calling in the literal sense — it still gets a schema, still returns a structured call, still waits for a result. MCP is a layer on top of that mechanism, not a replacement for it. If a model provider’s API had no function-calling capability at all, an MCP client would have nothing to hand the model in the first place. The two aren’t competitors; one is built on the other.
It also doesn’t make function calling obsolete for the cases it was always good at. A single app calling a handful of its own internal functions, where nobody else will ever need that tool and there’s no reason to stand up a separate server process, is still simpler as plain function calling. MCP earns its overhead — a server process, a protocol handshake, discovery, usually OAuth — when the tool needs to be reusable across more than one client, or when it’s something a third party built and you’re connecting to rather than writing yourself.
When to reach for which
Building a tool only your own application will ever call, with no plan for another client to reuse it: plain function calling is less to build and less to run. Building (or connecting to) a tool meant to work the same way across Claude, Cursor, ChatGPT, or whatever comes next, written once and maintained in one place: that’s what MCP is for. If you’re converting an existing API into something agent-callable and deciding between the two, turning an API into an MCP server walks through the OpenAPI-to-tools path in more detail, and gate’s MCP server builder does the generation part for you once you’ve made that call.
The bottom line
Function calling is the model-level mechanism that lets an LLM return a structured call instead of text. MCP is a protocol built on top of that mechanism, standardizing how a separate server describes its tools so any compliant client can use them without reimplementing the integration. Plain function calling is the right choice for a tool only one app will ever call; MCP is the right choice the moment that tool needs to outlive a single app or a single client.