Resources let hosts attach your data as context without spending a tool call.
A resource is data the host can read and add to the model's context. Each one has a URI, a unique address. You choose the scheme (the part before ://): config://app, notes://index, file:///....
@mcp.resource("notes://index") registers a fixed resource. Clients find it with resources/list and read it with resources/read.
Put placeholders in the URI and it becomes a resource template: @mcp.resource("notes://{title}") maps {title} to the function's title parameter. Templates are listed separately (resources/templates/list) because nothing exists to list until someone supplies a value. SDK v2 follows the URI template standard (RFC 6570) strictly and, by default, rejects values that try path tricks such as ../.
The content type matters. Set mime_type= (a standard label for the data format, like text/markdown, application/json, image/png). Return str for text, bytes for binary data, or a dict or list to send JSON.
When to use a resource instead of a tool:
- the data is read-only and identified by an address,
- the user or app should choose to attach it (a file, a schema, a log),
- you want it cacheable.
If the model itself needs to decide to fetch it mid-task, offer a tool too; many hosts don't let the model pick resources on its own. Servers can also notify subscribed clients when a resource changes, covered later.
Example
import json
from mcp.server import MCPServer
mcp = MCPServer("Shop")
PRODUCTS = {"p1": {"name": "Mug", "price": 12}}
@mcp.resource("shop://products", mime_type="application/json")
def products() -> str:
"""All products as JSON."""
return json.dumps(PRODUCTS)
@mcp.resource("shop://products/{product_id}")
def product(product_id: str) -> str:
"""One product, as readable text."""
p = PRODUCTS[product_id]
return f"{p['name']}: ${p['price']}"
# Client side:
# await client.list_resources() -> shop://products
# await client.list_resource_templates() -> shop://products/{product_id}
# await client.read_resource("shop://products/p1") -> "Mug: $12"Remember
- Resources are read-only data at a URI you design
- A {placeholder} in the URI makes a resource template
- Set mime_type; return str, bytes, or JSON-able data
- Pair with a tool when the model must fetch it itself