The confusion between MCP and function calling arises because they both appear close to the same point in the architecture: the moment when a model needs to leave text generation and use some external capacity. But they don't solve exactly the same problem. Function calling, or tool calling, is mainly a mechanism for the model to choose a tool and produce structured arguments. MCP, the Model Context Protocol, is a protocol for connecting an AI application to servers that expose tools, resources, and prompts in a standardized way.
The most useful distinction is this: function calling answers “which tool does the model want to use and with what arguments?”. MCP answers “how does the application find, describe, access and govern external capabilities in an interoperable way?”. In a real architecture, these answers may appear in the same run. The host discovers a tool via MCP, presents this capability to the model via a tools abstraction, and when the model decides to use it, the call travels through the MCP client to the server. In other situations, the tool is a local function of the application itself and there is no MCP.
The first difference: model decision is not the same as integration
In function calling, the application provides the model with a description of the tool, usually with name, description and parameters structured by schema. When faced with a request, the model may respond not with the final response, but with a call indicating the tool and arguments. In the classic self-function flow, the application receives this intent, executes the corresponding code, and returns the result to the model for it to continue.
This is important because function calling does not mean, in itself, that the model executed the function. Current OpenAI documentation explicitly separates decision from execution in the case of client-controlled functions: the application receives the call, executes the function, and sends the result back. Other tool types may be hosted by the provider, but this is another execution arrangement.
MCP goes into a different layer. The 2026-07-28 specification defines a JSON-RPC-based host-client-server architecture. The host is the application that coordinates the experience with the
model. Each MCP client connects to a specific server. The server advertises capabilities that may include tools, resources, and prompts. Thus, the protocol is not just for “function calling”: it also standardizes discovery, context reading, capabilities negotiation, transport and authorization aspects.
What function calling does well
Function calling is especially straightforward when the tool belongs to the application itself. Imagine an internal system with the consult_status_pedido function, which receives an order_id. The team already knows the code, controls authentication, knows where the function runs and does not need to make this integration reusable by other AI hosts.
In this case, simply declare the tool for the model, define the input schema and handle the call. The contract is small and predictable. If the application has five or ten stable functions, this solution usually has fewer operational parts than introducing an additional protocol.
Modern APIs have expanded this design. OpenAI, for example, today offers tool search engines to load tools on demand in certain models, and providers also have hosted tools. This means that “dynamic discovery” is not absolutely exclusive to MCP. The difference is that without MCP, this mechanism tends to belong to the provider's specific API or framework. MCP attempts to standardize the interface between host and capability servers independently of a single model vendor.
What MCP adds
MCP gains value when integration stops being just a function known by your application and becomes a capability that different AI applications can discover and use through a common contract.
In the current specification, servers can expose tools for actions and queries, resources for contextual data identified by URI, and prompts for reusable templates. The protocol also defines how the client discovers the server's capabilities. This separates the integration logic from the model-specific API and makes it easier for the same server to be consumed by different hosts, as long as they both implement the compatible version and capabilities.
This portability gain does not eliminate integration work. Someone still needs to implement the MCP server, authentication, policies, observability, and error handling. The benefit appears when this shared layer replaces multiple proprietary adapters, or when the capability needs to be discovered by more than one agent, IDE, wizard, or platform.
A unique example, from schema to result
Consider the query_status_order tool. It receives order_id and returns status, delivery forecast and, when applicable, tracking code. The user's goal is simple: “Where is order 84521?”.
Step 1: The schema describes the capability
In the function calling path, the application includes the consulta_status_pedido tool among the tools that the model can use. The schema tells you which order_id is required and what type of value is expected. The description should make it clear when the tool is appropriate and what it returns.
In the MCP path, the server also describes the tool with name, metadata and schema. The difference is that this description is part of a server interface that can be discovered by the MCP client. The host does not necessarily need to have coded each tool individually before connection.
Step 2: Model decides if they need the tool
After reading the question, the model concludes that it cannot answer reliably with just the available context. It selects query_status_order and generates the order_id argument equal to 84521.
This is the point at which the architectures look the same to someone who only looks at the behavior of the model. In both, there is a tool described and a call decision. The divergence appears soon after: who owns the tool, how it was discovered and through which path the call reaches the executor.
Step 3: local execution with function calling
If query_status_order is a function of the application itself, the orchestrator receives the model call and executes its local code or its direct integration with the backend. Then, send the result to the model. The model transforms technical feedback into a response for the user.
Here, the contract between model and application is the center of the solution. The application already knows where the executor is and how to call him. There is no need for MCP host, client and server as separate protocol.
Step 4: execution by MCP
If the same capacity is published by an MCP server, the host keeps a client connected to that server. The client can discover that query_status_order exists, obtain its schema and make it available in the agent tooling layer. When the call is authorized, the client sends the MCP request to the server, which executes the operation and returns the result.
In version 2026-07-28, the core of MCP is stateless: each request carries the necessary version and capabilities metadata, rather than relying on implicit session state. The default transport can be stdio for local processes or Streamable HTTP for servers accessed via HTTP. In both cases, the protocol semantics remain separate from the model decision.
Step 5: Hybrid architecture
Now suppose that the agent has two capability classes. A local function calculates the promised deadline according to internal rules, while a logistics MCP server provides the latest shipment status. The model can use the local function and the MCP tool in the same flow.
This is precisely why “MCP or function calling?” is often an incomplete question. In a hybrid system, function calling can remain the way the model expresses the decision to use an application-controlled tool, while MCP provides a standardized surface for external tools. In APIs that offer MCP as a type of hosted tool, the provider can hide part of this cycle; In SDKs that connect MCP sessions to the tool list, the implementation can use the same tool calling loop to forward the calls. The detail changes by platform, but the conceptual responsibilities remain distinct.
MCP does not replace tool calling reasoning
An MCP server does not generally decide on its own which tool the model should use to meet user intent. It describes and offers capabilities. The host and model continue to participate in selection and orchestration.
It is also incorrect to treat MCP as “a catalog of functions”. Tools are an important part, but the protocol includes resources and prompts, as well as features for discovery, transport, authorization, and other interactions between host, client, and server. This breadth is one of the reasons MCP makes sense as a protocol, and not just as a schema convention.
Function calling does not solve portability alone
A function definition in JSON Schema can be very similar between providers, but the way to register tools, receive calls, return results, require approval and maintain the execution loop varies by API. A team can write adapters for each platform and this can be perfectly acceptable in a closed product.
MCP attempts to place external integration behind a common contract. The same capacity can be exposed by one server and consumed by different hosts. This reduces coupling in high-client scenarios, but adds an operational layer that needs to be justified.
Decision matrix: compare the layer that actually changes
Portability
Simple function calling tends to be coupled to the way the application or provider defines and delivers tools. It is a good choice when the product controls both ends and there is no need to reuse the integration across multiple hosts. MCP is most attractive when the same capacity needs to be consumed by different applications, agents or providers, because there is a common protocol between host and server.
Dynamic discovery
In traditional function calling, the application sends a known set of tools to the model. Modern APIs can load tools on demand with their own mechanisms, so this boundary has become less rigid. MCP, however, standardizes capability discovery at the server level. The client can consult what the server offers and react to changes without each tool having to be individually coded on the host.
Execution
In client-controlled functions, the model requests the call and the application executes it. This gives you direct control over code, networking, and error handling. With MCP, execution typically belongs to the MCP server, although the connection can be local via stdio or remote via HTTP. Some platforms also run MCP access as a hosted tool, reducing customer workload. So, “where does it run?” should be answered by the concrete implementation, not the name of the technique.
Authentication and approval
Function calling defines the structured intent of the call, but does not magically authenticate the external service. The application still needs to protect credentials, check authorization and decide when to ask the user for confirmation. MCP has an authorization framework for HTTP transports and assigns consent and policy responsibilities to the host. Platforms that offer hosted MCP can also add approval controls. In write or high-impact operations, the existence of the protocol does not eliminate the need for a clear human boundary.
Latency
A local function can have the shortest path: model, application, executor, result. A remote MCP server can add discovery, transport, and another network boundary. This does not mean that MCP will always be slower. Discovery and capability lists can be cached, and the current specification introduces cache signals and notification mechanisms to avoid unnecessary queries. The decision must be measured in the actual flow, especially when remote integration would already require an external API anyway.
Governance
Function calling gives the application an explicit point to validate arguments, apply allowlists, log calls and block actions. MCP expands the governance surface because the host can control which servers and tools are exposed, while each server maintains its own policy and authentication. In multi-team environments, this separation can help; in a small system, it can increase complexity without proportional return.
When to use only function calling
Choose a function calling-centric solution when the tools are few, stable, belong to your application and do not need to be reused across multiple hosts. It also makes sense when execution must remain strictly within your backend and you want to minimize protocol layers.
A good sign is being able to answer clearly: “these functions only exist for this agent, this product controls the executor and any new tool will be added by the same team”. In this scenario, MCP may be a premature abstraction.
When MCP becomes worth the cost
MCP starts to be more compelling when there are many integrations, when capability servers are maintained by different teams or companies, when tools need to be discovered dynamically, or when the same integration must work across multiple AI hosts.
It is also useful when the domain involves more than actions. A server that offers context resources, prompt templates and tools under the same protocol is solving a bigger problem than function calling alone.
When to use both
Use a hybrid architecture when some capabilities are local and product-specific, while others come from reusable MCP servers. The agent can be provided with native functions for low-latency internal operations while also accessing partner MCP tools, databases, enterprise systems, or specialized services.
Current documentation of the main ecosystems shows this coexistence in different ways. OpenAI allows you to combine remote MCP with other tools in the same request. Anthropic offers tool usage and an MCP connector for remote servers. The Gemini SDK can connect an MCP session to the tools engine and automatically loop calls in supported scenarios. This reinforces the architectural reading: MCP and function calling are pieces that can fit together, not mandatory substitutes.
The most common architectural error
The most common mistake is to choose based on the newness of the technology, and not because of the frontier that needs to be standardized. If the problem is just allowing the model to call three functions from your backend, start with the platform's tools mechanism. If the problem is distributing a reusable integration to multiple hosts, discovering capabilities and reducing specific adapters, MCP solves a concrete need.
The second mistake is to assume that MCP automatically transfers security and governance to the protocol. Does not transfer. The host still needs to decide what it exposes to the model, the user needs to have control over sensitive actions, and the server needs to authenticate and authorize what it executes. The MCP specification explicitly enforces consent, security boundaries, and denyability of invocations.
A rule of thumb for deciding
First ask who owns the tool and how many independent consumers it will have. If the answer is “my application, a single agent”, function calling tends to suffice. If the answer is “a capability shared by multiple hosts or clients,” MCP deserves evaluation. If there are tools of both types in the same product, don't force a single choice: keep functions local where they are simpler, and use MCP where portability and discoverability justify the extra layer.
Then, measure what actually changes: number of adapters, time to add an integration, authentication cost, latency, ease of approval, traceability and maintenance. The correct architecture is not the one that uses the most protocols; is the one that places each responsibility in the right layer.





