Three primitives, three people holding the remote
The question that sorts everything
An MCP server can offer three kinds of thing: tools, resources, and prompts. Nearly every newcomer learns them as three technical shapes — functions, data, templates — and then spends a week unsure which one a given feature should be, because plenty of features could plausibly be any of them.
There is a better axis, and it is the one the specification is actually organised around. The three primitives differ less in what they carry than in who decides to invoke them.
- Tools are model-controlled. The model reads the descriptions, decides one is relevant, and calls it. Nobody asked it to.
- Resources are application-controlled. The host application decides what context to load and hand to the model. The model does not reach for a resource; it is given one.
- Prompts are user-controlled. A human picks one by name, from a slash command or a menu, and fills in its arguments.
Once you sort by that question, the design decisions stop being arguable. A capability the model should reach for on its own is a tool. Data the application should be able to put in front of the model is a resource. A workflow a person starts deliberately is a prompt.
Three remote controls in one room
Picture the floor's lounge with a screen on the wall and three remotes on the table.
The model has one: it can press buttons whenever it judges pressing one would help, and its judgment comes entirely from the labels. The application has another: it decides what is on screen before anyone starts talking — the channel, the brightness, the context. The user has the third: they choose the programme, deliberately, because they wanted that programme.
The pictures a beginner takes from this is that three different parties are in control at different moments, which is exactly right. What an experienced engineer takes from it is that MCP has split its control plane three ways along the axis of who initiates, and that this is a permissions boundary as much as an ergonomic one. Both readings are the same fact.
What each looks like on the floor
Atrium Works needs all three, and which is which follows directly from the question.
Tools — the model should decide to call these:
@mcp.tool()
def find_slots(room_id: str, day: str, minutes: int = 60) -> list[Slot]:
"""Free slots in a room on a given day. Call this before booking anything."""When a member asks "is Studio B free Thursday?", nobody should have to tell the model to check availability. That is the whole job. book_room and cancel_booking are tools for the same reason.
Resources — the application should be able to load these as context:
@mcp.resource("rooms://catalog", mime_type="application/json")
def room_catalog() -> dict[str, dict]:
"""Every bookable room on the floor, with seats and location."""The room catalog is not an action. It is a fact about the floor that is useful in almost every conversation, and the host application should be able to put it in front of the model without the model having to ask. Note the URI: a resource is addressed, not named, and that difference is what lets an application enumerate and select them.
Prompts — a human should start these:
@mcp.prompt(title="Weekly utilisation review")
def weekly_utilisation_review(week_of: str) -> str:
"""Draft the Monday note on how the floor was used last week."""Nobody wants the model spontaneously deciding to write a utilisation review. The floor manager wants it on Monday morning, from a menu, having typed the date. That is a prompt, and prompts are how a server author ships the best-known way to drive their own server.
The test, and the case it settles
The test is one question: who should decide that this happens?
The case it settles most often is data that could be either a tool or a resource. Atrium's room catalog is a good example — you could plausibly write get_rooms() as a tool, and it would work. So which is right?
Ask who decides. If the answer is "the application should just have this available, always", it is a resource. If the answer is "the model should fetch it when it judges it needs it", it is a tool. The catalog is small, stable, and useful in every conversation, so the application should simply load it: resource.
There is one honest complication, which Lesson 18 covers properly: many hosts today surface tools far better than resources. The primitive that is architecturally right is sometimes the one your users cannot reach. That is a real tension and pretending otherwise would waste your afternoon.
What to take into the next lesson
Tools, resources and prompts are separated by who initiates them — model, application, user — and that question resolves nearly every "which should this be?" design argument on the spot. Next: the three participants those primitives travel between, and why a "client" is not the program you think it is.