Resources
Expose data sources and dynamic content generators to your MCP clients.
Resources give an LLM read‑only access to text, JSON, binaries, or files. Templates extend the idea by letting clients request parameterised URIs that generate data on the fly. In Hyperia both are primarily declared with the @mcp.resource
decorator (for dynamic content) or mcp.add_resource()
(for static assets).
What Are Resources?
When a client issues resources/read
for a URI:
Hyperia finds the matching resource definition.
If the resource is dynamic (a function), it executes.
The returned content is packaged (text, JSON, bytes…) and streamed back.
This mechanism lets LLMs inspect configuration, fetch user docs, read database rows, or access freshly computed summaries relevant to a conversation.
Defining Resources with @resource
@resource
import json
from hyperia import Hyperia
mcp = Hyperia("DataServer")
# Static string
@mcp.resource("resource://greeting")
def greeting() -> str:
return "Hello from Hyperia!"
# JSON dict auto‑serialised
@mcp.resource("data://config")
def cfg() -> dict:
return {"theme": "dark", "version": "1.2.0"}
Key points
URI – the unique identifier (
resource://greeting
).Lazy – functions run only when the URI is requested.
Metadata – name & description inferred from the function by default.
Return mapping → content: •
str
→TextResourceContents
text/plain
•dict/list/BaseModel
→ JSON stringapplication/json
•bytes
→ base64BlobResourceContents
(specifymime_type
!) •None
→ empty list (204‑like).
Custom Metadata
@mcp.resource(
uri="data://app-status",
name="ApplicationStatus",
description="Current health status of the app.",
mime_type="application/json",
tags={"monitoring", "status"},
)
def app_status() -> dict:
return {"status": "ok", "uptime": 12345}
uri
(required)name
,description
override inferred valuesmime_type
explicit for non‑texttags
help clients filter/group
Accessing MCP Context
Inject a Context
param for request metadata, logging, resource reads, sampling, etc.
from hyperia import Hyperia, Context
mcp = Hyperia("DataServer")
@mcp.resource("resource://system-status")
async def system(ctx: Context) -> dict:
return {"status": "operational", "request_id": ctx.request_id}
Async Resources
Use async def
for I/O‑heavy reads.
import aiofiles
from hyperia import Hyperia
mcp = Hyperia("DataServer")
@mcp.resource("file:///app/log.txt", mime_type="text/plain")
async def read_log() -> str:
async with aiofiles.open("/app/log.txt", mode="r") as f:
return await f.read()
Static Assets with mcp.add_resource()
mcp.add_resource()
from pathlib import Path
from hyperia import Hyperia
from hyperia.resources import FileResource, TextResource, DirectoryResource
mcp = Hyperia("DataServer")
# Static file
readme = Path("README.md").resolve()
if readme.exists():
mcp.add_resource(
FileResource(
uri=f"file://{readme.as_posix()}",
path=readme,
mime_type="text/markdown",
)
)
# Pre‑defined text
mcp.add_resource(
TextResource(
uri="resource://notice",
text="Maintenance Sunday 02:00 UTC",
tags={"notification"},
)
)
# Directory listing as JSON
data_dir = Path("./app_data").resolve()
if data_dir.is_dir():
mcp.add_resource(
DirectoryResource(
uri="resource://data-files",
path=data_dir,
recursive=False,
)
)
Common classes: TextResource
, BinaryResource
, FileResource
, HttpResource
(requires httpx
), DirectoryResource
.
Custom Storage Key
special = TextResource(uri="resource://special")
mcp.add_resource(special, key="internal://v2/special")
Resource Templates (Parameterized URIs)
Templates let you embed placeholders in the URI that map directly to function parameters.
from hyperia import Hyperia
mcp = Hyperia("DataServer")
@mcp.resource("weather://{city}/current")
def weather(city: str) -> dict:
return {"city": city.title(), "temp": 22, "unit": "c"}
@mcp.resource("repos://{owner}/{repo}/info")
def repo_info(owner: str, repo: str) -> dict:
return {"owner": owner, "repo": repo, "stars": 120}
Request
weather://london/current
→{city="london"}
Request
repos://Hyperia/hyperia/info
→{owner, repo}
Wildcard Params {param*}
(Hyperia extension)
{param*}
(Hyperia extension)@mcp.resource("path://{filepath*}")
def read_path(filepath: str) -> str:
return f"Reading {filepath}"
Matches any depth: path://docs/api/v1/index.md
.
Defaults & Multiple Templates
@mcp.resource("users://email/{email}")
@mcp.resource("users://name/{name}")
def lookup(name: str | None = None, email: str | None = None) -> dict:
...
Error Handling
Raise exceptions or hyperia.ResourceError
.
from hyperia import Hyperia, ResourceError
mcp = Hyperia("DataServer")
@mcp.resource("resource://safe-error")
def fail() -> str:
raise ResourceError("Unable to retrieve data – file not found")
Server Behaviour Flags
Duplicate URIs
mcp = Hyperia(on_duplicate_resources="error")
Options: "warn"
(default), "error"
, "replace"
, "ignore"
.
Last updated