Two Specific Questions
Article 01 covered MCP's architectural advantage: standardized tool reuse. Engineers making an actual selection ask two more concrete questions:
- How large is the MCP process communication overhead? Does it affect user experience?
- When does MCP's code size actually become smaller than Function Calling?
Real benchmark data answers both.
Benchmark Design
Test subject: the same "search issues" feature
- Method A (Function Calling): tool definition and handler live in Agent code, executed as a direct Python function call
- Method B (MCP): tool runs in a standalone Server process, called via stdio subprocess
20 calls each (5 warm-up excluded), recording P50/P90/mean.
Latency Results
Method Mean P50 P90 Min
──────────────────────────── ──────── ──────── ──────── ────────
Direct function call 0.01ms 0.01ms 0.01ms 0.005ms
MCP stdio call 2.09ms 2.05ms 2.37ms 2.00ms
MCP overhead per call: +2.08ms (283x slower than direct)
MCP server startup (one-time): 570ms
Calls to amortize startup cost: ~274
283x sounds alarming. In context: LLM inference takes 5–30 seconds. Tool calls are one step in that chain. At this timescale, 2ms of protocol overhead is imperceptible.
When the 2ms overhead actually matters:
Typical Agent task: LLM inference 15s + tool call 2ms → 0.01% overhead
→ negligible
Real-time chatbot: target < 200ms, tool call on critical path
→ evaluate carefully
High-frequency automation: 100 tool calls/second
2ms × 100 = 200ms extra latency/sec
→ evaluate carefully
The MCP Server initializes once per session and serves all tool calls after that. Sessions exceeding 274 tool calls (570ms ÷ 2.08ms) reach parity with Function Calling on total latency. Most Agent tasks surpass that threshold; the startup cost amortizes fast.
Code Size Results
Function Calling (definition + handler + Agent loop): 43 lines
MCP Server (standalone process, complete server): 32 lines
MCP Agent code (zero tool code): 0 lines
At N=1 the gap is small. It grows with every additional project:
Projects sharing one tool FC total lines MCP total lines MCP saves
──────────────────────────────────────────────────────────────────────────
N=1 43 32 11
N=2 86 32 54
N=3 129 32 97
N=5 215 32 183
Function Calling code scales linearly (every Agent maintains its own tool code). MCP code stays constant (Server written once). The reuse benefit compounds with each additional project.
Why 283x Is Not the Right Metric for Selection
The raw multiplier misleads. A tool call's actual cost has three components:
Total latency = LLM inference + tool execution + protocol overhead
Typical scenario:
LLM inference: 8,000ms
Tool execution: 200ms
MCP protocol: 2ms
─────────────────────────────
Total: 8,202ms
Function Calling: 8,200ms
MCP: 8,202ms
Difference: 0.024%
Protocol overhead disappears next to LLM inference time. Latency doesn't drive the selection decision.
Decision Framework
Core question: how many projects will use this tool?
Projects = 1, AND:
Tool logic < 30 lines
Rapid prototype, unclear if long-term
→ Function Calling
Projects >= 2, OR:
Tool needs state (connection pool, auth session)
Non-engineers need to install/configure it (Claude Desktop ecosystem)
Team wants a shared, centrally maintained tool standard
→ MCP Server
MCP is wrong when:
Real-time requirement < 10ms (API gateway, live recommendations)
Tool logic is tightly coupled to Agent logic; separation adds nothing
Session lifetime is very short (< 100 tool calls) and startup time matters
Selection logic in one diagram:
Tool reuse (N projects × M calls)
│
├── Single project, infrequent ──────→ Function Calling (simpler)
│
├── Multiple projects sharing ────────→ MCP Server (reuse pays off)
│
├── Needs state ───────────────────────→ MCP Server (process holds state)
│
└── Real-time requirement < 10ms ────→ Function Calling (no overhead)
Side-by-Side Implementation
Function Calling (43 lines — tool code in every Agent):
# Tool schema
SEARCH_TOOL = {
"name": "search_issues",
"description": "Search Jira issues by keyword",
"input_schema": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"]
}
}
# Tool implementation
def search_issues(query: str) -> str:
results = [i for i in ISSUES if query.lower() in i["summary"].lower()]
return "\n".join(f"[{i['key']}] {i['summary']}" for i in results)
# Agent loop (every Agent needs this)
def run_agent(user_input: str):
client = anthropic.Anthropic()
messages = [{"role": "user", "content": user_input}]
while True:
response = client.messages.create(
model="claude-sonnet-4-6", tools=[SEARCH_TOOL], messages=messages)
if response.stop_reason != "tool_use":
return response.content[0].text
tc = next(b for b in response.content if b.type == "tool_use")
result = search_issues(tc.input["query"])
messages.extend([...])
MCP Server (32 lines once — zero tool code in Agent):
# jira_server.py (written once, reused by every Agent)
server = Server("jira-tools")
@server.list_tools()
async def list_tools():
return [Tool(name="search_issues",
description="Search Jira issues by keyword",
inputSchema={"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"]})]
@server.call_tool()
async def call_tool(name, arguments):
query = arguments["query"].lower()
results = [i for i in ISSUES if query in i["summary"].lower()]
text = "\n".join(f"[{i['key']}] {i['summary']}" for i in results)
return [TextContent(type="text", text=text)]
async def main():
async with stdio_server() as (r, w):
await server.run(r, w, server.create_initialization_options())
asyncio.run(main())
# Agent configuration: one line in settings.json — no tool code in Agent at all
Summary
Three conclusions from real numbers:
- 2ms overhead is negligible in Agent contexts: LLM inference is 8,000ms, protocol overhead is 2ms — 0.024% of total. "283x slower" is technically accurate but practically misleading
- 570ms startup cost needs a warm-up design: if the Agent must respond to the first tool call immediately, initialize the MCP Server at session start rather than on first use
- Code reuse is the core reason to choose MCP: at N=1 the difference is small (43 vs 32 lines); at N=3 projects Function Calling needs 129 lines while MCP stays at 32 — the gap grows with every additional project and every additional tool
References
- Full demo code: mcp-06-comparison
Check out PrimeSkills — a curated marketplace of AI agents and skills that have been validated in real-world, enterprise-grade workflows. No fluff, just what actually works.
Find more useful knowledge and interesting products on my Homepage
Top comments (0)