Build with AI

What is the difference between MCP and function calling?

· By Robert Scales · 4 min read

Short answer

Function calling is a feature of a model's API: you describe tools in your request, the model replies with the name and arguments of the one it wants, and your own code runs it. MCP is a protocol one level up: it packages tools into separate servers that any compatible app can discover and call, so a tool written once works in many assistants.

Both ideas let a language model use tools, and both describe those tools the same way, with a name, a description and a list of inputs written in JSON Schema (a standard format for describing what data should look like). That is why they are easy to confuse. The difference is who owns the tool and where it lives.

With function calling, which OpenAI added to its API in June 2023 and other providers now offer too, the tool lives inside your application. You list it in every request, the model answers "please call get_weather with these arguments," and your code does the work. With the Model Context Protocol (MCP), released by Anthropic on November 25, the tool lives in a separate program called a server. An app that speaks MCP, such as Claude Desktop, asks the server what tools it has, and calls them on the model's behalf.

The two paths in words

Picture a user asking, "Do I need an umbrella in Montreal today?"

Function calling:

  1. Your app sends the question plus the tool's description to the model's API.
  2. The model replies with a tool call: get_weather, {"city": "Montreal"}.
  3. Your app runs its own get_weather code, which calls a weather service.
  4. Your app sends the result back; the model writes the answer.

MCP:

  1. When the host app starts, it connects to a weather MCP server and sends tools/list. The server answers with get_weather and its input schema.
  2. The host passes that tool description to its model along with the question.
  3. The model asks for get_weather; the host sends tools/call to the server.
  4. The server runs the code and returns the result; the host gives it to the model, which writes the answer.

Inside the host, step 3 of the MCP path still uses the model's own tool-use feature. MCP doesn't replace function calling; it standardizes how tools are found and run from outside the app.

A weather tool, built both ways

First, function calling with OpenAI's Python library. The tool is described in the tools list; setting strict to true, an option added in August, makes the model's arguments match the schema exactly.

from openai import OpenAI
client = OpenAI()

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Current weather for a city",
        "strict": True,
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
            "additionalProperties": False,
        },
    },
}]

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Do I need an umbrella in Montreal today?"}],
    tools=tools,
)
call = response.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments)  # get_weather {"city":"Montreal"}

Your code would now run its weather lookup and send the result back in a message with the role tool. The tool exists only in this program.

Now the same tool as an MCP server, using the pattern from the MCP documentation's Python example. The weather data here is a placeholder for illustration.

from mcp.server import Server
import mcp.types as types

app = Server("weather")

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [types.Tool(
        name="get_weather",
        description="Current weather for a city",
        inputSchema={
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    )]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "get_weather":
        city = arguments["city"]
        report = f"{city}: 4°C, light rain"   # illustrative; call a real weather API here
        return [types.TextContent(type="text", text=report)]
    raise ValueError(f"Unknown tool: {name}")

A complete server also needs a few lines to start it over standard input and output, which the SDK provides. Notice what's missing: no model, no API key, no chat loop. The server only knows how to describe and run its tool. Any MCP host can connect to it and offer it to whatever model the host uses.

Function callingMCP
Where the tool runsIn your application's codeIn a separate server process
How the model learns about itYou list it in each API requestThe host asks the server with tools/list
Who runs itYour codeThe server, when the host sends tools/call
ReuseOne app, one provider's formatAny MCP-compatible host
Best forA single app you control end to endTools you want to share across apps

Try it: Take a tool you already built with function calling and write down three things: its JSON Schema, the code that runs it, and the code that talks to the model. Only the first two would move into an MCP server. Seeing which lines go where makes the split clear.

When do you need both?

Whenever you build your own app that should use shared tools. Suppose your company writes one MCP server for its order database, so staff can use it from Claude Desktop. Later you build a customer-service chatbot on a model's API. Your chatbot can act as an MCP host: it connects to the same server, reads the tool list, converts each tool into the function-calling format its model expects, and forwards the model's tool calls to the server. Function calling handles the conversation with the model; MCP handles finding and running the tool. Nobody writes the database code twice.

If you are building one small app with two or three tools that nobody else will use, plain function calling is simpler: there is no extra process to run. MCP pays off as tools multiply, or when several apps, or several teams, need the same ones.

In both cases the safety rules are the same. The MCP documentation asks server builders to validate every input against the schema and to keep a person in the loop to approve actions. OpenAI's own guidance on function calling says to confirm real-world actions, such as sending an email or making a purchase, with the user before running them.

Sources

  1. Tools (Model Context Protocol documentation) — Model Context Protocol / Anthropic (GitHub), December 2, 2024
  2. Introducing Structured Outputs in the API — OpenAI, August 6, 2024
  3. Function calling and other API updates — OpenAI, June 13, 2023

Get the free Guide to Artificial Intelligence

Sign up for the weekly newsletter and receive the free guide: what changed in AI this week, one lesson, one prompt to try. Unsubscribe in one click.

How we handle your address

Back to top

Display

Your choices are saved in this browser only. No data is sent.

Text size
100%
Colours
Reading
More settings
Accessibility statement