MCP vs Function Calling: What MCP Adds, Context Costs, and When to Use Which
Understand the architectural differences between raw LLM function calling and the Model Context Protocol, including token overhead, progressive discovery, and selection criteria.
Function calling is a model-level inference capability that enables a Large Language Model (LLM) to output structured JSON arguments for a defined schema instead of plain prose. The Model Context Protocol (MCP) is an open, client-server application layer standard built on JSON-RPC 2.0 that governs how AI hosts discover, authenticate, inspect, and invoke tools, data resources, and prompt templates across isolated runtimes. In short: function calling is the low-level engine mechanism by which a model triggers actions, whereas MCP is the universal integration protocol that manages the ecosystem of tools and data sources feeding into that engine.
How MCP and Function Calling Work: Architectural Mechanics
To understand when to use each approach, you must separate the LLM's raw generation mechanism from the client-server system that organizes external capabilities.
+-------------------------------------------------------------------------+
| Plain Function Calling (Point-to-Point) |
| |
| +--------------------+ HTTP API Payload +------------+ |
| | Application Code | ------------------------------> | LLM API | |
| | (Hardcoded schemas | <------------------------------ | (Evaluates | |
| | & execution loop) | Tool Call Arguments | schemas) | |
| +--------------------+ +------------+ |
+-------------------------------------------------------------------------+
+-------------------------------------------------------------------------+
| Model Context Protocol (Decoupled Client-Server Architecture) |
| |
| +------------+ JSON-RPC +------------+ HTTP API +------------+ |
| | MCP Server | <=========> | MCP Client | ------------> | LLM API |
| | (Files, DB,| (stdio / | (In Host: | <------------ | (Evaluates |
| | GitHub) | Streamable | IDE, App, | Tool Schemas | selected |
| +------------+ HTTP) | Agent) | & Arguments | schemas) |
| +------------+ +------------+ |
+-------------------------------------------------------------------------+
Plain Function Calling
Plain function calling operates directly between your application code and an LLM provider endpoint (such as OpenAI's /v1/chat/completions or Anthropic's /v1/messages).
- Schema Injection: The developer defines a JSON Schema describing function names, descriptions, and parameter properties, then embeds that entire array into the
toolsparameter of the HTTP API request. - Inference & Structured Generation: The model evaluates the user prompt against the provided schemas. When it decides to invoke a tool, it suspends text generation and outputs a structured
tool_callsobject containing the tool name and validated JSON arguments. - Local Dispatch: Your application code parses the arguments, executes the corresponding function locally (e.g., executing a SQL query or invoking an internal API), and formats the output.
- Context Injection: The developer appends a new message with role
tool(ortool_result) containing the serialized string result and sends the entire conversation history back to the model for the next turn.
This pattern is point-to-point and tightly coupled. The application runtime must own every tool's implementation, credentials, lifecycle, and schema serialization.
The Model Context Protocol (MCP)
MCP standardizes tool and context delivery by establishing a clean separation between MCP Hosts, MCP Clients, and MCP Servers via JSON-RPC 2.0.
- MCP Host: The orchestration container (such as VS Code, Claude Desktop, Cursor, or an enterprise agent runtime).
- MCP Client: An adapter instantiated within the host that maintains a dedicated 1:1 session with an individual server.
- MCP Server: An independent, lightweight service that exposes specific capabilities over standardized transports.
Beyond basic function execution, MCP provides three core primitives and dedicated transport layers:
- Tools: Dynamic executable functions (analogous to function calling endpoints) exposed via
tools/listand executed viatools/call. - Resources: Read-only, URI-addressable data streams (
resources/list,resources/read) such asfile:///workspace/app.pyorpostgres://schema/users. Resources allow host applications to pull contextual data into the prompt without forcing the model to issue active tool execution commands. - Prompts: Pre-engineered prompt templates and workflows (
prompts/list,prompts/get) surfaced directly by the server to guide user interactions. - Standard Transports: Communication occurs locally via
stdio(standard input/output pipes with zero network latency and OS-level process isolation) or remotely viaStreamable HTTP(HTTP POST with Server-Sent Events and OAuth 2.1 authentication).
MCP does not replace function calling at the model level; instead, the MCP Client discovers tools from connected MCP Servers, converts their schemas into the target LLM's native function-calling format, routes the model's tool calls to the correct server, and normalizes the output back into the host context.
| Architectural Dimension | Plain Function Calling | Model Context Protocol (MCP) |
|---|---|---|
| Layer | LLM API inference parameter | Open application-layer protocol (JSON-RPC 2.0) |
| Topology | Tightly coupled, hardcoded in client code | Decoupled client-server architecture |
| Discovery | Static (schemas hardcoded per API call) | Dynamic (tools/list, resources/list, server/discover) |
| Capabilities | Executable tools only | Tools, URI Resources, Prompt Templates, Elicitation |
| Transports | Provider-specific HTTP REST API | Local stdio (process pipes) or Remote Streamable HTTP / SSE |
| Authentication | Unified under host application API keys | Granular, per-server OAuth 2.1 or local permission gates |
| Portability | Locked to specific application codebases | Shared across any compliant host (IDE, Desktop, CLI, Agent) |
A Worked Example: Database Lookup and Issue Creation
Consider an assistant that diagnoses a production database error and opens an engineering ticket.
Implementation via Plain Function Calling
In plain function calling, the developer manually constructs the JSON schemas for both operations and passes them directly to the LLM API:
{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Check failed payments in DB and file a ticket."}],
"tools": [
{
"type": "function",
"function": {
"name": "run_readonly_query",
"description": "Execute a read-only SQL query on PostgreSQL",
"parameters": {
"type": "object",
"properties": {
"sql": { "type": "string", "description": "SQL SELECT statement" }
},
"required": ["sql"]
}
}
},
{
"type": "function",
"function": {
"name": "jira_create_issue",
"description": "Create a Jira issue",
"parameters": {
"type": "object",
"properties": {
"summary": { "type": "string" },
"priority": { "type": "string", "enum": ["Low", "High", "Critical"] }
},
"required": ["summary", "priority"]
}
}
}
]
}
Your application code must embed the database credentials, initialize the database connection pool, manage the Jira REST API client, handle error serializations, and maintain the message turn loop. If another application (like a CLI or an IDE) needs the same tools, you must rewrite or import those libraries and rewire the schema definitions.
Implementation via MCP
With MCP, the capabilities reside in two isolated, reusable processes: an official Postgres MCP server (@modelcontextprotocol/server-postgres) running locally over stdio, and a Jira MCP server running remotely over Streamable HTTP.
- Initialization: The MCP Host launches the local Postgres server as a child process and connects to the remote Jira endpoint. Each sends an
initializehandshake negotiating capabilities. - Dynamic Discovery: The MCP Host sends
tools/listto both servers. The Postgres server returnsrun_readonly_query; the Jira server returnsjira_create_issue. - Context Provision: The host transforms those discovered schemas into the model's native format.
- Execution Cycle: When the model outputs a call for
run_readonly_query, the host catches it, dispatches a JSON-RPC request to the Postgres server process overstdio, receives the JSON-RPC response, and feeds the output back to the model. - Security Isolation: The database credentials remain inside the Postgres server process environment; the host runtime never handles raw connection strings or Jira API secrets.
Context Token Costs and Tokenomics
Every tool definition made available to an LLM consumes prompt tokens on every single request turn, regardless of whether that tool is called.
+-------------------------------------------------------------------------+
| Naive Static Loading (All Tools Injected Every Turn) |
| |
| Prompt Payload: [ System Prompt (~1k) ] |
| [ User Message (~500) ] |
| [ 30 MCP Tool Schemas (~8,500 tokens) ] |
| ==> 10,000 prompt tokens per turn |
+-------------------------------------------------------------------------+
+-------------------------------------------------------------------------+
| Progressive Tool Discovery (Lightweight Search Meta-Tool) |
| |
| Turn 1: [ search_tools schema (~250 tokens) ] |
| Model searches: "query postgresql database" |
| |
| Turn 2: [ Loaded: run_readonly_query schema (~350 tokens) ] |
| Model executes query |
| ==> ~1,100 total prompt tokens per turn (89% reduction) |
+-------------------------------------------------------------------------+
The Math of Schema Bloat
A typical, production-grade tool schema—including parameter descriptions, enum lists, and nested object constraints—averages 200 to 450 tokens.
- 10 tools: ~2,500 to 4,500 tokens per turn.
- 30 tools (e.g., 3 standard MCP servers with 10 tools each): ~7,500 to 13,500 tokens per turn.
- Over an 8-turn conversation: Tool definitions alone consume between
60,000and108,000cumulative input tokens.
Beyond API billing costs, high token overhead causes severe attention degradation ("lost-in-the-middle" effects), where models struggle to adhere to core system instructions because the prompt is dominated by unused schema definitions.
Mitigation: Progressive Tool Discovery
To prevent MCP tool proliferation from exhausting the context window, modern MCP clients implement Progressive Tool Discovery using a three-layer pattern:
- Catalog (Lightweight Meta-Tool): The host hides full tool schemas from the initial prompt. It exposes only a single meta-tool:
search_tools(query: string)(~150 tokens). - Inspect: The model queries the catalog (e.g.,
search_tools("salesforce record")) and receives concise matches (name and 1-line description). The model then invokesget_tool_details(tool_name)to dynamically load the exact JSON schema into context. - Execute: The model executes the target tool.
Progressive discovery reduces upfront context overhead by 80% to 92% in environments with dozens of available server tools. However, modifying or injecting tool definitions mid-turn alters the prompt prefix, which can invalidate the LLM provider's KV prompt cache. When using static toolsets under 10–15 functions, keeping definitions fixed to leverage prompt caching is often more cost-effective than dynamic schema swapping.
Trade-offs and When NOT to Use MCP
MCP solves distribution and modularity, but introduces latency and architectural overhead. Choosing the right abstraction depends on your deployment environment and lifecycle requirements.
Is the toolset fixed, internal,
and part of a single service?
/ \
YES NO
/ \
Is latency critical (<100ms) Do multiple clients/agents
or running on edge workers? need to discover and share
/ \ these tools dynamically?
YES NO / \
/ \ YES NO
[ Plain Function ] [ Plain Function ] [ MCP ] [ Plain Function ]
Calling Calling Calling
When Plain Function Calling is the Right Choice
- Single-Purpose, Monolithic Applications: If you are building a dedicated customer support bot with 3 fixed internal API calls, adding MCP server wrappers introduces unnecessary JSON-RPC serialization, process management, and connection plumbing.
- Edge and Serverless Execution: Serverless environments (e.g., Cloudflare Workers, AWS Lambda) favor minimal cold starts. Spawning child processes for
stdioor maintaining persistent stateful HTTP sessions adds latency and infrastructure complexity. - Ultra-Low Latency Pipelines: Voice agents or real-time streaming pipelines requiring sub-150ms round trips should avoid the inter-process communication (IPC) hops inherent in client-server transport layers.
When MCP is the Right Choice
- Extensible AI Applications & IDEs: When building platforms (like coding assistants, workspace agents, or desktop copilots) where end users or third parties attach arbitrary tools and databases without modifying host source code.
- Multi-Agent Systems: When diverse agents need to share a unified catalog of enterprise tools across distinct environments (Node.js, Python, Go).
- Strict Security Boundaries: When tools require elevated credentials (e.g., internal shell access, database root credentials) that should run inside isolated containers or distinct network boundaries rather than inside the main application runtime.
Common Mistakes
- Treating MCP and Function Calling as Mutually Exclusive: Developers often ask whether to build with MCP or function calling. MCP clients use the model's native function calling under the hood. You use MCP to standardize how tools are exposed, but the LLM still relies on function calling to invoke them.
- Dumping Every Connected MCP Server into Context: Connecting 5 MCP servers (e.g., GitHub, Slack, Postgres, FileSystem, Jira) and passing all 60+ generated schemas into the initial prompt will degrade reasoning and balloon token consumption. Use progressive discovery or explicit tool allowlists (
allowedTools). - Passing Massive Raw Payloads Through the Model: Returning large SQL query dumps (e.g., 5,000 rows of JSON) directly as a tool result forces thousands of data tokens into the context window. Use MCP Resources or temporary storage references, returning only summary metadata and URIs to the model.
- Ignoring Transport Failure Modes:
stdioprocesses can crash silently, and remoteStreamable HTTPstreams can experience dropped connections. Production MCP clients must implement robust heartbeat pings, automatic process restarts, and timeout handling ontools/call. - Busting the Prompt Cache with Dynamic Tool Mutations: Frequently toggling individual tools on and off across conversational turns invalidates LLM prompt prefix caches. Group stable tools together or rely on a permanent
search_toolscatalog entry to preserve KV cache hits.
FAQs
Does MCP replace function calling?
No. MCP builds on top of function calling. The LLM still uses native function calling to emit structured arguments, while MCP acts as the protocol layer that discovers tool schemas, manages process connections, and dispatches the execution requests to external servers.
Can I use MCP with any LLM provider?
Yes. Because MCP operates at the application host layer, any model capable of structured output or tool calling (OpenAI, Anthropic, Gemini, or open-weight models via Ollama/vLLM) can act as the reasoning engine for an MCP host.
What is the difference between an MCP Tool and an MCP Resource?
An MCP Tool is an active, executable function with side effects or dynamic parameters that the LLM decides to call during inference. An MCP Resource is a passive, URI-addressable data source (like a file, database schema, or log stream) that the host application or user reads directly into context without requiring model execution turns.
What is the performance overhead of MCP compared to direct API calls?
For local servers running over stdio, the overhead is negligible (typically sub-millisecond JSON-RPC IPC latency). For remote servers over Streamable HTTP, latency is comparable to standard REST API calls, with slight overhead for HTTP header negotiation, session tracking, and OAuth token validation.
Sources
- Model Context Protocol Architecture Overview modelcontextprotocol.io
- OpenAI Function Calling Guide developers.openai.com
- MCP Client Best Practices: Progressive Tool Discovery modelcontextprotocol.io
- Anthropic Research: Code Execution with MCP anthropic.com
The stories that matter for people who build with AI, with the source for every claim. Free, no spam.
Feed, daily deep-dive and bytes — readable offline, with push alerts for the topics you follow.