MCP: The Universal Adapter
After this you can decide whether a given integration belongs on MCP at all, wire an existing server into a host without drowning it in tools, and recognize when a tutorial you are following is teaching a transport that no longer exists.
MCP gets introduced as a thing the model learned to do, and that framing leads people wrong before they write a line of config. The model never speaks MCP. The Model Context Protocol is a wire protocol — a client-server convention built on JSON-RPC 2.0 — that standardizes how an application connects a language model to outside tools, data, and prompt templates. A host (Claude Desktop, Cursor, an agent you wrote) embeds a client; the client talks over a transport to one or more servers; each server exposes up to three primitive types. Tools are model-callable functions, the part nearly everyone uses. Resources are read-only data the host can pull into context, like a file or a database row. Prompts are templated workflows a person triggers. The model's only window into any of this is the tool descriptions the host injects into its context. Everything else is plumbing between host and server, and knowing that the model sees descriptions and nothing else is the line between people who can debug an MCP setup and people who poke at it.
The reason the protocol exists is an arithmetic one. Before a shared standard, connecting M applications to N tools meant writing M×N bespoke connectors, because every app reinvented its own way to reach every tool. MCP turns that into M+N: each app speaks the protocol once, each tool exposes it once, and any app reaches any tool through the same convention. The pitch that lands with engineers is "USB-C for AI applications," and it is the right anchor because the value is entirely in the standardization, not in any new capability.
This is also where the honest answer lives. MCP buys you nothing over a plain function definition when you are writing a single bespoke agent that calls one API you already control. Function calling let models call tools before MCP existed; the protocol does not add a capability there, it standardizes the wiring and the marketplace. Simon Willison has made the same point since MCP launched: it is a distribution and standardization play, not a new capability. It earns its keep in three situations: the same tool must be reused across hosts and agents you do not control, you want users to add capabilities without you redeploying, or you are consuming the growing ecosystem of pre-built servers. Outside those, a function in your own codebase is simpler, and reaching for MCP anyway is the first way people overspend.
That ecosystem framing drives the two decisions most people get backwards. The first is build versus use. The beginner instinct is "I'll build a server," when the operator default is to wire an existing one (filesystem, GitHub, Postgres, Slack, Sentry, a browser server) and learn how the agent actually behaves with real tools before building anything. The second decision comes only if you do build, and it is local versus remote transport. People reach for a remote HTTP server because "production means hosted," but for a tool only you or your IDE will call, a local stdio server is radically simpler: no auth, no deployment, no transport edge cases, instant iteration. Remote servers are the answer to multi-user, multi-client distribution, and that need brings auth, rate limiting, multi-tenancy, and observability as hard requirements rather than nice-to-haves. Default to local stdio and let an actual distribution requirement be the thing that moves you off it.
Once a server is wired in, the one concern that is genuinely MCP's to carry is the context budget. Every connected tool's description rides in context on every single call, so the tool list is a line item you curate, not a free buffet. A useful working ceiling is around twenty active tools. Past roughly thirty, descriptions start to overlap and the model's tool-selection accuracy measurably degrades. Beyond a hundred it is close to guaranteed to misfire. How each tool is named, described, and shaped so the model actually uses it well is its own discipline, and the tools lesson owns it. MCP matters here because it is the layer that multiplies whatever you decide across every server you connect.
Where it breaks
The failure that catches almost everyone is tool sprawl. Connecting every interesting server you find feels like progress, and then the agent gets slow, expensive, and starts picking the wrong tool among sixty similarly named ones, because all of those descriptions were already spending context budget before the user typed anything. The fix is unglamorous: connect what the task needs, disable the rest, prefer servers that let you toggle toolsets.
The transport failures are subtler because they come from following advice that was correct when it was written. MCP's transport layer churned hard in its first year, and the spec moved underneath the tutorials. The original specification shipped two transports: stdio, where the server runs as a local subprocess over stdin and stdout, and HTTP+SSE, a two-endpoint design with a separate Server-Sent-Events channel for server-to-client messages. The HTTP+SSE design was stateful, awkward behind load balancers, and a poor fit for serverless, so the 2025-03-26 spec revision replaced it with Streamable HTTP — a single-endpoint transport that can optionally upgrade to SSE for streaming and runs statelessly. Auth followed the same arc: early MCP had no real auth story, the community shipped a half-baked OAuth flow, and the 2025-06-18 revision formalized OAuth 2.1 with the server acting as a resource server separate from the authorization server. Two breakages fall straight out of that timeline. Build on HTTP+SSE because a six-month-old tutorial showed it, and you are building on a deprecated transport. Deploy a stateful SSE session behind a load balancer and your sessions drop the moment it scales horizontally. If you advise on remote MCP without knowing SSE is legacy and Streamable HTTP is the target, you are repeating early-2025 blog posts back to people.
One more boundary worth naming and then leaving alone: connecting a server that can read untrusted content and also call powerful tools assembles a real security problem — tool poisoning, rug pulls, the lethal trifecta. That attack surface is large enough to be its own lesson, and it is. Treat this as the pointer, not the coverage.
Run this checklist before you connect or build any MCP server. It exists to stop the two backwards decisions and the transport trap at the moment you would otherwise make them, while the choice is still cheap.
MCP — before you connect or build a server
1. Should this be MCP at all?
[ ] Will this tool be reused across hosts/agents I don't control,
OR consumed from the pre-built ecosystem,
OR added by users without me redeploying?
→ If NO to all three: a plain function in my own code is simpler. Stop.
2. Use before build.
[ ] Searched the reference + partner servers for one that already exists?
[ ] If building: written down the specific need no existing server meets?
3. Transport — default local.
[ ] Single-user / my-IDE-only? → stdio (no auth, no deploy). Stop here.
[ ] Genuinely multi-user / multi-client distribution?
→ remote Streamable HTTP. NOT HTTP+SSE (deprecated 2025-03-26).
→ auth = OAuth 2.1 (2025-06-18 spec). Don't hand-roll it.
4. Context budget (every connected tool taxes every call).
[ ] Counted total tools across all connected servers?
[ ] Disabled servers I'm not actively using this session?
[ ] No two tools the model could confuse by name?
5. Following a tutorial?
[ ] Checked its date. Pre-2025-03-26 transport advice is stale.Three of these five items carry the weight. Build-versus-use and local-versus-remote (items 1 to 3) are the decisions people drift past on instinct, so the checklist forces them into explicit yes/no answers. Item 4 turns the tool list into something you count rather than something that grows silently, and item 5 is the cheapest insurance here, because the date on a transport tutorial tells you more than its content does.
Worked example
IllustrativeIllustrative. A constructed walkthrough of the decision, not a real deployment.
Say you want an agent that reads issues from your team's GitHub and posts a daily digest to one Slack channel. The reflex is to build a server and host it.
Walk it through the checklist instead. Item 1: are you reusing this across hosts you do not control, or letting users add to it, or pulling from the ecosystem? No. It is one agent you run, talking to two systems. That answer alone says a custom server is the wrong instinct, but GitHub and Slack are exactly the case where existing reference servers cover the need, so you wire those in rather than write anything. Item 3: single-user, running from your own machine, so the transport is stdio. No auth flow, no deployment, no load balancer. You are done before you have written a server.
Now contrast the path that skips the checklist:
Skipped the checklist: built a custom remote server on HTTP+SSE (a tutorial from eight months ago showed it), deployed it behind a load balancer, then spent a day on OAuth.
Result: sessions drop intermittently once a second instance spins up (stateful SSE doesn't survive horizontal scaling), and the transport is deprecated, so the next SDK upgrade will break it again.
The two paths reach the same agent. One took an afternoon on stdio with servers that already existed; the other imported deployment, auth, and a dead transport for an integration that never needed any of them.
The whole point of running the gates is that the cheap answer (a function, an existing server, or stdio) is the right one far more often than the instinct to build and host suggests.