Meet Prefect Horizon, the enterprise MCP gateway built by the team behind FastMCP.
These are the docs for FastMCP 2.0. FastMCP 3.0 is now available.
What Are Resources?
Resources provide read-only access to data for the LLM or client application. When a client requests a resource URI:
- FastMCP finds the corresponding resource definition.
- If it’s dynamic (defined by a function), the function is executed.
- The content (text, JSON, binary data) is returned to the client.
This allows LLMs to access files, database content, configuration, or dynamically generated information relevant to the conversation.
Resources
The @resource Decorator
The most common way to define a resource is by decorating a Python function. The decorator requires the resource’s unique URI.
import json
from fastmcp import FastMCP
mcp = FastMCP(name="DataServer")
# Basic dynamic resource returning a string
@mcp.resource("resource://greeting")
def get_greeting() -> str:
"""Provides a simple greeting message."""
return "Hello from FastMCP Resources!"
# Resource returning JSON data (dict is auto-serialized)
@mcp.resource("data://config")
def get_config() -> dict:
"""Provides application configuration as JSON."""
return {
"theme": "dark",
"version": "1.2.0",
"features": ["tools", "resources"],
}
Key Concepts:
- URI: The first argument to
@resourceis the unique URI (e.g.,"resource://greeting") clients use to request this data. - Lazy Loading: The decorated function (
get_greeting,get_config) is only executed when a client specifically requests that resource URI viaresources/read. - Inferred Metadata: By default:
- Resource Name: Taken from the function name (
get_greeting). - Resource Description: Taken from the function’s docstring.
- Resource Name: Taken from the function name (
Decorator Arguments
You can customize the resource’s properties using arguments in the @mcp.resource decorator:
from fastmcp import FastMCP
mcp = FastMCP(name="DataServer")
# Example specifying metadata
@mcp.resource(
uri="data://app-status", # Explicit URI (required)
name="ApplicationStatus", # Custom name
description="Provides the current status of the application.", # Custom description
mime_type="application/json", # Explicit MIME type
tags={"monitoring", "status"}, # Categorization tags
meta={"version": "2.1", "team": "infrastructure"} # Custom metadata
)
def get_application_status() -> dict:
"""Internal function description (ignored if description is provided above)."""
return {"status": "ok", "uptime": 12345, "version": mcp.settings.version} # Example usage
Return Values
FastMCP automatically converts your function’s return value into the appropriate MCP resource content:
str: Sent asTextResourceContents(withmime_type="text/plain"by default).dict,list,pydantic.BaseModel: Automatically serialized to a JSON string and sent asTextResourceContents(withmime_type="application/json"by default).bytes: Base64 encoded and sent asBlobResourceContents. You should specify an appropriatemime_type(e.g.,"image/png","application/octet-stream").None: Results in an empty resource content list being returned.
Disabling Resources
You can control the visibility and availability of resources and templates by enabling or disabling them. Disabled resources will not appear in the list of available resources or templates, and attempting to read a disabled resource will result in an “Unknown resource” error. By default, all resources are enabled. You can disable a resource upon creation using the enabled parameter in the decorator:
@mcp.resource("data://secret", enabled=False)
def get_secret_data():
"""This resource is currently disabled."""
return "Secret data"
Accessing MCP Context
Resources and resource templates can access additional MCP information and features through the Context object. To access it, add a parameter to your resource function with a type annotation of Context:
from fastmcp import FastMCP, Context
mcp = FastMCP(name="DataServer")
@mcp.resource("resource://system-status")
async def get_system_status(ctx: Context) -> dict:
"""Provides system status information."""
return {
"status": "operational",
"request_id": ctx.request_id
}
Async Resources
Use async def for resource functions that perform I/O operations (e.g., reading from a database or network) to avoid blocking the server.
import aiofiles
from fastmcp import FastMCP
mcp = FastMCP(name="DataServer")
@mcp.resource("file:///app/data/important_log.txt", mime_type="text/plain")
async def read_important_log() -> str:
"""Reads content from a specific log file asynchronously."""
try:
async with aiofiles.open("/app/data/important_log.txt", mode="r") as f:
content = await f.read()
return content
except FileNotFoundError:
return "Log file not found."
Resource Classes
While @mcp.resource is ideal for dynamic content, you can directly register pre-defined resources using mcp.add_resource() and concrete Resource subclasses.
from pathlib import Path
from fastmcp import FastMCP
from fastmcp.resources import FileResource, TextResource, DirectoryResource
mcp = FastMCP(name="DataServer")
# 1. Exposing a static file directly
readme_path = Path("./README.md").resolve()
if readme_path.exists():
# Use a file:// URI scheme
readme_resource = FileResource(
uri=f"file://{readme_path.as_posix()}",
path=readme_path, # Path to the actual file
name="README File",
description="The project's README.",
mime_type="text/markdown",
tags={"documentation"}
)
mcp.add_resource(readme_resource)
Notifications
FastMCP automatically sends notifications/resources/list_changed notifications to connected clients when resources or templates are added, enabled, or disabled. This allows clients to stay up-to-date with the current resource set without manually polling for changes.
@mcp.resource("data://example")
def example_resource() -> str:
return "Hello!"
# These operations trigger notifications:
mcp.add_resource(example_resource) # Sends resources/list_changed notification
example_resource.disable() # Sends resources/list_changed notification
example_resource.enable() # Sends resources/list_changed notification
Annotations
FastMCP allows you to add specialized metadata to your resources through annotations. These annotations communicate how resources behave to client applications without consuming token context in LLM prompts. You can add annotations to a resource using the annotations parameter in the @mcp.resource decorator:
@mcp.resource(
"data://config",
annotations={
"readOnlyHint": True,
"idempotentHint": True
}
)
def get_config() -> dict:
"""Get application configuration."""
return {"version": "1.0", "debug": False}
FastMCP supports these standard annotations:
| Annotation | Type | Default | Purpose |
|---|---|---|---|
readOnlyHint |
boolean | true | Indicates if the resource only provides data without side effects |
idempotentHint |
boolean | true | Indicates if repeated reads have the same effect as a single read |
These components showcase how resources and templating work within the FastMCP framework.