Module 3: Three Primitives — Resources, Tools, Prompts
Module 3: Three Primitives — Resources, Tools, Prompts
Module 3: Three Primitives — Resources, Tools, Prompts
Capsule description
You've come a long way. In Module 1 you understood why MCP exists — the M×N problem and how a standard protocol solves it. In Module 2 you learned how it works — the Host-Client-Server architecture and the data flow between layers. Now comes the natural question: what can an MCP server do?
The answer fits in three words: Resources, Tools, Prompts.
These are the three primitives — the fundamental building blocks — that every MCP server exposes. There isn't a fourth. Any capability an MCP server offers is implemented as one of these three. Understanding them is the difference between "I know what MCP is" and "I can design an MCP server."
This module is the bridge between theory and construction. By the end of it, you won't just understand the primitives conceptually — you'll have a minimal MCP server working with 1 resource, 1 tool, and 1 prompt.
Where are we?
Context within the guide
Phase 1: MCP Fundamentals (Modules 1-3)
✅ Module 1: What MCP is and why it matters
✅ Module 2: Host-Client-Server Architecture
→ Module 3: Three Primitives (YOU ARE HERE)
Phase 2: Build MCP Servers (Modules 4-6)
○ Module 4: MCP Server in TypeScript
○ Module 5: MCP Server in Python
○ Module 6: MCP Apps and Interactive UI
Phase 3: Production (Modules 7-8)
○ Module 7: Testing, Debugging, and Integration
○ Module 8: Project — Real MCP Server
What you already know
From the previous modules you bring:
- The M×N vs M+N mental model — why a standard protocol is necessary
- The Host-Client-Server architecture — how the pieces connect
- The flow of a request — how data travels from the user to the server and back
- Hands-on experience — you configured and used the Filesystem MCP Server in Claude Code
What's missing
You know that an MCP server exposes "capabilities" to the host. But what types of capabilities exist? How do you decide whether something should be a resource, a tool, or a prompt? How do you implement each one? That's exactly what this module covers.
Module objective
By the end of this module, you'll be able to:
- ✅ Explain the difference between Resources, Tools, and Prompts with concrete examples
- ✅ Decide when to use each primitive: "I need to expose data → Resource; I need to execute an action → Tool; I need to standardize a flow → Prompt"
- ✅ Implement a Resource that exposes static and dynamic data
- ✅ Implement a Tool that executes a function with side effects
- ✅ Implement a Prompt that generates parameterized templates
- ✅ Build a minimal MCP server with the 3 primitives working together
- ✅ Connect your server to Claude Code and verify that it works
The 3 primitives: overview
Before going deep into each one (capsules 02-04), you need the complete map.
Analogy: a tool shop
Imagine that an MCP server is a tool shop:
MCP Server = Tool shop
│
├── Resources (the catalog)
│ "I can show you what we have in stock"
│ → Data you can read
│ → Doesn't modify anything — just queries
│
├── Tools (the services)
│ "I can cut, weld, paint for you"
│ → Functions that execute actions
│ → They can modify state
│
└── Prompts (the project recipes)
"Here are step-by-step instructions"
→ Reusable templates
→ They standardize how to ask for things
Quick comparison table
| Aspect | Resources | Tools | Prompts |
|---|---|---|---|
| What it is | Contextual data | Executable functions | Reusable templates |
| Direction | Pull: client asks, server responds | Invocation: model calls, server executes | Template: client asks, server generates |
| Side effects | No — read-only | Yes — can modify state | No — just generates text |
| Analogy | Reading a book | Using a tool | Following a recipe |
| Example | Read a file, query a DB | Create a file, send an email | Code review template |
| Who initiates | The client/user asks for data | The model decides to invoke | The user selects a template |
| Control | Controlled by the application | Controlled by the model (with approval) | Controlled by the user |
The natural flow
In a real server, the three primitives complement each other:
1. Resource → "What files are in the project?"
Server responds with the list of files
2. Tool → "Refactor this file"
Server executes the refactoring
3. Prompt → "Use the code review template"
Server generates the prompt with the user's parameters
The resource exposes the data, the tool acts on it, and the prompt standardizes how things are asked for. Each has its role.
Decision tree: which primitive do I need?
When you design your MCP server, this tree helps you decide:
Does the model need to READ data?
├── Yes → Do the parameters fit in a URI?
│ ├── Yes → Resource (with a URI template if it's dynamic)
│ └── No → Read-only Tool (with a schema for complex parameters)
└── No
↓
Does the model need to EXECUTE an action with side effects?
├── Yes → Tool
│ └── Is it a destructive action?
│ ├── Yes → Tool with a dryRun pattern
│ └── No → Standard Tool
└── No
↓
Do you want to STANDARDIZE how the user asks for something?
├── Yes → Prompt
│ └── Does it need context from files/data?
│ ├── Yes → Prompt with an embedded resource
│ └── No → Prompt with just text
└── No → You probably don't need MCP for this
Examples of real MCP servers and their primitives
To anchor this in reality, let's see how existing servers use the primitives:
Filesystem Server (Anthropic official):
Resources: (doesn't expose resources, uses tools for everything)
Tools:
├── read_file → Reads a file
├── write_file → Writes a file
├── list_directory → Lists a directory
├── search_files → Searches files
├── create_directory → Creates a directory
├── move_file → Moves/renames
└── ...
Prompts: (doesn't define prompts)
This server is 100% tools because all the operations are actions with variable inputs. Note that read_file is a tool and not a resource — because the file's path comes as a complex parameter, not as a predefined URI.
A hypothetical GitHub Server:
Resources:
├── github://repos/{owner}/{repo}/readme → The repo's README
├── github://repos/{owner}/{repo}/issues/open → Open issues
└── github://repos/{owner}/{repo}/stats → Statistics
Tools:
├── create_issue → Creates an issue
├── close_issue → Closes an issue
├── create_pr → Creates a pull request
├── merge_pr → Merges a PR
└── add_comment → Adds a comment
Prompts:
├── bug-report → Standardized bug report template
├── pr-description → Generates a PR description
└── code-review → Code review template with criteria
This server uses the 3 primitives: resources for query data, tools for actions, prompts to standardize common interactions.
The mental model: think in layers
A useful way to think about the primitives is as the layers of a restaurant:
┌─────────────────────────────────────┐
│ MENU (Prompts) │
│ What the customer sees and chooses │
│ "Combo #3: burger + fries" │
├─────────────────────────────────────┤
│ KITCHEN (Tools) │
│ Where the actions are executed │
│ "Cook burger, fry fries" │
├─────────────────────────────────────┤
│ INVENTORY (Resources) │
│ The available ingredients │
│ "Bread, meat, potatoes, oil" │
└─────────────────────────────────────┘
- The menu (Prompts) standardizes how the customer asks — they don't need to know the internal details.
- The kitchen (Tools) executes the real actions — it transforms ingredients into dishes.
- The inventory (Resources) provides the base data — what's available, quantities, status.
The customer doesn't go to the inventory directly. They don't enter the kitchen. They use the menu. But behind it, everything works as an integrated system.
Module roadmap
| Capsule | Topic | What you'll learn |
|---|---|---|
| 02 | Resources: contextual data | Expose data the model can read — files, DB records, API responses |
| 03 | Tools: executable functions | Create functions the model can invoke — with real side effects |
| 04 | Prompts: reusable templates | Design parameterized templates for common interactions |
| 05 | Combining primitives | How the 3 work together in a real server |
| 06 | Mini-project | Implement an MCP server with 1 resource, 1 tool, 1 prompt |
Learning flow
The progression is deliberate:
- Resource (capsule 02) — we start with the simplest primitive: read-only data. No side effects, no complexity.
- Tool (capsule 03) — we raise the complexity: functions that execute actions and can modify state. It requires schemas, validation, permissions.
- Prompt (capsule 04) — the least intuitive for developers: reusable templates. It's not code that executes — it's text that guides.
- Combination (capsule 05) — the 3 together: how a real server orchestrates resources, tools, and prompts as a cohesive system.
- Mini-project (capsule 06) — you build your first functional MCP server with the 3 primitives.
Each capsule has examples in TypeScript (primary) and Python (secondary). Both official SDKs are supported.
Connection to the project
This module's mini-project
You're going to build a minimal MCP server with:
- 1 Resource: list a directory's files
- 1 Tool: create a new file
- 1 Prompt: refactoring template
It's deliberately simple. The goal is for you to understand the 3 primitives in action, not to build something complex. The complexity comes in modules 4-6.
Connection to the capstone project (Module 8)
This module's minimal server is the seed of the final project. In Module 4 you'll scale it up with complete TypeScript (multiple tools, Zod schemas, transports). In Module 8 you'll turn it into a production-ready server connected to a real API/database. The patterns you learn here — how to define resources, tools, and prompts — are exactly the ones you'll use at scale.
Prerequisites
For this module you need:
- ✅ Claude Code installed and working
- ✅ Node.js v18+ and npm installed
- ✅ To have completed modules 1 and 2 (concepts and architecture)
- ✅ To have used the Filesystem MCP Server (module 1, capsule 05)
Recommended but not required:
- Basic familiarity with TypeScript (you can learn as you go)
- Basic familiarity with Python (only needed if you choose the Python implementation)
- To have explored the Filesystem Server beyond the module 1 examples
Boundaries: what is NOT covered in this module
- ❌ Complete implementation in TypeScript — That comes in module 4
- ❌ Complete implementation in Python — That comes in module 5
- ❌ Advanced Zod schemas — Covered in module 4
- ❌ Transports (stdio, HTTP/SSE) — Covered in module 4
- ❌ Testing and debugging — Covered in module 7
- ❌ MCP Apps and UI — Covered in module 6
This module is conceptual + first hands-on contact. You're building the "what it can do" before the "how to do it at scale."
Signs of success
By the end of this module, you'll know you succeeded if:
- ✅ You can explain Resources, Tools, and Prompts to a colleague using concrete examples
- ✅ Given a use case, you can decide which primitive(s) you need
- ✅ You have a minimal MCP server running with 1 of each primitive
- ✅ You've connected your server to Claude Code and tested it
- ✅ You understand how the 3 primitives combine in a real server
- ✅ You feel prepared to scale this up in TypeScript (module 4)
Design decision: why only 3 primitives?
It may seem limiting — only three types of capability? But that simplicity is intentional. Think of HTML: the entire web is built with ~100 tags, but most pages use only 20-30. The simplicity of the set doesn't limit what you can build — it enables it.
Resources cover any data the model needs to read
It doesn't matter where the data comes from:
- Filesystem files →
file:///src/main.ts - Records from a database →
db://users/123 - Responses from external APIs →
api://weather/madrid - System configurations →
config://app/settings - Logs and metrics →
metrics://server/cpu - Service status →
status://docker/containers
Any data you can put in a URI, you can expose as a Resource.
Tools cover any action the model needs to execute
If it has a verb, it's probably a Tool:
- Create: files, records, issues, PRs
- Read with complex parameters: searches, queries with filters
- Update: modify data, configurations, state
- Delete: remove records, files, resources
- Execute: deploy, test, lint, build
- Send: emails, notifications, messages
Everything that modifies state or requires validated parameters is a Tool.
Prompts cover any interaction you want to standardize
If you repeat an interaction pattern, encapsulate it in a Prompt:
- Code review templates with specific criteria
- Step-by-step code generation wizards
- Debugging flows with a structured format
- Standardized reports (standup, sprint review)
- Documentation with a consistent format
You don't need a fourth primitive because these three cover the complete spectrum: read data (Resource), execute actions (Tool), and standardize interactions (Prompt).
Frequently asked questions before starting
"Do I need all 3 primitives in my server?"
No. Many servers only use Tools (like the Filesystem Server). Others only expose Resources (a metrics server). Some only have Prompts (a template server). Use the ones you need.
"Do the primitives call each other?"
Not directly at the protocol level. But in your code, a Tool can read data internally (as a Resource would), and a Prompt can generate instructions that lead the model to use a Tool. The integration happens at the design level, not the protocol level.
"Which is the most important?"
Tools. It's the most used primitive in practice. If your server could only have one type of primitive, it would be Tools. But the 3 together make a server much more powerful and usable.
"Can I create my own types of primitives?"
Not in the standard protocol. MCP defines exactly 3 primitives. If something doesn't fit in Resources, Tools, or Prompts, you probably need to rethink your design — almost everything fits if you model it correctly.
Mental preparation
Before entering the technical capsules, keep this in mind:
- You don't need to memorize the APIs. What matters is the mental model — knowing when to use each primitive. You look up the syntax in the documentation.
- TypeScript first, Python second. If you don't know TypeScript, don't worry — the examples are self-explanatory and the patterns are universal.
- The mini-project is the goal. Everything you learn in capsules 02-05 converges in capsule 06, where you build a functional server.
Summary
- This module covers the what an MCP server can do — the 3 primitives
- Resources = read-only data the model queries
- Tools = executable functions with side effects
- Prompts = reusable templates with parameters
- Progression: Resource → Tool → Prompt → Combination → Mini-project
- By the end you'll have a minimal MCP server with the 3 primitives working
- This minimal server is the seed you'll scale up in modules 4-8
Additional resources
- MCP Specification — Primitives - Official specification of Resources, Tools, and Prompts
- MCP TypeScript SDK - SDK you'll use to implement the primitives
- MCP Python SDK - Python alternative
- Building MCP Servers (Anthropic Docs) - Official construction guide
- MCP Inspector - Tool to inspect resources, tools, and prompts
- Awesome MCP Servers - Real examples of servers with different combinations of primitives
Note about the code examples
Throughout this module you'll find examples in TypeScript (primary language) and Python (secondary language). Both official MCP SDKs are supported and the choice depends on your preference:
- TypeScript SDK (
@modelcontextprotocol/sdk) — More mature, more reference servers available, uses Zod for schema validation - Python SDK (
pip install mcp) — More concise thanks to decorators, ideal if your stack is Python-centric, uses type hints and Pydantic
In module 4 you'll go deeper into TypeScript and in module 5 into Python. Here you'll see both so you can compare and choose.
Next capsule: Resources — contextual data the model can read. The simplest primitive and the perfect entry point to understand how an MCP server exposes capabilities.