Engineering 1 Sep 2026 · 5 min read

Tools, resources and prompts: the three MCP primitives and which one you actually want

MCP has three things a server can offer and three the client can. Most servers should be tools and nothing else, and knowing why is what stops you building a resource nobody can see.

MR mcprush team · The people who run the gateway

The specification gives a server three things to offer, and most explanations list them as if they were three flavours of the same thing. They are not. The difference between them is who decides: a tool is invoked by the model, a resource is attached by the application, a prompt is chosen by the person. Everything else — how well clients support them, what they cost in the window, what can go wrong — follows from that.

Who decides. The model calls tools; the application attaches resources; the person picks prompts. Get this wrong and the primitive works in one client and vanishes in the next.Who decides. The model calls tools; the application attaches resources; the person picks prompts. Get this wrong and the primitive works in one client and vanishes in the next.
Who decides. The model calls tools; the application attaches resources; the person picks prompts. Get this wrong and the primitive works in one client and vanishes in the next.

Tools: the model decides

A tool is a named operation with an input schema and a description. The client sends the whole list on every turn; the model picks one on the strength of that text and the client runs it. Tools are the only primitive every client supports, because they are the only one the model can use on its own — which is also why they are the only one that needs a safety conversation.

  • Model-controlled, so the description is an instruction to a system that follows instructions. Describe; do not direct.
  • Universally supported: every client that speaks MCP shows tools to its model. Nothing else on this page can say that.
  • Read or write is not in the protocol. Annotations exist — readOnlyHint, destructiveHint — and they are hints a client may show and a model may ignore. Only something that reads the code can verify them.
  • Structured output arrived in the 2025-06-18 revision: a tool can declare an output schema and return structuredContent beside the text, so a client can validate the result rather than parse prose.

Resources: the application decides

A resource is data at a URI — a file, a database row, a document — that the server exposes and the client chooses to put into the conversation. The model does not call resources/read; the application does, usually because a person picked the resource from a list or because it matched something the application already tracks. Templates (issues://{project}/open) make a family of them; subscriptions let a client hear when one changes.

That is the elegant version and the reason resources disappoint in practice: most coding agents do not surface them at all. A desktop chat client with an attachment menu shows them; a terminal agent whose whole interface is a prompt has nowhere to put a list of URIs, and ignores the capability. A server whose main value is a resource is invisible in half the clients it is installed in.

A resource is something on a shelf the application can take down. If the client has no shelf, the resource might as well not exist.A resource is something on a shelf the application can take down. If the client has no shelf, the resource might as well not exist.
A resource is something on a shelf the application can take down. If the client has no shelf, the resource might as well not exist.

The 2025-06-18 revision added one bridge worth knowing: a tool result can carry a resource link, a URI the model is told about without the content being inlined. That is how a tool returns "here is the file" without spending the file’s length in the window — and it works in clients that never show a resource list, because the tool is what carried it.

Prompts: the person decides

A prompt is a reusable message template with arguments, offered by the server and picked by the user — the slash-command shape. /triage INFRA expands into a message the server wrote, with the argument filled in, and the model sees only the result. It is user-controlled by definition: nothing about a prompt runs unless a person chose it.

Support follows the interface again. Clients with a command palette show prompts as commands; clients without one drop them. Prompts are worth shipping when your server has a workflow people repeat and get wrong — the exact order of three tool calls, say — and worthless as a substitute for a good tool description, because the model never reads a prompt it was not handed.

The other direction: what a client can offer

Less discussed and more interesting: the protocol runs both ways, and a server can ask things of the client.

Client primitiveWhat it isWhat a server uses it for
SamplingThe server asks the client’s model for a completionSummarising a large result before returning it, without the server holding a model key of its own
RootsThe client tells the server which directories are in scopeA file tool that stays inside the project instead of the whole disk
Elicitation (2025-06-18)The server asks the person a question through the client, with a schemaA confirmation before an irreversible call, or a missing argument asked for rather than guessed
All three are optional and unevenly implemented. A server that depends on one has to check the client declared it in the handshake, and have an answer for when it did not.

Elicitation is the one to watch. A tool that would otherwise guess — "which of the three projects called INFRA did you mean" — can ask, and a destructive tool can require a yes. Where the client supports it, that is the difference between an agent that acts and one that checks; where it does not, the server has to fall back to refusing with a sentence.

What each one costs

Cost here means the model’s window, because that is the resource nobody budgets. Tools cost on every turn whether or not they are called: the list is re-sent each time, names, descriptions and schemas included. Resources cost only when attached, and then cost their whole length. Prompts cost nothing until picked, and then cost the expanded message.

Spent before you type: the tool list, the attached resources, the skills that matched. A fifty-tool server is expensive in every session it is installed in, called or not.Spent before you type: the tool list, the attached resources, the skills that matched. A fifty-tool server is expensive in every session it is installed in, called or not.
Spent before you type: the tool list, the attached resources, the skills that matched. A fifty-tool server is expensive in every session it is installed in, called or not.

Which is the honest argument for narrow servers, and it applies to read-only tools as much as to write ones. A server with ten tools that describe themselves in one line each is cheaper to have installed than one with forty that describe themselves in paragraphs, on every turn of every session, forever.

The rule for choosing

  • If the model should be able to do it on its own initiative, it is a tool. This is nearly everything.
  • If a person should be able to hand the model a document and you know the client has an attachment surface, it is a resource — and return it as a resource link from a tool as well, for the clients that do not.
  • If people keep typing the same three-step request, it is a prompt, in clients with a palette. Ship the tools regardless.
  • If a tool would guess, ask through elicitation where the client supports it, and refuse with a sentence where it does not.
  • If you are unsure, it is a tool. A tool works everywhere; the other two work somewhere.

The primitives are a good design and they are not equally real. Tools are the protocol as it is used. The rest is the protocol as it was hoped to be used, and a server should be built for the first while leaving room for the second.