MCP's Three Primitives: Tools, Resources, and Prompts
MCP servers can expose three first-class capability types: tools, resources, and prompts.
Clients negotiate which of these a server supports during session initialization. Not every server implements all three.
How to Use This Cheatsheet
- Use the comparison table when designing a server surface.
- Use A/B/C sections when implementing or reviewing each primitive.
- Prefer tools for model-chosen actions, resources for readable context, prompts for reusable workflows.
- Jump to Building MCP when you need implementation recipes.
At a Glance
| Primitive | Direction of initiative | Typical content | Model usually... | Host usually... |
|---|---|---|---|---|
| Tools | Model/host invokes action | Args in, result out | Chooses when to call | Authorizes, executes via MCP, returns observation |
| Resources | Host/user selects data | URIs + text/binary content | Reads injected context | Lists, fetches, attaches to context |
| Prompts | User/host starts workflow | Templated messages | Follows the filled template | Lists, fills arguments, inserts messages |
Tools → "do something" (side effects possible)
Resources → "read this context" (mostly passive data)
Prompts → "start this workflow" (guided multi-message shapes)A - Tools
What they are: Named operations with JSON Schema-like input definitions and structured results.
When to expose as a tool:
- Searching, creating, updating, or deleting systems of record
- Running calculations or code in a sandbox
- Calling internal APIs the model should not invent by hand
Client flow (conceptual):
tools/list → expose schemas to model
tools/call → { name, arguments } → result contentDesign rules:
| Rule | Why |
|---|---|
Verb-noun names (get_order, create_ticket) | Clear selection |
| Tight required fields + enums | Fewer bad args |
| Short structured results | Protects context budget |
| Separate read vs write tools | Easier least privilege |
| Host allowlists after list | Servers may be over-broad |
# Conceptual tool descriptor (server SDK shapes vary)
tool = {
"name": "get_order_status",
"description": "Fetch order status by id. Use for live status, not historical analytics.",
"inputSchema": {
"type": "object",
"properties": {
"order_id": {"type": "integer", "description": "Numeric order id"}
},
"required": ["order_id"],
"additionalProperties": False,
},
}Security note: Tools are the highest risk primitive because they can mutate systems.
B - Resources
What they are: Addressable pieces of context (files, docs, records, configs) identified by URIs.
When to expose as a resource:
- Large or infrequently needed documents
- User-selected attachments or workspace files
- Read-only snapshots that should not be re-fetched via a write-capable tool
Client flow (conceptual):
resources/list → pick URI
resources/read → content (text or binary metadata)
optional: subscribe / notifications when content changesURI examples (illustrative):
| URI pattern | Meaning |
|---|---|
file:///project/README.md | Local file resource |
docs://handbook/onboarding | Knowledge base page |
db://customers/42 | Record snapshot |
config://agent/policy | Host policy blob |
Design rules:
| Rule | Why |
|---|---|
| Stable URIs | Caching and bookmarks |
| MIME / mime-like typing | Host can render correctly |
| Size limits or pagination | Avoid multi-MB dumps into prompts |
| Read-only default | Resources should not mutate silently |
| Redact secrets on read | Resources enter model context |
Resources are not a substitute for tools when the model must act. They shine when the host wants to attach known context without inventing a pseudo-tool.
C - Prompts
What they are: Named, parameterized message templates (workflows) a user or host can invoke.
When to expose as a prompt:
- Repeatable reviews ("security checklist", "release notes draft")
- Multi-step starter packs with fixed structure
- Productized workflows you want discoverable in a client UI
Client flow (conceptual):
prompts/list → show catalog in UI
prompts/get → fill arguments → message list for the host# Conceptual prompt descriptor
prompt = {
"name": "summarize_diff",
"description": "Summarize a git diff for a PR description",
"arguments": [
{"name": "diff", "description": "Unified diff text", "required": True},
{"name": "audience", "description": "engineer|pm", "required": False},
],
}Design rules:
| Rule | Why |
|---|---|
| Clear argument list | Hosts can render forms |
| Opinionated structure | Consistent outputs |
| No hidden side effects | Prompts should not silently write systems |
| Version names when behavior changes | Avoid surprise template drift |
Prompts are usually user- or host-initiated, not free-fired by the model on every turn. Some hosts may also load prompt text as system instructions; treat that as a product choice.
D - Choosing the Right Primitive
| Need | Prefer | Avoid |
|---|---|---|
| Model should decide when to act | Tool | Encoding actions only as free text |
| Attach a known document | Resource | Forcing the model to cat via a shell tool every time |
| Start a standardized workflow | Prompt | Pasting a long template manually each session |
| Both read and write the same system | Tools (+ optional resources for snapshots) | One mega-tool that does everything |
| Huge corpus | Resources with selective attach or search tools | Always-on full dump |
E - Capability Negotiation
Servers advertise support; clients only call what was negotiated.
initialize
server capabilities: { tools?, resources?, prompts?, logging?, ... }
client only requests listed methodsIf list_tools works but list_resources fails, the server may simply not implement resources.
Design hosts to degrade gracefully.
F - Mapping Into the Agent Loop
| Primitive | Typical insertion point |
|---|---|
| Tools | Model tool list + tool-result observations |
| Resources | System/user context before reason steps |
| Prompts | Initial messages or slash-command workflows |
User picks prompt "incident_triage"
→ host fills args
→ messages seeded
→ model may call tools
→ host may attach resources as evidenceCommon Mix-ups
- Tool that only returns a static doc - often should be a resource (or search tool + resource).
- Resource that mutates on read - surprising; prefer an explicit write tool.
- Prompt that calls APIs itself - prompts should return messages; side effects belong in tools the model/host then runs.
- Exposing only tools - fine for many servers; add resources/prompts when UX needs them.
FAQs
Must every MCP server implement all three primitives?
No. Tools-only servers are common and valid.
Can resources be binary?
Yes, depending on client support. Prefer references or strict size caps for model context.
Are prompts the same as system prompts?
Not exactly. MCP prompts are named templates from a server. A host may place their content into system or user roles.
Who authorizes tool calls?
The host. MCP delivers the call path; policy stays with your agent runtime.
Do resources auto-enter every request?
Usually no. Hosts list and select what to attach unless a product auto-includes them.
How do notifications fit?
Some servers notify clients when resource lists or contents change so hosts can refresh context (verify support for your protocol version).
Should I mirror every REST endpoint as a tool?
No. Curate a small, agent-friendly surface with clear names and tight schemas.
Where do sampling / roots / other features fit?
They are additional protocol capabilities beyond the three core primitives. Start with tools/resources/prompts, then add advanced features as needed.
Related
- What MCP Standardizes and Why It Won the Tool-Connection Wars
- Model Context Protocol Basics
- Exposing Resources and Prompts, Not Just Tools, from an MCP Server
- Anatomy of an MCP Server: Handlers, Schemas, and Transport
- JSON Schema for Tool Parameters: A Reference Guide
- Model Context Protocol Best Practices
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.