C.W.K.
Stream
Lesson 02 of 05 · published

Resources — Read-Only Data

~22 min · resources, uri, read, subscribe

Level 0Curious Reader
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Resources are the read-only side of MCP. They model anything that has a stable identity and can be fetched: a file on disk, a row in a database, a documentation page, a snapshot of memory state. Each resource has a URI (its name on the wire), a mime type, optional annotations, and a piece of content that is either text or binary.

The protocol exposes three resource methods: resources/list returns the available resources, resources/read returns one resource's content by URI, and resources/subscribe (when the server advertises it) lets the client be notified when a specific resource changes. Subscribers are the foundation for live-data UIs in hosts that want to keep a panel up-to-date.

The right mental model: Resources are what the host can read without asking the user. They are safe by design — no side effects, no state mutations, no irreversible operations. That is why hosts can list and pre-fetch them aggressively without prompting for confirmation.

Common pattern: a Postgres MCP server exposes one resource per table (URI like postgres:///orders), a filesystem server exposes a resource per allowed path, a docs server exposes a resource per page. Tools mutate; Resources just sit there ready to be read.

Code

Defining a resource in the Python SDK·python
from mcp.server.fastmcp import FastMCP

app = FastMCP("docs-server")

@app.resource("docs://README")
def read_readme() -> str:
    return open("/srv/docs/README.md").read()

@app.resource("docs://changelog/{version}")
def read_changelog(version: str) -> str:
    return open(f"/srv/docs/changelog/{version}.md").read()
Reading a resource from the client side·python
async with ClientSession(read, write) as s:
    await s.initialize()
    listing = await s.list_resources()
    for r in listing.resources:
        print(r.uri, r.name, r.mimeType)
    content = await s.read_resource("docs://README")
    print(content.contents[0].text)

External links

Exercise

Build a tiny FastMCP server with two resources: one static (a fixed README) and one templated (e.g. echo://{message}). Connect to it from a client SDK script, list the resources, and read both kinds. The list/read symmetry is the same in every server you will ever write.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.