MCP Primitives: Tools, Resources, and Prompts

An MCP server can expose tools, resources, and prompts. They are distinguished by their control model, meaning who decides when each runs: tools are model-controlled, resources are application-controlled, and prompts are user-controlled. That single distinction explains most of how each is meant to be used.
A tool is model-controlled: the AI decides to call it, usually to take an action or fetch something dynamic. A resource is application-controlled: the client application decides which ones to load as context, and each is addressed by a URI. In short, tools let the model act while resources supply read-only context.
Use a prompt when a person should trigger a reusable, parameterized template on purpose, such as a code-review or summarize request you want to offer as a one-click starting point. Prompts are user-controlled and are often surfaced as slash commands, which makes them ideal for common, structured requests people would otherwise retype.
You should not. Because resources are application-controlled, there is no guarantee a given client loads a particular one into context, so anything the model must always follow can be silently skipped. Put mandatory instructions in a tool description or a prompt instead, where they are far more likely to reach the model.
Ask who should decide when the capability runs. If the model should decide and it may act or fetch dynamically, make it a tool. If it is read-only context the application selects, make it a resource with a stable URI. If a person should trigger it deliberately as a reusable template, make it a prompt.

Key Takeaway
MCP servers expose three primitives: tools, resources, and prompts. Tools are model-controlled actions the AI can invoke, resources are application-controlled context addressed by URI, and prompts are user-controlled templates. Knowing which primitive fits which job is the difference between a server a model uses well and one that constantly reaches for the wrong lever.
When people first meet the Model Context Protocol, they tend to fixate on tools and assume that is all a server offers. In fact the specification defines three server primitives, and the difference between them is not what they do but who decides when they run. Getting that distinction right is what separates a server a model uses smoothly from one it fumbles.
This explainer walks through all three primitives, shows how they differ in code, and gives a simple rule for choosing between them when you design a server.
An MCP server can expose tools, resources, and prompts. They are distinguished by their control model, meaning which party in the conversation is expected to decide when the capability is invoked. That single idea explains most of how they are meant to be used.
In short:
The distinction is easiest to see when you register one of each on a server. The shape is similar, but the intent behind each registration is different, and clients treat them differently as a result.
Here all three are registered on the same server object:
// Tool: model-controlled action the client can invoke
server.tool(
"create_issue",
{ title: z.string() },
async ({ title }) => ({
content: [{ type: "text", text: "Created: " + title }],
})
);
// Resource: application-controlled context, addressed by a URI
server.resource(
"readme",
"file:///project/README.md",
async (uri) => ({
contents: [{ uri: uri.href, text: "Project overview..." }],
})
);
// Prompt: user-controlled template, surfaced as a slash command
server.prompt(
"summarize",
{ topic: z.string() },
({ topic }) => ({
messages: [
{
role: "user",
content: { type: "text", text: "Summarize " + topic },
},
],
})
);The control model is the mental model to hold onto. Before adding a capability, ask who should decide when it runs. That answer, not the implementation, tells you whether it should be a tool, a resource, or a prompt.
Tools are the primitive most servers lean on because they let the model act. Because the model invokes them on its own judgment, they carry the most responsibility and deserve the most care.
Resources expose data the application can choose to pull into context, each identified by a URI such as a file path or a custom scheme. They are meant for read-only context, like a document or a configuration file, that the client decides is relevant rather than the model demanding it.
Prompts are reusable, parameterized templates that a user invokes on purpose. They are ideal for common, structured requests, a code-review prompt or a summarize prompt, that you want to offer as a one-click starting point rather than making people retype every time.
Do not rely on resources for instructions the model must always follow. Because resources are application-controlled, there is no guarantee a given client loads a particular one into context, so anything mandatory belongs in a tool description or a prompt, not in a resource the client may quietly skip.
Most design mistakes come from forcing one primitive to do another's job. A short decision rule keeps a server clean and predictable for the clients that consume it.
The three MCP primitives are not interchangeable; each answers a different question about who is in control. Tools are for the model to act, resources are for the application to supply context, and prompts are for the user to invoke a template. Design around that split and your server will feel obvious to every client that connects to it.