What MCP Actually Standardises

Every explanation of MCP reaches for the same picture. It is USB for tools. One plug, any device, no more hand-built adapters. That picture is true and it stops exactly where the interesting part begins, because a plug shape tells you nothing about what is on the other end.
MCP (Model Context Protocol) standardises three things a server can offer, two ways to reach it, and one handshake that happens before anything else. That is the whole protocol. Learn those three lists and you can read any MCP server, write one, and predict how it will break. In the last post MCP was the answer to bespoke glue. Now we open it.
In short: A server exposes tools, resources and prompts, and they differ by who decides to use them. It connects over stdio or HTTP, and that choice decides your auth and deployment story. The connection opens with a capability handshake, so the tool list is discovered at runtime, not shipped. What MCP does not give you is a namespace, a version contract or any notion of trust.
Three Things a Server Can Expose, and the Difference Is Who Decides
Most people meet MCP through tools and assume tools are all there is. A server can expose three kinds of thing, and the split is not about what they contain. It is about who chooses to use them.
A tool is model-controlled. You hand over a name, a description, and a schema for the arguments, and the model reads that description and decides on its own to call it. Everything from the previous post applies: the model asks, your code runs it.
A resource is application-controlled. It is data the server can hand over, a file, a record, a query result, identified by a URI. The model does not reach for a resource. The host decides what to load into the context window and when. That is the whole difference, and it exists because pulling data should be a decision your application makes, not one the model makes mid-sentence.
A prompt is user-controlled. It is a prepared template the server offers, surfaced in the host as something a person picks: a slash command, a menu item. The server author is saying "here is the right way to ask for this," instead of hoping each user invents it.

Get this split wrong and the symptoms are predictable. Expose a data fetch as a tool and the model will call it whenever it feels like, at your cost. Expose an action as a resource and nothing will ever trigger it.
Two Transports, and the Choice Decides Your Auth Story
A server has to be reachable. MCP defines two ways, and picking one is a deployment decision disguised as a technical detail.
stdio is a local child process. The host launches the server on the same machine and talks to it over standard input and output. There is no port, no network, no login. The server already runs as you, with your permissions and your files, so authentication is a question nobody has to ask.
HTTP is a remote server, reached over the network, streaming its replies back. Now every question stdio dodged comes due at once. Who is calling. What are they allowed to do. Where does the token live, how does it get refreshed, what happens when it expires halfway through an agent run.
So the rule is short. Local and personal goes over stdio. Shared, hosted or multi-user goes over HTTP, and you own an auth story from the first day. The mistake is starting with stdio because it is easy, building on it for a month, and discovering that "can my team use this too" is not a config change.
One Handshake, and Why the Tool List Is Never Fixed
An MCP connection does not begin with a call. It begins with an exchange where both sides say what they support. The client says which protocol version it speaks and what it can handle. The server answers with its version and which of the three kinds of thing it offers. Only then does the client ask for the actual list of tools, and only then can anything be called.
This is the part with real consequences. The tool list arrives at runtime. It is not compiled in, not shipped with your app, not reviewed by you. A server can return a different list tomorrow because it was updated, because a feature flag flipped, or because it decided to. Your agent's capabilities are late-bound, and late binding is exactly why "it worked yesterday" happens without a single line of your code changing.
What MCP Does Not Standardise
Here is the part the USB picture hides, and it is where the real work is. A standard that solves wiring does not solve everything that wiring touches.
There is no namespace. Two servers can both expose a tool called search, and nothing in the protocol objects. The model picks by name and description, so the failure is not an error, it is the model quietly calling the wrong one. Near-collisions are worse than exact ones: two tools whose descriptions read alike produce a model that chooses inconsistently, and it looks like the model being unreliable.
Tool descriptions cost context on every call. Each tool ships a name, a description and an argument schema, and all of it sits in the window for the whole conversation. Connect several rich servers and the schemas alone can crowd out the actual work. The point where this bites is lower than people expect. It is why serious clients have moved to loading schemas on demand rather than pasting every tool up front, and why a fourteen-tool server is a design decision and not a feature list.
There is no version contract. A server can rename a tool, change an argument, or tighten a schema, and the first you learn of it is an agent behaving differently. You did not pin anything, because the protocol gave you nothing to pin.
And nothing here is a trust boundary until you make one. This is the one that matters. A tool description is written by whoever wrote the server and lands in your model's context as text. So does every result the tool returns. Both are untrusted input, and both are a prompt-injection surface, which means a server you did not write can attempt to steer your agent using nothing but its own tool descriptions.

Least privilege is the answer, and it is the same answer as everywhere else in this course. Connect the servers you actually need. Give each one the narrowest reach that still works. Treat what comes back as input, not as instruction. That is a whole level of its own, and it is coming.
The Plug Was the Easy Part
Go back to the opening. MCP really did end the bespoke glue, and the N times M problem really is gone. That is worth having, and it is what the standard set out to do.
But standardising the connection does not standardise the consequences of connecting. Names still collide, context still costs money, versions still drift, and text from a stranger still reaches your model. MCP moved those problems out of the adapter and into your architecture, where they are at least visible.
So plug things in, and stay aware that a universal plug makes it trivially easy to connect something you have not read. Which is fine while an agent only talks to tools. It gets sharper the moment agents start talking to each other.