If you have built anything with OpenAI’s function calling or Anthropic’s tool use, you already know the pattern: define a JSON schema, pass it to the model, and let the LLM decide when to call it. It works. Millions of applications run on it.
So when MCP showed up promising to connect AI agents to external tools, the first question from most developers was simple: how is this different from function calling?
The answer comes down to who owns the tool definitions and when they get resolved.
How Function Calling Works
Function calling is a feature of the LLM API itself. You send a list of tool definitions alongside your prompt. Each definition includes a name, description, and parameter schema. The model reads them all, decides whether to call one, and returns structured arguments for you to execute.
The flow looks like this:
- Developer writes JSON schemas for each function
- Schemas are sent with every API request
- Model selects a function and generates arguments
- Your application code executes the function
- Results go back to the model as a follow-up message
This works well when:
- You control the full set of tools at build time
- The tool list is small enough to fit in the context window
- Your application handles the execution loop
- You want tight control over exactly which functions the model can access
Function calling is stateless from the model’s perspective. The LLM does not maintain connections or sessions. It sees tool schemas, picks one, and returns JSON. Your code does the rest.
How MCP Changes the Model
MCP moves tool definitions out of the prompt and into external servers. Instead of hardcoding schemas in your API call, your agent connects to one or more MCP servers that advertise their own capabilities. The agent discovers what tools are available, reads their schemas, and calls them through a standardized protocol.
The flow looks different:
- Agent connects to an MCP server (local via stdio or remote via HTTP)
- Server responds with a list of available tools, their schemas, and descriptions
- Agent decides which tool to call based on the task
- Agent sends a tool call request to the MCP server
- Server executes the tool and returns results directly
The key shift: the tool definitions live on the server, not in your application code. Your agent does not need to know every tool in advance. It discovers them at runtime.
The Real Differences
Ownership of tool definitions
With function calling, you write and maintain every schema. If you want your agent to search the web, you define a search_web function. If you want it to query a database, you define run_sql_query. Every tool is your responsibility.
With MCP, the service provider defines the tools. The Stripe MCP server defines payment tools. The GitHub MCP server defines repository tools. Your agent just connects and uses them. When a server adds new capabilities, your agent sees them without any code changes on your end.
Scaling past a handful of tools
Function calling hits practical limits. Every schema you send consumes context tokens. At 20 tools, you are spending thousands of tokens on definitions before the conversation even starts. At 50 tools, it becomes expensive and slow.
MCP handles this differently. Your agent can connect to dozens of MCP servers, each offering their own tools, without stuffing all those schemas into a single prompt. The agent queries each server for its capabilities and only pulls in what it needs for the current task.
Execution environment
Function calling requires you to build the execution layer. The model returns {"name": "search_web", "arguments": {"query": "..."}} and your code has to actually run that search. You write the HTTP calls, handle errors, manage authentication, and return results.
MCP servers handle their own execution. When your agent calls a tool on an MCP server, the server runs it. Authentication, API keys, rate limiting, and error handling all live server-side. Your agent sends a request and gets a result.
Composability
Function calling is one-to-one. One application, one set of tools, one LLM provider’s API format.
MCP is many-to-many. One agent can connect to multiple MCP servers simultaneously. A single task might use tools from a database server, a file system server, and a web search server together. And because MCP is a protocol rather than a vendor feature, it works across different LLM providers and agent frameworks.
When to Use Each
Function calling is the right choice when:
- You have a small, fixed set of tools (under 10)
- You want maximum control over what the model can access
- You are building a focused application, not a general-purpose agent
- You already handle tool execution in your backend
MCP makes more sense when:
- Your agent needs tools from multiple services
- You want to add new capabilities without changing agent code
- The tool ecosystem matters (using community-built servers from registries like AgentNDX)
- You are building an agent that adapts to different environments or users
Many production systems use both. An agent framework like Claude Code uses MCP for extensible tool access while the underlying model still uses tool-use (function calling) as the mechanism for selecting and invoking those tools. MCP sits above function calling in the stack. It does not replace it. It extends what function calling can reach.
A Practical Example
Say you want an agent that can manage GitHub issues, query a Postgres database, and send Slack messages.
With function calling alone, you would define schemas for create_issue, list_issues, run_query, send_message, and every other operation. You would write the execution code for each, manage three sets of API credentials in your application, and handle errors for all of them. Adding a fourth service means more schemas, more execution code, more credential management.
With MCP, you connect to three servers: a GitHub MCP server, a Postgres MCP server, and a Slack MCP server. Each server handles its own authentication and execution. Your agent discovers all available tools from all three servers and uses them as needed. Adding a fourth service means adding one more server connection.
The tradeoff is clear: function calling gives you tighter control, MCP gives you broader reach with less integration work.
FAQ
Q: Does MCP replace function calling? A: No. MCP is a protocol layer that sits above function calling. The LLM still uses function/tool calling under the hood to decide which MCP tool to invoke. MCP standardizes how those tools are discovered and executed across services.
Q: Can I use MCP with OpenAI models? A: Yes. MCP is model-agnostic. Any agent framework that supports MCP can work with any LLM that supports tool use, including OpenAI, Anthropic, Google, and open-source models. The MCP server does not care which model is calling it.
Q: Is function calling going away? A: No. Function calling is a fundamental capability of modern LLMs. It is the mechanism that makes MCP work. What is shifting is where tool definitions live and who manages execution. For simple, tightly-controlled applications, direct function calling will remain the right choice.