The Six Primitives of MCP
Tools, resources, prompts, sampling, roots, elicitation, organized by who is in control.

The heart of MCP is six primitives: three the server offers (tools, resources, prompts) and three the client offers (sampling, roots, elicitation). This piece defines each precisely, with method names and the one question that organizes them, plus what the 2025-11-25 revision added around them: async tasks, tool-calling in sampling, richer elicitation, and icons.
A restaurant runs on a few clear roles: a menu you order from, a pantry the kitchen draws on, recipes the cooks follow, and a waiter who comes back to ask when something needs deciding. Each role has an obvious owner, and the place works because nobody is confused about who does what. MCP splits everything a server and client can offer into that same kind of small, clearly-owned set. There are six of these parts in all, and knowing who controls each one is most of understanding MCP.
This is part of a series on MCP. The opening piece said the core of the protocol is six primitives. This one is about those six in detail, because if you hold them in your head, the rest of MCP is just plumbing around them. They have been the stable center of the protocol since launch; even the big 2025-11-25 anniversary revision added things around them without changing the six.
The trick to learning them is a single question asked of each: who is in control of invoking this? Three are offered by the server, three by the client, and each has a clear answer.
What the server offers
- Tools are functions the model can call: query a database, open a pull request,
send a message. They are model-controlled, meaning the LLM decides when to
reach for one. The client discovers them with
tools/listand runs one withtools/call. Each tool declares a JSON Schema for its input, and since the 2025-06-18 revision it can also declare an output schema and return structured, machine-readable results rather than only prose. - Resources are contextual data exposed by URI: a file, a record, a document.
They are application-controlled, meaning the host decides what to pull into
context, not the model. The client lists them with
resources/listand reads one withresources/read. If tools are verbs the model performs, resources are nouns it can be given. - Prompts are pre-written templates or workflows, the kind of thing that shows up
as a slash command. They are user-controlled, meaning a person chooses to
invoke one. Listed with
prompts/list, fetched withprompts/get.
Model, application, user: three different parties in control of three different primitives. That distinction is not decoration; it is how a host decides what the model may reach for on its own versus what needs a human or the app to initiate.
What the client offers
The other three run the other direction: things a server can ask the host to do.
- Sampling lets a server ask the host to run an LLM generation on its behalf,
through
sampling/createMessage. The server never needs its own API key or model, and the host stays in the loop to review the request. As of the 2025-11-25 revision, sampling requests can even include tools and a tool-choice hint, so a server can ask the host to run a tool-using generation. - Roots let the host tell a server which directories or files it is allowed to
work within, listed via
roots/list. A root is a boundary, not a payload; it is how a server knows where its sandbox ends. - Elicitation lets a server pause mid-task and ask the user for a bit more
structured information, through
elicitation/create, with a simple accept, decline, or cancel response. Introduced in 2025-06-18 and expanded in 2025-11-25, it now supports titled and multi-select choices, default values, and a URL mode for flows that need the user to visit a link.
Click through the six and keep an eye on the controller of each, which is the part people get wrong:
Actions the model decides to invoke, like sending an email or querying a database.
How a tool call actually runs
Tools are the primitive people reach for first, so it is worth seeing the full round trip, because it shows how the whole protocol works: discover, then invoke.
First the client asks for the catalogue with tools/list, and the server returns,
for each tool, a name, a description, and an inputSchema. Those three are what
the model sees, and they are the entire contract: the description tells the model
what the tool is for, and the schema tells it exactly what arguments to supply. The
model picks a tool and fills in the schema; the client sends tools/call with the
name and arguments; the server validates the arguments against the schema it
advertised, runs the tool, and returns the result. A refinement worth knowing: since
2025-11-25, argument-validation failures come back as tool execution errors rather
than protocol errors, so the model sees them and can correct itself instead of the
whole call just failing.
What grew around the six
The six primitives did not change, but the 2025-11-25 revision added capabilities that ride alongside them, and a June-2026 reader will meet these in the wild:
- Tasks are an experimental mechanism for long-running or asynchronous work: a request can return a task handle you poll and collect later, instead of blocking. It is a utility that any request can use, not a seventh primitive.
- Icons can now be attached to tools, resources, and prompts, so clients can render them nicely.
- Structured output and richer elicitation, covered above, make the round trips carry more than plain text.
Why this framing pays off
Six primitives, two directions, one question about control. When you meet a new MCP server, you already know the shape of what it can do, and the additions above slot into that frame rather than complicating it. Nothing about a server can surprise you at the protocol level.
The primitives are what MCP says. The next piece is how those messages actually travel, and how a connection is set up in the first place.