AI

WritingMCP series

The Six Primitives of MCP

Tools, resources, prompts, sampling, roots, elicitation, organized by who is in control.

By Sachin Gupta8 min read
Portrait of Sachin Gupta rendered in binary

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.

The six primitives grouped by direction and by who controls them: the server offers tools (model-controlled), resources (app-controlled), and prompts (user-controlled); the client offers sampling, roots, and elicitation that a server can ask it to do

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/list and runs one with tools/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/list and reads one with resources/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 with prompts/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:

Interactive · The six MCP primitivesOpen in Visualizers →
Server offers
Client offers
Tools
Model-controlledtools/call

Actions the model decides to invoke, like sending an email or querying a database.

The trap is thinking the server controls everything. It does not: the model picks tools, the app picks resources and roots, the user picks prompts, and the server can turn around and ask the client (sampling, elicitation).

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.

A tool call end to end: the client calls tools/list and the server returns each tool's name, description, and input schema; the model picks a tool and the client calls tools/call with name and arguments; the server validates against the schema, runs the tool, and returns text or structured content

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.

Related

Tagged