MCP Server
Tools are model-controlled, resources are application-controlled. That column decides which primitive a capability belongs to.
Where the server sits among MCP roles
Three roles. The host is the application a person uses, such as an editor or a chat client. The client lives inside the host and holds one connection. The server is a separate process that exposes capabilities over that connection.
The server is where your code goes. It decides what a model can reach, which makes it a boundary before it is a feature.
The three primitives, and who controls each
The specification defines what a server exposes, and it comes with a column most introductions leave out.
| Primitive | Control | What it is | Example |
|---|---|---|---|
| Prompts | User-controlled | Templates the user invokes | Slash commands, menu options |
| Resources | Application-controlled | Contextual data the client attaches | File contents, git history |
| Tools | Model-controlled | Functions the model can call to act | API requests, file writing |
Read down the control column first. It answers the question that matters when you design a server: who decides this happens.
A prompt runs because a person chose it. A resource is read because the host decided to attach it. A tool runs because the model asked for it.
Choosing a primitive for a capability
Suppose you are exposing a company handbook.
As a resource, the host decides when to attach it. A user opens a support conversation, the application attaches the relevant section, and the model works from what it was given.
As a tool, search_handbook becomes something the model invokes when it
judges the handbook relevant. That is more flexible and it moves the decision to
the model.
Neither is wrong. The question is whether you want the application deciding or the model deciding, and that is a design choice rather than a technical one.
The rule of thumb: if the host knows when the data is needed, make it a resource. If knowing requires reading the conversation, make it a tool. Anything that changes state should be a tool, because tools are the primitive with a permission story attached.
The server as a capability boundary
A server exposes a fixed set of capabilities. Whatever is not exposed cannot be reached, whatever the model asks for.
That makes the server the right place to enforce scope. A server over a support
database that exposes lookup_ticket and nothing else cannot be talked into
deleting a ticket, because there is no such capability to invoke. Narrowing what
you expose is more reliable than instructing a model not to use something.
Inside a tool handler, the same rules apply as anywhere else arguments arrive from outside. Validate them, check permissions against the acting user rather than the model's request, and treat the whole payload as untrusted. The reasoning is the same as in function calling, because from your handler's point of view this is the same situation.
Why server output is untrusted input to the model
The direction people forget runs the other way.
Whatever your server returns lands in the model's context, where it is indistinguishable from your own instructions. A tool that returns the text of a document returns whatever that document says, including any instruction somebody wrote into it.
So a compromised server, or an honest server over attacker-controlled content, is an injection vector. The MCP client trusts the server it connected to, and the model reads what arrives.
Two consequences for anyone running a host. Servers are a supply chain, so installing one is a trust decision equivalent to installing a dependency that can write to your context. And the decisions that matter belong in code that runs after the model responds, not in a prompt asking the model to ignore instructions it finds in tool results. Prompt injection covers the attack in general; this is the MCP-shaped version of it.
Further reading
- MCP, Server primitives: the control hierarchy and the three primitives, at revision 2026-07-28.
- Transport layer: how the messages travel, and what changes between stdio and HTTP.
- MCP in one sitting: the protocol end to end.
Knowledge check
Question 1 of 3
Sign in to save your progress and pick up where you left off.