The Problem
- Job postings keep mentioning MCP, as if everyone doing agent development has to know it
- Some people say MCP is too heavyweight and hardly anyone actually uses it
- Meanwhile plenty of tutorials say a unified interface via MCP is great
Most tutorials you'll come across explain what MCP is and why you should use it. After all that explanation, it's still hard to get an intuitive feel for the trade-offs. So today I'll flip the question around: when do you not need MCP? That's a better way to build intuition about it.
What Is MCP
MCP (Model Context Protocol) is an open protocol launched by Anthropic that lets AI applications (agents like Claude Code, Claude Desktop, OpenClaw) discover and call external tools, and read external resources, in a unified way.
That's the textbook definition. In practice, you can think of MCP as a kind of resource exposed to an agent. Before MCP existed, if you wanted an AI application to connect to services like Google Drive, GitHub, or Slack, every single AI application had to write its own integration code for every external service.
MCP is essentially a "standard socket" defined for that connection.
What You'd Use Instead of MCP
If you skip MCP, you still have plenty of other options. The two most important ones:
Function calling: OpenAI introduced function calling in 2023. It's actually simple — you pass a function signature to the LLM first.
{
"name": "get_weather",
"description": "Get the current weather for a specified city",
"input_schema": {
...
"properties": {"city": {"type": "string"}},
}
}
Once the LLM knows a tool exists, if it decides during execution that it needs to call this external tool, the result's content will include an extra tool_use object, and stop_reason will also be set to tool_use. Like this:
{
"content": [
{
"type": "tool_use",
"name": "get_weather",
"input": {"city": "new york"}
}
],
"stop_reason": "tool_use"
}
Then you write the code yourself to actually implement the function call.
if response.stop_reason == "tool_use":
tool_use = response.content[-1]
// ... call the weather-lookup function
In real-world work it's obviously less crude than this — you'd use a framework like LangChain.
CLI: This is really just another form of function calling — except you expose exactly one tool, and you tell the LLM upfront that it's a bash shell, so it can write whatever command it wants. The advantage is you don't need to tell the LLM what bash can do or how to use it — the LLM has already read enough material to know how to write bash commands on its own.
But using a CLI comes with real risk, since permission control is hard to get right.
From the Model's Perspective
First, you need to understand one thing: the model has no idea whether you're calling it through MCP or through function calling.
For example, when you register a weather-lookup tool, if you register it via MCP, here's what the model sees in its tools list:
{
"name": "get_weather",
"description": "Get the current weather for a specified city",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string"}
}
}
}
If you use function calling instead, here's what the model sees:
{
"name": "get_weather",
"description": "Get the current weather for a specified city",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string"}
}
}
}
Let's play a little game: can you spot the difference between these two JSON blocks? The answer is there isn't one. So there's no need to agonize over whether MCP versus function calling affects the model somehow. As far as the model is concerned, there's no difference at all.
The Downsides of MCP
If MCP is so great, why not just use it everywhere? Because MCP does have real downsides:
Large context overhead: Once you connect to an MCP server, the full schema (name, parameters, description) for every tool that server exposes gets stuffed into the model's context window up front — whether or not this particular conversation ever needs it.
Server resource consumption: An MCP server is something that runs continuously and has to stay alive. The more MCP servers you spin up, the more CPU and memory they eat on your machine.
Operational burden: Since an MCP server is a separate process, you're on the hook for restarting it when it crashes, sequencing startup order across multiple servers, and maintaining internal state over time.
The Upsides of MCP
MCP sounds pretty rough so far. So why do so many companies keep using it anyway? Because despite its downsides, its biggest strength is unifying the integration interface across your project's resources. A unified interface brings two benefits on its own:
Cleaner calling code: People who don't build software won't really feel this benefit, but anyone who does knows immediately how good a unified interface is. Your thousands of lines of legacy spaghetti code can suddenly collapse into a dozen lines. The more interfaces you have, the more bugs get buried, and buried deeper — maintenance becomes endless.
Easier third-party integration: Once every third-party resource is packaged as MCP, integrating them no longer takes a lot of custom effort. There's nothing technically clever about this — it's the same idea as standardizing currency or units of measurement. What matters is that someone has to actually go do it.
Conclusion
If your situation matches one of the following:
- You want to use a tool built by a third party
- You're using a tool shared across multiple platforms on your team
- You need to separate permissions across multiple roles
then MCP is worth considering. Otherwise, a lighter-weight approach — like plain function calling — is enough.
About the Author
I'm CodePlato.
I believe human creativity is the true tree of AI Coding. Code and models are only shadows projected onto the walls of the cave.
X: @codeplato2026
https://x.com/codeplato2026
Top comments (1)
The operational headache that bit me early with MCP in agent workflows is process supervision and connection latency. When an agent spins up ephemeral worker tasks or subagent sessions, initializing and handshaking with multiple STDIO MCP servers adds hundreds of milliseconds before the first turn even runs.
The other failure mode is error recovery. With plain in-process function calling or a simple script dispatcher, an unhandled exception or bad argument returns structured error text directly to the model in the same turn. With external STDIO MCP servers, an uncaught runtime panic or OOM in the child process frequently closes the pipe without a clean JSON-RPC response. If the client harness doesn't maintain dedicated heartbeat monitors and automatic restart logic for every server process, a single failing tool can hang the entire agent loop on a timeout.
For internal tools inside a single repo where schemas rarely change, keeping tool execution in a local dispatch table avoids maintaining a fleet of background server daemons.