Understanding MCP Resources

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

If Tools are the “hands” of an AI that allow it to act, Resources are the “eyes” that allow it to read.

Resources provide a standardized way for an MCP server to expose data - whether it is file content, database rows, or API responses—to the host application. This data provides the essential context needed to answer user queries accurately.

The Role of Context

Imagine you are building an AI travel assistant. A user asks: “Plan a week-long itinerary for me in Japan.”

Host vs. Model: Who Reads What?

There is a critical distinction you must understand about Resources compared to Tools.

Resources for UI Templates

Resources are not limited to just raw data like JSON or text. They can also serve code, such as HTML or JavaScript.

Types of Resources

MCP defines two primary ways to expose data:

1. Direct Resources

These point to fixed data sources. They look like static file paths or URLs.

2. Resource Templates

These are dynamic. They use parameters to fetch data based on variables.

Building a Resource Server

Now, you will build a server that demonstrates both types of resources. You will continue working in your lesson_2 directory.

from mcp.server.fastmcp import FastMCP


mcp = FastMCP("Resource Demo")

@mcp.resource("bus://schedule/london")
def get_bus_schedule_in_london() -> str:
    """Returns the bus schedule for London."""
    # In a real app, this would fetch from a database
    schedule = "08:00 AM (Regular), 02:00 PM (Regular)"
    return schedule

@mcp.resource("train://schedule/{city}")
def get_train_schedule(city: str) -> str:
    """Returns the train schedule for a specific city."""
    # In a real app, this would fetch from a database
    schedules = {
        "berlin": "08:00 AM (Regular), 02:00 PM (Regular)",
        "london": "08:00 AM (Express), 02:00 PM (Regular)",
        "paris": "09:30 AM (High Speed), 04:00 PM (Regular)",
    }
    return schedules.get(city.lower(), "No schedule found for this city.")

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

Analyzing the Code

  • @mcp.resource("URI"): This decorator registers the function as a resource.
  • URIs: Notice we are using custom schemes like bus:// and train://. MCP is protocol-agnostic; you don’t have to use http:// or file://. You can invent schemes that make sense for your domain.
  • Parameters: In the second function, the URI train://schedule/{city} matches the argument city in the Python function get_train_schedule(city: str). FastMCP handles the routing automatically.

Running the Server

Run your new resource server using uv:

$ uv run --with mcp resources_demo_server.py
See forum comments
Download course materials from Github
Previous: Executing Tools with Inspector Next: Inspecting Resources with Inspector