Resources — Exposing Structured Data to AI Models
While tools let AI take action, resources let AI read data. Resources are how your MCP server exposes files, configurations, database records, and any other structured data for the AI model to consume.
Tools vs Resources
| Aspect | Tools | Resources |
|---|---|---|
| Purpose | Perform actions | Expose data |
| Direction | AI calls, server executes | AI reads, server provides |
| Side effects | Yes (create, update, delete) | No (read-only) |
| Trigger | AI decides when to call | Client fetches as needed |
| Analogy | API endpoints (POST/PUT) | API endpoints (GET) |
Defining Static Resources
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({ name: "resource-demo", version: "1.0.0" });
// A simple text resource
server.resource(
"readme",
"docs://readme",
{ description: "Project README documentation" },
async () => ({
contents: [{
uri: "docs://readme",
text: "# My Project\n\nThis is the project documentation...",
mimeType: "text/markdown",
}],
})
);
// A JSON resource
server.resource(
"app-config",
"config://app",
{ description: "Current application configuration" },
async () => ({
contents: [{
uri: "config://app",
text: JSON.stringify({
version: "2.1.0",
environment: process.env.NODE_ENV,
features: { darkMode: true, betaFeatures: false },
limits: { maxUploadSize: "10MB", rateLimit: "100/min" },
}, null, 2),
mimeType: "application/json",
}],
})
);
Resource URIs
Every resource needs a unique URI. Use custom schemes to organize:
config://app → Application config
config://database → Database settings
docs://readme → README file
docs://api/endpoints → API documentation
db://users/schema → User table schema
metrics://dashboard → Dashboard metrics
Dynamic Resources with Templates
Resource templates let you define parameterized resources:
// Template resource — the AI can request any user's profile
server.resource(
"user-profile",
"users://{userId}/profile",
{ description: "User profile data. Replace {userId} with a valid user ID." },
async (uri) => {
// Extract userId from the URI
const match = uri.href.match(/users:\/\/(.+)\/profile/);
const userId = match?.[1];
if (!userId) {
throw new Error("Invalid user ID in URI");
}
const user = await db.query("SELECT * FROM users WHERE id = $1", [userId]);
return {
contents: [{
uri: uri.href,
text: JSON.stringify(user.rows[0], null, 2),
mimeType: "application/json",
}],
};
}
);
Python Resources
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("resource-demo")
@mcp.resource("config://app")
def get_app_config() -> str:
"""Current application configuration and feature flags."""
import json
return json.dumps({
"version": "2.1.0",
"environment": "production",
"features": {"dark_mode": True, "beta": False},
}, indent=2)
@mcp.resource("docs://api/{endpoint}")
def get_api_docs(endpoint: str) -> str:
"""API documentation for a specific endpoint."""
docs = load_api_docs(endpoint)
return docs
Resource Update Notifications
When a resource changes, notify the client so the AI can re-read it:
// When data changes, notify the client
server.notification({
method: "notifications/resources/updated",
params: { uri: "metrics://dashboard" },
});
Key Takeaway
Resources are the read-only counterpart to tools. Use them to expose configuration, documentation, database schemas, metrics, and any data the AI model needs as context. Well-designed resources make your AI dramatically smarter about your system.