Model Context Protocol / The Protocol
The three primitives a server exposes.
Reviewed by Yuvaraj
An MCP server's entire surface area reduces to three kinds of things it can offer a host application: tools, resources, and prompts. They look superficially similar, each is a named, described capability the server advertises, but they differ along the one dimension that matters most in practice: who decides when it is used. Get that control model right and the rest of MCP falls into place; get it wrong and you will build a server whose tools never fire, or whose resources flood the context window uninvited.
The Model Context Protocol assigns each primitive to a different actor in the loop:
file:///… or https://…). The host application decides which resources to fetch and load into context, the model cannot pull them in by itself.A fourth interaction runs the other way: a server can request sampling, asking the client to run a model completion on its behalf, so a server can reason without shipping its own model. That request is always mediated by the client, which can refuse or edit it.
Ask about this lesson, or about anything in AI. Answers cite the lessons they draw on.
Finished this lesson?
Mark it complete to earn XP, keep your streak, and schedule a review.
For a curious beginner
How it is actually used
The underlying mechanism
Consider a small MCP server that exposes one of each primitive over a project directory.
A read_file tool, model-controlled. It declares an input schema so the client can validate arguments before dispatch:
{
"name": "read_file",
"description": "Read the UTF-8 contents of a file in the project.",
"inputSchema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Path relative to project root"
}
},
"required": ["path"]
}
}
When the user asks "what does the build script do?", the model emits a read_file call with arguments {"path": "build.sh"}; the client validates them against the schema, runs the read, and returns the contents.
A file:///project/README.md resource, application-controlled. The host might list available resources and let the user attach the README, or auto-load it when the project opens. The application issues the read; the model never names the URI itself.
A summarize-file prompt, user-controlled. The server defines a template such as Summarize the following file for a new contributor: {{contents}}. The user selects it from a slash-command menu, the host injects the file, and the server returns the assembled messages.
| Primitive | Controlled by | Example | Analogy |
|---|---|---|---|
| Tool | Model | read_file(path) | POST endpoint (acts, has side effects) |
| Resource | Application | file:///project/README.md | GET endpoint (fetches data) |
| Prompt | User | /summarize-file | Saved query (user runs it) |
Why the split matters
Separating control lets a host enforce policy per primitive: auto-approve resource reads, require confirmation for tools, and expose prompts only in the command palette. One undifferentiated "capability" would collapse those distinct trust boundaries into a single blunt switch.
Common mistakes
inputSchema,
so the client cannot validate arguments and the model guesses argument shapes.