MCP Servers Explained: What They Are, and When You Shouldn't Bother
MCP (Model Context Protocol) gets pitched as the default way to give an agent tools now, which means it’s also getting reached for in situations where a plain function call would have been simpler, faster, and easier to debug. Both things are true at once: MCP solves a real problem, and it’s not free.
If you haven’t seen the layering first, read tool-calling vs. function-calling vs. MCP first — this piece assumes you know MCP sits underneath the tool-calling loop, not next to it.
What an MCP server actually gives you
A running process that speaks a standard protocol (JSON-RPC over stdio or HTTP) and exposes three kinds of things to any connected host: tools (functions the agent can call), resources (data the agent can read, like files or query results), and prompts (reusable prompt templates the host can surface).
from mcp.server.mcpserver import MCPServer # mcp 2.x — see note below if you're on 1.x
mcp = MCPServer("reporting-db")
@mcp.tool()
def query_database(sql: str) -> str:
"""Run a read-only SQL query against the reporting database."""
return run_readonly_query(sql)
@mcp.resource("schema://tables")
def list_tables() -> str:
"""Expose the current schema so the agent doesn't have to guess column names."""
return get_schema_summary()
if __name__ == "__main__":
mcp.run()
(If you’re still on mcp 1.x, the class you want is FastMCP from
mcp.server.fastmcp instead — it was renamed to MCPServer in the 2.x
release. The decorators and everything else below work identically either
way; only the import and class name changed.)
Once this is running, it works identically whether it’s connected to Claude Code, Claude Desktop, or a custom agent host you wrote yourself. That portability is the entire value proposition — and it’s real when you actually need it.
When MCP is genuinely the right call
- You’re integrating a tool that multiple different agent hosts need to use. A database connector, a search API, an internal tool — write it once as an MCP server, and every host that speaks MCP gets it for free.
- You’re distributing a tool for other people to plug into their own agents. This is the actual “why does MCP exist” case: you don’t control what host someone connects your tool to, so a standard protocol beats a custom SDK per framework.
- You want tool definitions decoupled from a specific agent’s codebase, so the tool can be versioned, deployed, and updated independently of the agent using it.
When it’s overhead you don’t need
- A single agent, in one codebase, calling one function you wrote. Running a
separate process, managing its lifecycle, and debugging across a protocol boundary
is strictly more moving parts than
tools=[my_function_schema]and a direct function call in the same process. - Latency-sensitive tool calls. Even a local stdio-based MCP server adds process-boundary overhead — serialization, IPC round-trip — that an in-process function call doesn’t have. For a tool called in a tight loop, that adds up.
- Early prototyping. Standing up a server, a manifest, and a connection handshake before you’ve even validated the agent’s behavior is exactly the “building infrastructure instead of shipping the thing” trap. Hand-roll the tool call first; wrap it in MCP later if and when portability actually becomes a real requirement.
- Debugging a new integration. A stack trace from a direct function call points at your code. A failure across an MCP connection can mean the server crashed, the transport dropped, the schema didn’t match, or the host’s client had a bug — one more layer to rule out before you find the actual problem.
The actual decision rule
Ask: will more than one agent host ever need this tool, or am I distributing it for others to plug in? If yes, MCP is the right layer — that portability is exactly what it’s for. If no — one agent, one codebase, one use — a direct function call in your tool-calling loop does the same job with one less network boundary between you and the bug you’re chasing at 11pm.
MCP is infrastructure. Infrastructure is worth building when more than one thing depends on it. Before that point, it’s usually just overhead wearing infrastructure’s clothes.