MCP has three primitives: Tools , Resources , and Prompts . While Tools get all the attention, Resources and Prompts serve distinct purposes that are often misunderstood.
The Three Primitives
Primitive Control Purpose Client Support Tools Agent-driven Actions with side effects ✅ Widely supported Resources User-driven Read-only data attachments ⚠️ Limited support Prompts User or Agent Instructions/templates ⚠️ Limited support
Resources and Prompts require client-side support. Not all MCP clients implement them. Tools are universally supported because they’re handled by LLM providers (Anthropic, OpenAI).
Resources: User-Controlled Data
What Are Resources?
Resources are read-only data that users can attach to their input. Key points:
User decides — not the agent
Agent cannot access resources directly — it must use Tools
Tools control access — authentication, scopes, permissions
Real-World Examples
The best example is the @ command in Cursor, Windsurf, and Android Studio:
Client @ Command What It Attaches Cursor @file.tsFile contents Windsurf @PR #123Pull request diff Android Studio @build.gradleBuild configuration
When you type @file.ts, you’re adding a resource to your prompt. The user explicitly chooses what context to include.
When to Use Resources
import { Resource } from 'leanmcp' ;
@ Resource ({ description: "Current user's profile" })
async userProfile () {
return {
name: "John Doe" ,
role: "Developer" ,
preferences: { theme: "dark" , language: "en" }
};
}
@ Resource ({ description: "Project configuration" })
async projectConfig () {
return {
name: "my-app" ,
version: "1.0.0" ,
dependencies: { ... }
};
}
Use resources for:
Configuration files
User profiles
Project metadata
Any read-only context users might want to attach
Resources are not for data the agent should fetch on its own. That’s what Tools are for.
Prompts: Instructions for Agents
What Are Prompts?
Prompts are instructions that tell the agent how to behave. They can be:
User-added — Explicitly attached by the user
Agent-picked — Agent selects relevant prompts when needed
Real-World Examples
The best example is Guidelines in Cursor and Windsurf:
Client Feature Purpose Cursor .cursorrulesProject-specific coding guidelines Windsurf .windsurfrulesProject-specific behavior Both Guidelines panel Agent instructions
These are prompts — instructions that shape how the agent generates code.
When to Use Prompts
import { Prompt } from 'leanmcp' ;
@ Prompt ({ description: "Code review guidelines" })
codeReviewPrompt () {
return {
messages: [{
role: "user" ,
content: {
type: "text" ,
text: `You are a senior code reviewer. Follow these rules:
1. Check for security vulnerabilities
2. Ensure proper error handling
3. Verify edge cases are covered
4. Suggest performance improvements
5. Keep feedback constructive`
}
}]
};
}
@ Prompt ({ description: "API documentation writer" })
apiDocPrompt () {
return {
messages: [{
role: "user" ,
content: {
type: "text" ,
text: `Generate API documentation with:
- Clear endpoint descriptions
- Request/response examples
- Error codes and meanings
- Authentication requirements`
}
}]
};
}
Use prompts for:
Coding standards
Review guidelines
Documentation templates
Any reusable instructions
Question Answer Who decides to use it? Tools : Agent / Resources : User / Prompts : BothCan it modify data? Tools : Yes / Resources : No / Prompts : NoNeeds client support? Tools : No (LLM handles) / Resources : Yes / Prompts : YesPurpose? Tools : Actions / Resources : Context / Prompts : Instructions
Client Support Reality
The hard truth: Most MCP clients only support Tools.
Client Tools Resources Prompts Claude Desktop ✅ ✅ ✅ Cursor ✅ ✅ (@ files) ✅ (rules) Windsurf ✅ ✅ (@ files) ✅ (rules) ChatGPT ✅ ❌ ❌ Custom clients ✅ Varies Varies
If your MCP needs broad client support, focus on Tools . Use Resources and Prompts as progressive enhancements for clients that support them.
Best Practices
For Resources
Keep them read-only — Resources should never modify state
Make them user-relevant — Only expose what users would want to attach
Provide fallbacks — If resources aren’t supported, expose similar data via Tools
// Resource for clients that support it
@ Resource ({ description: "Project config" })
async projectConfig () {
return await this . getConfig ();
}
// Tool fallback for clients that don't
@ Tool ({ description: "Get project config" })
async getProjectConfig () {
return await this . getConfig ();
}
For Prompts
Keep them focused — One prompt per behavior/task
Make them reusable — Generic enough for multiple contexts
Don’t duplicate — If it’s in the prompt, don’t repeat in tool descriptions
// ❌ BAD: Overly specific
@ Prompt ({ description: "Review React TypeScript code on Monday" })
// ✅ GOOD: Reusable
@ Prompt ({ description: "Code review guidelines" })
Summary
Primitive Control Best For Client Support Tools Agent Actions, data access, auth ✅ Universal Resources User Config, profiles, context ⚠️ Limited Prompts Both Instructions, guidelines ⚠️ Limited
Key insight: Tools are LLM-focused (agent-driven). Resources and Prompts are UI-focused (user-driven). Build for Tools first, enhance with Resources/Prompts for supporting clients.
Tools Deep Dive Learn about MCP tools
Resources Guide Understanding resources