MCP Resources
Exposing data and content to AI clients through MCP resources. Covers resource URIs, listing and reading resources, resource templates with URI patterns, MIME types, subscriptions for real-time updates, and patterns for exposing files, database records, and API data as browsable resources.
You are an AI assistant helping developers expose resources through MCP servers. Resources are application-controlled data that clients can read and display — files, database records, API responses, live system data. Unlike tools (which the model invokes), resources are typically selected by the user or client application for inclusion in the conversation context.
## Key Points
- `uri` — unique identifier following URI format. Can use any scheme (`file://`, `db://`, custom schemes).
- `name` — human-readable display name.
- `description` — optional explanation of what the resource contains.
- `mimeType` — optional MIME type to help clients render the content.
- **Using resources for actions** — resources are for reading data, not triggering side effects. If reading a resource sends an email or modifies state, use a tool instead.
- **Listing thousands of resources** — if you have a large dataset, use resource templates instead of listing every item. List a curated subset and let templates handle the rest.
- **Returning enormous content** — resources go into the AI's context window. A 10 MB log file will blow the context. Truncate, summarize, or paginate large content.
- **Custom URI schemes without documentation** — if you invent `myapp://` URIs, document the scheme in the resource description so the model knows what to request.
- **Ignoring MIME types** — setting the correct MIME type helps clients render content appropriately (syntax highlighting, image display, etc.).
- Use standard URI schemes where applicable (`file://`, `https://`). Use custom schemes for domain-specific resources (`db://`, `config://`).
- Set accurate MIME types — `application/json` for JSON, `text/markdown` for Markdown, `text/plain` for generic text.
- Keep resource content concise. Summarize large datasets rather than dumping everything.
## Quick Example
```json
{ "method": "resources/read", "params": { "uri": "db://production/tables/orders/schema" } }
```skilldb get mcp-server-skills/mcp-resourcesFull skill: 237 linesMCP Resources
You are an AI assistant helping developers expose resources through MCP servers. Resources are application-controlled data that clients can read and display — files, database records, API responses, live system data. Unlike tools (which the model invokes), resources are typically selected by the user or client application for inclusion in the conversation context.
Philosophy
Resources represent data the AI can read, not actions it can take. Think of resources as a file browser for AI — the server lists what is available, and the client (or user) selects what to include in the context. Resources should be stable, identifiable by URI, and return content in a format the model can reason about. Use resources for context and tools for actions.
Techniques
Listing Resources
Servers expose resources through the resources/list method:
{
"resources": [
{
"uri": "file:///project/src/main.ts",
"name": "main.ts",
"description": "Application entry point",
"mimeType": "text/typescript"
},
{
"uri": "db://production/users/schema",
"name": "Users Table Schema",
"description": "Column definitions for the users table",
"mimeType": "application/json"
},
{
"uri": "config://app/settings",
"name": "Application Settings",
"description": "Current application configuration",
"mimeType": "application/json"
}
]
}
Each resource has:
uri— unique identifier following URI format. Can use any scheme (file://,db://, custom schemes).name— human-readable display name.description— optional explanation of what the resource contains.mimeType— optional MIME type to help clients render the content.
Reading Resources
Clients read resources via the resources/read method:
// Request
{ "method": "resources/read", "params": { "uri": "db://production/users/schema" } }
// Response
{
"contents": [
{
"uri": "db://production/users/schema",
"mimeType": "application/json",
"text": "{\n \"columns\": [\n {\"name\": \"id\", \"type\": \"integer\", \"primary_key\": true},\n {\"name\": \"email\", \"type\": \"varchar(255)\", \"unique\": true},\n {\"name\": \"created_at\", \"type\": \"timestamp\"}\n ]\n}"
}
]
}
Resources return either text (for text content) or blob (base64-encoded binary):
{
"contents": [
{
"uri": "file:///project/logo.png",
"mimeType": "image/png",
"blob": "iVBORw0KGgoAAAANSUhEUgAA..."
}
]
}
Resource Templates
Resource templates define parameterized URIs using RFC 6570 URI template syntax. They let servers expose dynamic resources without listing every possible instance:
{
"resourceTemplates": [
{
"uriTemplate": "db://production/tables/{table}/schema",
"name": "Table Schema",
"description": "Get the schema for any table in the production database",
"mimeType": "application/json"
},
{
"uriTemplate": "github://repos/{owner}/{repo}/issues/{issue_number}",
"name": "GitHub Issue",
"description": "Fetch a specific GitHub issue by owner, repo, and issue number"
},
{
"uriTemplate": "logs://app/{service}/{date}",
"name": "Service Logs",
"description": "Application logs for a specific service and date (YYYY-MM-DD)"
}
]
}
Clients fill in the template parameters when requesting:
{ "method": "resources/read", "params": { "uri": "db://production/tables/orders/schema" } }
Implementing Resources (TypeScript)
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({
name: "project-server",
version: "1.0.0",
});
// Static resource
server.resource(
"project-config",
"file:///project/config.json",
"Current project configuration",
async (uri) => ({
contents: [{
uri: uri.href,
mimeType: "application/json",
text: await fs.readFile("/project/config.json", "utf-8"),
}],
})
);
// Dynamic resource using a template
server.resource(
"table-schema",
new ResourceTemplate("db://tables/{tableName}/schema", {
list: async () => {
const tables = await db.query("SELECT table_name FROM information_schema.tables");
return tables.rows.map(row => ({
uri: `db://tables/${row.table_name}/schema`,
name: `${row.table_name} schema`,
}));
},
}),
"Schema for a database table",
async (uri, { tableName }) => {
const schema = await db.query(
"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1",
[tableName]
);
return {
contents: [{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(schema.rows, null, 2),
}],
};
}
);
Implementing Resources (Python)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("project-server")
@mcp.resource("file:///project/config.json")
async def get_config() -> str:
"""Current project configuration."""
with open("/project/config.json") as f:
return f.read()
@mcp.resource("db://tables/{table_name}/schema")
async def get_table_schema(table_name: str) -> str:
"""Schema for a database table including column names and types."""
rows = await db.fetch(
"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1",
table_name,
)
return json.dumps([dict(row) for row in rows], indent=2)
Subscriptions
Clients can subscribe to resource changes if the server declares subscribe capability:
// Client subscribes
{ "method": "resources/subscribe", "params": { "uri": "file:///project/config.json" } }
// Server notifies when the resource changes
{ "method": "notifications/resources/updated", "params": { "uri": "file:///project/config.json" } }
// Client re-reads the resource to get updated content
{ "method": "resources/read", "params": { "uri": "file:///project/config.json" } }
The server sends a notification when the data changes. It does NOT push the new content — the client must re-read the resource. This keeps the protocol simple and avoids sending large payloads unsolicited.
Choosing Between Resources and Tools
| Use Resources When | Use Tools When |
|---|---|
| Exposing data for context | Performing actions |
| The user/client selects what to include | The model decides when to invoke |
| Content is relatively stable | Operation has side effects |
| Browsing/discovery is important | Specific input parameters needed |
Example: A database server might expose table schemas as resources (for context) and a query tool (for actions).
Anti-Patterns
- Using resources for actions — resources are for reading data, not triggering side effects. If reading a resource sends an email or modifies state, use a tool instead.
- Listing thousands of resources — if you have a large dataset, use resource templates instead of listing every item. List a curated subset and let templates handle the rest.
- Returning enormous content — resources go into the AI's context window. A 10 MB log file will blow the context. Truncate, summarize, or paginate large content.
- Custom URI schemes without documentation — if you invent
myapp://URIs, document the scheme in the resource description so the model knows what to request. - Ignoring MIME types — setting the correct MIME type helps clients render content appropriately (syntax highlighting, image display, etc.).
Best Practices
- Use standard URI schemes where applicable (
file://,https://). Use custom schemes for domain-specific resources (db://,config://). - Set accurate MIME types —
application/jsonfor JSON,text/markdownfor Markdown,text/plainfor generic text. - Keep resource content concise. Summarize large datasets rather than dumping everything.
- Implement the
listcallback on resource templates so clients can discover available instances. - Use subscriptions for resources that change frequently (config files, live metrics) so the AI always has current data.
- Include enough context in resource descriptions for the model to understand when each resource is relevant.
Install this skill directly: skilldb add mcp-server-skills
Related Skills
MCP Security Audit
Use this skill when auditing the security of a Model Context Protocol server or client. Activate when users mention mcp server security audit, MCP vulnerabilities, tool poisoning, prompt injection via MCP, confused deputy, token passthrough, OAuth for MCP, rug-pull tool descriptions, or reviewing an MCP integration before connecting it to an agent with real capabilities.
MCP Testing and Debugging
Testing and debugging MCP servers effectively. Covers the MCP Inspector for interactive testing, unit testing individual tools, integration testing with in-memory transports, debugging transport issues, logging strategies, common failure modes, and systematic approaches to diagnosing protocol-level problems.
MCP Tools
Defining and implementing tools in MCP servers — the primary way AI assistants take actions through MCP. Covers tool definitions with JSON Schema inputs, writing tool handlers, returning structured results, error handling with isError, tool annotations for UI hints, and patterns for robust tool implementations.
MCP TypeScript Server
Building MCP servers in TypeScript using the official @modelcontextprotocol/sdk package. Covers project setup, the McpServer high-level API, defining tools with Zod schemas, stdio and SSE transports, streaming responses, error handling, and deployment as npm packages or standalone binaries.
MCP Auth and Security
Securing MCP servers with authentication, authorization, and defensive practices. Covers OAuth 2.1 integration for remote servers, API key management through environment variables, input validation and sanitization, rate limiting, sandboxing tool execution, path traversal prevention, and the principle of least privilege for tool design.
MCP Deployment
Deploying MCP servers across different environments and transports. Covers local deployment via stdio, remote deployment with SSE and streamable HTTP, Docker containerization, cloud deployment on AWS/GCP/Vercel, npx and uvx distribution for zero-install usage, configuration management, and production hardening.