When to Use MCP vs Raw Function Calling

RoadmapsAI Engineering

Scenario

You're building a simple, single-purpose Slack bot that checks the weather. You decide to spin up a dedicated MCP server in a Docker container just to expose the weather API to your LLM, adding complexity and latency.

A developer building a single-purpose weather chatbot decides to spin up a separate MCP server instance instead of passing the weather schema directly to the LLM. Why is this structurally inefficient?

Mental model

Raw function calling is a direct, hardcoded wire. MCP is a universal switchboard.

You built the raw execution loop in the Function/tool calling lesson. You already know how to pass a JSON schema to `client.chat.completions.create`. MCP doesn't replace that underlying mechanism; it wraps it in a switchboard. MCP is built for runtime discovery and scaling across many models and tools. But if you have a closed, single-purpose app, that switchboard is just overhead. Direct APIs are faster and cheaper.

Deep dive

In standard function calling, you hardcode the schema and send it directly in the LLM's `tools` array. The model replies instantly with a tool call. It's a single network hop. It's extremely fast and requires zero extra infrastructure.

Raw function calling is a direct, single-hop integration with zero protocol overhead.

MCP introduces a negotiation handshake. Before the Host can invoke the LLM, it must send an `initialize` request to the MCP Server, wait for the response, send a `tools/list` request to discover capabilities, and wait for that response. Only then does it pass the schemas to the LLM.

MCP requires a multi-step JSON-RPC negotiation phase before inference begins.

This handshake means MCP inherently introduces latency. It is structurally impossible for MCP to be faster than a raw, direct function call. If a developer benchmarks an MCP server against a raw API call and sees a 50ms increase, the server isn't broken—that is the mathematical reality of protocol negotiation.

MCP adds latency; it does not reduce it. Its benefit is architectural scalability, not execution speed.

So when does MCP earn its complexity? Scale. If you are building an open ecosystem (like an AI IDE) that needs to dynamically discover tools from third-party plugins at runtime, MCP is mandatory. If you are integrating 10 different tools across 4 different LLMs, the M×N integration problem justifies the switchboard.

MCP is for open ecosystems, runtime discovery, and massive multi-tool scale.

Conversely, if you are building a closed system—like a dedicated customer support bot with exactly two internal APIs and one LLM—you should use standard raw function calling. Adding an MCP server to a closed, single-purpose system is pure over-engineering.

For single-purpose, closed systems, raw function calling is definitively faster and cheaper.

Code examples

Raw Function Calling: The single network hop

# 1. You hardcode the schema
weather_tool = {
    "type": "function",
    "function": {"name": "get_weather", "parameters": {...}}
}

# 2. One direct call to the LLM provider
response = client.chat.completions.create(
    model="gpt-4o",
    messages=user_messages,
    tools=[weather_tool]
)

Zero discovery overhead. You know the tool exists, you format it perfectly, and you send it directly to the model. This is the lowest possible latency.

The MCP overhead: Multi-step negotiation

# To get the same result, the Host must first negotiate:
# 1. Host -> Server: initialize
# 2. Server -> Host: initialize_result
# 3. Host -> Server: tools/list
# 4. Server -> Host: tools_result (containing the schemas)

# 5. NOW the Host translates and calls the LLM provider
response = client.chat.completions.create(
    model="gpt-4o",
    messages=user_messages,
    tools=translated_mcp_tools
)

Steps 1 through 4 add network latency before the LLM even sees the prompt. This overhead is only justified if you don't know what tools are available until runtime.

Common mistakes

Glossary

Raw Function Calling
The standard process of directly passing a hardcoded JSON schema to an LLM provider's API (e.g., in the OpenAI `tools` array) without any intermediary protocol.
JSON-RPC Negotiation
The multi-step handshake MCP uses to discover tools dynamically before the LLM can even be invoked.

Recall questions

Questions & answers

How is MCP different from a regular REST API?

A regular REST API integration (like raw function calling) involves hardcoding the specific tool schema and sending it directly to the LLM in a single hop. MCP is a dynamic protocol that requires the client to negotiate a connection and actively query the server to discover its capabilities at runtime before translating them to the LLM.

Approach: Contrast hardcoded schemas (REST/Function Calling) with dynamic runtime discovery (MCP). Highlight the latency tradeoff.

When would you choose raw function calling over MCP?

I would choose raw function calling when building a single-purpose, closed system where all tools are known in advance (like a dedicated customer support bot). Implementing MCP in this scenario adds unnecessary negotiation latency and infrastructure overhead without providing the runtime discovery benefits that justify the protocol.

Approach: Highlight the overhead of MCP's negotiation handshakes. Position MCP as a solution for open ecosystems, not simple closed scripts.

Continue learning

Previous: Function / Tool Calling

Previous: The M×N integration problem and protocol necessity

Return to AI Engineering Roadmap