Function calling or MCP: what is the difference and what to choose

These are not two rival methods but two levels of the same task. Who describes a tool, who runs it, and when you need MCP.

5 min · · агенты · сравнение

Function calling vs MCP is a common question from people building an agent who see both technologies in the documentation. The answer is that they solve different parts of the same task. Function calling answers "how does the model say it wants to call a function", while MCP answers "how does the application find and run tools that other people wrote". Below we look at who does what, how it appears in an API request, and when a plain tools list is enough.

Function calling: tools inside the request

With function calling you pass the model a list of tools in the request: a name, a description and a JSON Schema of the arguments. The model does not run code. Instead of a text reply it can return a structured request: "call get_order_status with these arguments". After that your application takes over:

  1. sends a request with the tool descriptions;
  2. receives a function call from the model;
  3. runs the function itself;
  4. sends the result back in the next request;
  5. receives the final text answer.

The tool code lives in your application, and the description is passed in every request. Through the Zukko gateway this works in both formats. In the OpenAI format (/v1/chat/completions) the description goes in tools and the reply arrives in tool_calls:

bash
import json
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.zukko.pro/v1", api_key=os.environ["ZUKKO_API_KEY"])

tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Returns the status of an order by number",
        "parameters": {
            "type": "object",
            "properties": {"order_id": {"type": "string"}},

In the Anthropic format (/v1/messages) the fields are named differently: a tool is described via input_schema, the call arrives as a tool_use block, and the result is returned as a tool_result block. The base address for the official Anthropic SDK has no /v1:

bash
import os
import anthropic

client = anthropic.Anthropic(base_url="https://api.zukko.pro", api_key=os.environ["ZUKKO_API_KEY"])
resp = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    tools=[{
        "name": "get_order_status",
        "description": "Returns the status of an order by number",
        "input_schema": {
            "type": "object",
            "properties": {"order_id": {"type": "string"}},
            "required": ["order_id"],
        },
    }],
    messages=[{"role": "user", "content": "Where is my order A-1042?"}],
)
for block in resp.content:
    if block.type == "tool_use":
        print(block.id, block.name, block.input)

See the request structure in the Chat Completions and Messages references; a detailed walkthrough using Claude is in the note on tool use.

MCP: a protocol for pluggable tools

The Model Context Protocol sets a standard for communication between an application with a model (the host) and programs that provide context (servers). The host creates an MCP client, which connects to a server and requests the list of tools (tools/list), then calls the one it needs (tools/call). The protocol is built on JSON-RPC 2.0 and has two transports: stdio for local servers and Streamable HTTP for remote ones. Besides tools, a server can offer resources and prompts.

The key difference is where the code lives and who wrote it. An MCP server is a separate program. The host doesn't know its functions in advance: it asks. So the same server connects to Claude Code, to an editor and to your application without extra work. A general description of a server is in the note what an MCP server is; in Claude Code such servers are connected with the claude mcp add command.

They are not rivals

The most common misconception: MCP replaces function calling. In practice the host takes the tool list from the MCP server, turns it into an ordinary tools list for the model request, and when the model calls a tool, forwards the call to the server. So function calling remains the "model asks for a call" mechanism, and MCP defines where tools come from and how they are executed. To the gateway there is no difference: it sees an ordinary model request with tools inside.

Comparison

QuestionFunction callingMCP
Who describes the toolYour application in each requestThe MCP server; the host requests the list
Where the code runsIn your applicationIn a separate process or service
ReuseYou copy descriptions between projectsOne server connects to different hosts
Ready-made third-party toolsYou integrate them yourselfConnected by a command or URL
Startup complexityMinimalYou need a server and a transport
ControlFull, all in your codeDepends on trust in the server

An MCP server versus a plain API

A separate question is how an MCP server differs from an API. A regular API is meant for a programmer who reads the documentation and writes calls. An MCP server is meant for a model: tools are described with schemas and text so the host can show them to the model without manual integration. An MCP server often simply wraps an existing API. If you already have a REST service and a single consumer, a separate MCP layer may not be needed.

When to choose which

A tools list in the request is enough if:

  • there is one application, few functions, and they are tightly tied to your logic;
  • you need full control over execution and permissions;
  • you don't want to run a separate process.

An MCP server is worth building if:

  • tools are needed by several hosts: Claude Code, an editor, your own bot;
  • you want to connect ready-made servers from other authors;
  • tools are written by another team or in another language;
  • you need to expose product capabilities "outward" to agents.

What about spending

Each tool's description is part of the request and is billed as input, regardless of whether it was written by hand or obtained from MCP. Suppose (hypothetically) the host connected 30 tools with 120 tokens of description each, and the session makes 100 requests: 3,600 × 100 = 360,000 input tokens. For claude-sonnet-5-5 (input 0.4, cache read 0.05 per 1M tokens as of October 18, 2026):

  • at the input price: 360,000 × 0.4 / 1,000,000 = $0.144;
  • with cache reads: 360,000 × 0.05 / 1,000,000 = $0.018.

For Claude the gateway sees the cache discount only in the Anthropic format (/v1/messages); in the OpenAI format all input is billed at the input price. So keep long tool lists in the Anthropic format and disable unneeded ones. Check current prices in GET https://api.zukko.pro/v1/models.

FAQ

Can I use MCP without function calling?

The model has to be able to call tools for MCP to be useful. How well models handle calls depends on the model, so test your choice on your own scenarios.

Do I need MCP if I have a single bot?

Probably not. A simple tools list and functions in code are simpler and more reliable. MCP pays off when tools must be reused.

Is a third-party MCP server safe?

It is a program that runs on your machine and can take actions. Connect only trusted servers, check permissions and don't give access to more than needed.

Does this work from Russia?

Access from Russia is through the gateway, with payment by SBP, MasterCard or crypto. Both approaches work the same through Zukko.

Create a key in the dashboard and run the get_order_status example to see the call loop with your own eyes.

zukko

Pay 25×
less

for Claude Code & ChatGPT

One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.

Get API keyDocumentation

api.zukko.pro · fetch_*

Function calling vs MCP: the difference and when to use · Zukko