Build Your Own MCP Server · 20 min · Python · MCP Python SDK (FastMCP)
Resources and Prompts
A resource is data you hand the host to attach; a tool is an action the model decides to take. Confusing the two is the most common MCP design mistake.
Hiring signal: Most MCP tutorials stop at tools. Knowing when a resource or a prompt template is the better-designed primitive is what separates a server that feels native to MCP from one that's just tool-calling with extra steps.
What you will learn
- Add a resource that exposes read-only data via a URI
- Add a parameterized prompt template
- Explain when each of the 3 MCP primitives (tool/resource/prompt) is the right design choice
Introduction
Lesson 1's checkpoint asked you to decide whether a changelog file should be a tool or a resource, and told you the answer without a way to prove it. Today you build a resource for real and feel the difference: it's just there, attached to context, without the model ever "deciding" to fetch it.
Resources: read-only, addressed by URI
@mcp.resource("notes://recent")
def recent_notes() -> str:
"""The 5 most recently added notes, always available as context."""
conn = sqlite3.connect(DB_PATH)
rows = conn.execute("SELECT content FROM notes ORDER BY created_at DESC LIMIT 5").fetchall()
conn.close()
return "\n".join(r[0] for r in rows)
Notice the decorator is @mcp.resource(uri), not @mcp.tool() -- and there's no input_schema because resources don't take arguments the way tools do (a parameterized resource template is possible with {} placeholders in the URI, but this course's resource is static: one URI, one read). In Claude Desktop, the user (or the host on the user's behalf) attaches this resource to a conversation explicitly, rather than the model deciding mid-conversation to call it -- that's the entire point: standing context, not an action.
Resources move the decision from the model to the host/user
A tool means "the model decides if and when to use this." A resource means "this is available context, attached deliberately." If you find yourself writing a tool whose only job is "fetch some standing data with no real parameters," it's very often a resource wearing a tool's clothes -- and the model will occasionally forget to call it, where an attached resource never has that failure mode because it doesn't depend on the model remembering.
Unlock the full lesson
You've read the first 2 sections. The rest of this lesson covers Prompts: reusable, parameterized templates, What You're Building — plus a hands-on lab, quiz, and project artifact.
Create a free account to unlock Phase 0 and Phase 1 of every course — no credit card.
Browse all courses · View pricing · DeVenture Academy