Resources Primitive: Read-Only Data the Host Controls

~12 min read

Resources give the AI read-only access to data — files, knowledge base snippets, query results — without handing over the ability to change anything. Unlike tools, they're typically fetched under the HOST application's control, not spontaneously by the model.

Resources provide read-only data to the AI model — think of them as databases or knowledge bases the AI can query for information, but never modify. Unlike tools, resources typically don't involve heavy computation or side effects, since they're usually just information lookups: a local file's contents, a snippet from a knowledge base or documentation, a read-only database query result, or any static data like configuration info — essentially anything the AI might need to know AS CONTEXT, rather than an action it needs to TAKE.

A key architectural difference from tools: resources are usually accessed under the HOST application's control, not spontaneously by the model. If a user says 'use the company handbook to answer my question,' it's typically the host that decides to call a resource retrieving the relevant handbook sections and feeds them to the model — the model doesn't independently decide to go fetch a resource the way it independently decides to call a tool. This distinction matters: tools are model-initiated actions, while resources are more often host-initiated context supply.

Resources are usually identified by some identifier — like a URI or name — rather than being free-form functions. This course's example uses a decorator like @mcp.resource("file://{path}"), which indicates a template for resource URIs: the AI (or host) asks the server for resources.get with a specific URI like file://home/user/notes.txt, and the server reads and returns that file's actual content.

From a safety standpoint, since resources are read-only, they're inherently less dangerous than tools — but privacy and permissions still matter, since the AI shouldn't be able to read files or data it isn't supposed to access. The host can regulate which resource URIs it allows the AI to access, or the server can restrict access to certain data on its own. In summary: resources give the AI knowledge without handing over the keys to change anything — the MCP equivalent of reference material supplied on-demand, acting like a smarter, protocol-integrated retrieval system.

💻 Code example

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("docs-server")

@mcp.resource("file://{path}")
def read_file(path: str) -> str:
    """Read-only access to a file's contents — the AI can query this
    for context, but this primitive never lets it WRITE or modify anything."""
    with open(path, "r") as f:
        return f.read()

# The Host decides WHEN to fetch this — e.g. the user said "use the
# company handbook," so the host application (not the model itself)
# calls resources.get("file://docs/handbook.md") and feeds the result
# into the model's context, rather than the model spontaneously deciding to

# The Host can also restrict which URIs are ever allowed to be fetched,
# preventing the AI from reading files it shouldn't have access to
ALLOWED_PATHS = {"docs/handbook.md", "docs/faq.md"}

def guarded_resource_fetch(path: str) -> str:
    if path not in ALLOWED_PATHS:
        raise PermissionError(f"Access to '{path}' is not permitted")
    return read_file(path)

💬 Deep Dive with AI

Key points

  • Resources provide read-only data — files, knowledge base snippets, query results — with no side effects and no way to modify anything
  • Usually accessed under the HOST application's control, not spontaneously by the model, unlike tools
  • Identified by a URI or name (e.g. file://{path}), not called with free-form arguments the way tools are
  • Being read-only makes resources inherently less dangerous than tools, but privacy/permission scoping still matters
  • The host or server can restrict which resource URIs the AI is allowed to access