BYOKchat Blog

MCP Tools vs Function Calling: What Is the Difference?

Understand how MCP tools differ from model function calling, how they fit together, what each layer controls, and why the distinction matters for security.

· 8 min read

On this page
  1. The shortest comparison
  2. Function calling in one sentence
  3. Who executes a function call?
  4. MCP in one sentence
  5. Why function calling alone does not solve integrations
  6. Why MCP still needs model tool calling
  7. Comparison table
  8. Tool discovery does not equal permission
  9. A practical permission model
  10. Why arguments should be visible before approval
  11. Tool results also matter
  12. MCP can expose more than tools
  13. Multi-provider clients make the distinction clearer
  14. Multi-round tool use
  15. What happens when the model asks for a nonexistent tool?
  16. What happens when an MCP server is offline?
  17. Function calling without MCP
  18. MCP without model-driven tool use
  19. When should developers add MCP?
  20. Security checklist for tool-enabled clients
  21. The practical takeaway

Function calling and MCP tools are often described as competing ways to give an AI model tools.

That framing is misleading.

Function calling is primarily a model-facing mechanism: the model emits a structured request saying which action it wants software to perform.

MCP is an integration protocol: it gives an AI application a standardized way to connect to external servers that expose tools and other capabilities.

They can be used together in the same tool invocation.

The shortest comparison

Function calling:
model ↔ AI application

MCP:
AI application ↔ external capability server

In a typical MCP-enabled chat app, the complete path can look like:

Model
  → structured tool request
AI client
  → permission check
  → MCP request
MCP server
  → external system
MCP server
  → tool result
AI client
  → provider-specific tool result
Model
  → final answer

The model does not need to speak MCP directly for this architecture to work.

Function calling in one sentence

Function calling gives a model a structured description of actions it may request.

An application might expose tools such as:

search_files(query)
get_weather(city)
create_issue(title, body)

The model receives a schema describing each function and its arguments.

Instead of replying:

I created the issue.

when it has no ability to do so, the model can emit a structured request similar to:

tool: create_issue
arguments:
  title: "Fix login retry"
  body: "..."

The application decides what happens next.

The function call is not the action itself. It is the model asking software to perform the action.

Who executes a function call?

The application does.

This is a crucial security boundary.

A provider can return a tool request, but the model provider normally does not reach directly into your GitHub account, filesystem, database, or calendar merely because the model generated a tool name.

The host application receives the request and decides whether to:

  • reject it;
  • ask the user;
  • validate the arguments;
  • execute local code;
  • call another API;
  • forward the request to an MCP server.

That execution layer is where tool policy belongs.

MCP in one sentence

The Model Context Protocol (MCP) standardizes how AI applications can connect to external servers that expose capabilities.

Instead of hard-coding every integration into every AI client, an MCP-capable client can connect to a server and discover what that server offers.

A simplified architecture is:

AI client
  ↔ MCP server
      ↔ filesystem / API / database / service

This moves the integration boundary away from a bespoke one-off plugin inside the client.

If you want the broader protocol introduction first, see What Is MCP and Why Does It Matter for AI Apps?.

Why function calling alone does not solve integrations

Imagine five AI apps all want to work with the same issue tracker.

Without a shared integration protocol, each app may need to build:

  • authentication;
  • tool discovery;
  • argument schemas;
  • transport;
  • error mapping;
  • lifecycle management;
  • custom update logic.

Function calling only solves the model-side part: “the model wants to call create_issue with these arguments.”

It does not define a reusable connection between the AI app and the external integration.

MCP addresses that other side of the system.

Why MCP still needs model tool calling

MCP does not eliminate the need for the model to express its intent.

The AI client still needs some mechanism to tell the model:

These tools are available.
Here are their descriptions.
Here are the argument schemas.

Then the model needs a structured way to request one.

Different model providers may represent this differently. The client can normalize those provider-specific formats into one internal tool representation.

That gives a useful architecture:

Anthropic tool format ─┐
Gemini tool format ────┼→ client tool layer → MCP
Other provider ────────┘

The MCP server does not need separate implementations for every model provider.

Comparison table

QuestionFunction callingMCP
Main boundarymodel ↔ appapp ↔ external server
Defines tool schemayes, model-facingyes, server/client-facing
Executes the real actionnoserver may perform it
Handles user approvalnonot by itself; client policy should
Provider-specificoftendesigned as a shared protocol
Discovers external toolsapp-definedyes, through protocol
Replaces app security policynono
Can work without the otheryessometimes, but model tools commonly bridge to MCP

This is why saying “MCP is just function calling” loses an important architectural distinction.

Tool discovery does not equal permission

Suppose an MCP server advertises:

read_file(path)
write_file(path, content)
delete_file(path)

Discovery tells the client these capabilities exist.

It does not mean the model should automatically receive permission to run all three.

A safer client separates at least three concepts:

  1. Available on the server — the server exposes it.
  2. Visible to this chat/model — the client chooses to include it.
  3. Allowed to execute — policy permits the requested call.

These states should not be collapsed into one switch.

A practical permission model

A client might expose policies such as:

  • Disabled — do not make the tool available to the model.
  • Ask — let the model request it, but require user approval before execution.
  • Always Allow — execute valid requests without another approval prompt.

The important point is that the policy belongs to the client/user boundary, not to the model’s decision.

A model request is an intent proposal, not authorization.

Why arguments should be visible before approval

A permission dialog that says only:

Allow "write_file"?

is much less useful than one that shows:

Tool: write_file
Path: /Projects/App/config.json
Content: ...

Risk often depends more on the arguments than on the tool name.

For example:

read_file("/tmp/example.txt")

and:

read_file("~/.ssh/id_rsa")

use the same tool but have very different implications.

A good client makes the requested arguments inspectable before executing sensitive actions.

Tool results also matter

Security does not stop once a tool is called.

Tool output becomes new context for the model.

That result may contain:

  • private data;
  • untrusted text;
  • malicious instructions;
  • very large content;
  • URLs;
  • secrets returned by an external system.

The client should treat tool output as data from an external boundary, not as trusted system instructions.

This matters because tool-enabled AI systems can encounter prompt injection through documents, webpages, issue bodies, database fields, or other retrieved content.

MCP can expose more than tools

MCP is broader than “functions the model can run.”

Depending on the server and client, MCP can expose other forms of context or interaction in addition to tools.

That is another reason the concepts should not be treated as synonyms.

Function calling answers:

How can the model request structured work?

MCP answers:

How can the AI application connect to an external capability provider using a standard protocol?

Those questions overlap, but they are not the same.

Multi-provider clients make the distinction clearer

Suppose a project can switch among Claude, Gemini, and another model.

You do not want the GitHub, filesystem, or internal-database integration to be rewritten for every model provider.

A provider-neutral client can:

  1. discover tools from MCP;
  2. convert them into the selected model provider’s tool schema;
  3. receive the provider’s structured tool request;
  4. normalize it internally;
  5. apply user/tool policy;
  6. call the MCP server;
  7. normalize the result;
  8. send the result back using that provider’s required format.

The model-facing API can change while the integration-facing MCP server stays the same.

That is one of MCP’s strongest architectural advantages.

Multi-round tool use

Real tool workflows often require more than one call.

For example:

User: Find the latest failing build and explain it.

Model
  → list_builds()
Tool result
  → build 912 failed

Model
  → get_build_logs(912)
Tool result
  → compiler error details

Model
  → final explanation

A capable client must manage the entire model → tool → model loop.

That includes:

  • preserving tool-call IDs;
  • limiting runaway loops;
  • handling cancellation;
  • handling partial failures;
  • showing intermediate state;
  • preserving tool results in conversation state;
  • deciding whether another tool round is allowed.

Neither “function calling support” nor “MCP support” alone guarantees a good implementation of this loop.

What happens when the model asks for a nonexistent tool?

The client should fail explicitly.

Possible causes include:

  • tool was removed from the server;
  • tool was disabled after the model saw the schema;
  • provider returned an invalid tool name;
  • stale conversation state refers to an old tool definition.

A robust client should not guess which tool the model meant.

Instead, return a structured failure to the model or require another model turn with the current tool set.

What happens when an MCP server is offline?

This is another layer-specific failure.

The model may have produced a perfectly valid function call while the MCP transport or server is unavailable.

The client should distinguish:

Model error
Tool permission denial
MCP connection failure
Tool execution failure
External service failure

Flattening all of those into “tool failed” makes debugging much harder.

Function calling without MCP

You can absolutely build useful tool-enabled AI without MCP.

For example, an app can implement a small set of native functions directly:

get_current_document()
search_local_notes()
create_calendar_event()

If the integration is tightly coupled to the app and unlikely to be reused elsewhere, MCP may add unnecessary complexity.

Function calling remains useful on its own.

MCP without model-driven tool use

MCP capabilities can also be useful even when every action is not initiated autonomously by a model.

An application can expose an MCP-connected capability through explicit UI or use MCP-derived context while retaining more deterministic control.

So the relationship is complementary, not mandatory in one exact form.

When should developers add MCP?

MCP becomes especially compelling when:

  • integrations should work across multiple AI clients;
  • tools come from external or user-configured servers;
  • the tool catalog changes dynamically;
  • the same integrations should work across model providers;
  • you want a standardized boundary rather than bespoke plugins.

A native function layer may remain simpler when:

  • the app owns a tiny fixed tool set;
  • there is no external server;
  • portability is not a goal;
  • the tool is deeply tied to internal UI state.

Security checklist for tool-enabled clients

Before calling tool support “safe,” ask:

  • Can users see which server provided each tool?
  • Can tools be disabled per conversation?
  • Can sensitive tools require approval?
  • Are tool arguments visible before approval?
  • Can the user tell what result came back?
  • Are secrets hidden from logs?
  • Are tool loops bounded?
  • Can execution be cancelled?
  • Are side-effecting retries handled carefully?
  • Is external tool output treated as untrusted context?

MCP standardizes connectivity. It does not remove the client’s responsibility to answer these questions.

The practical takeaway

Function calling is the model-side mechanism for saying “I want to use this structured action.”

MCP is a standardized application-side protocol for saying “these external capabilities are available here, and this is how the client communicates with them.”

They fit naturally together, especially in a multi-provider AI client.

The critical layer between them is the client itself: it decides which tools the model can see, which requests require approval, what arguments are executed, how results are returned, and how failures are contained.

Keep reading