MCP Resources
Resources are data and content that MCP servers expose to LLMs. Learn how to create, expose and manage resources effectively.
What are Resources?
Resources are read-only data that an MCP server exposes to the LLM. They allow the assistant to access information without being able to modify it directly. Resources are identified by URIs and can be listed, read and searched.resources
List
The client can request a list of all available resources.
Read
The client can read the full content of a specific resource.
Search
The client can search for resources matching a query.
How to Expose Resources from Servers
To expose resources in your MCP server, you need to implement three main methods: list_resources, read_resource, and optionally search_resources.
Example: Python SDK
from mcp.server import Server
from mcp.types import Resource, TextContent
import mcp.types as types
import os
app = Server("file-server")
@app.list_resources()
async def list_resources() -> list[Resource]:
"""Lista todos los archivos en un directorio"""
resources = []
base_path = "/path/to/documents"
for root, dirs, files in os.walk(base_path):
for file in files:
file_path = os.path.join(root, file)
uri = f"file://{file_path}"
resources.append(Resource(
uri=uri,
name=file,
description=f"Archivo: {file}",
mimeType="text/plain"
))
return resources
@app.read_resource()
async def read_resource(uri: str) -> str:
"""Lee el contenido de un archivo"""
# Validar URI
if not uri.startswith("file://"):
raise ValueError("URI inválida")
file_path = uri.replace("file://", "")
# Validar que el archivo existe y está permitido
if not os.path.exists(file_path):
raise FileNotFoundError(f"Archivo no encontrado: {file_path}")
# Leer y retornar contenido
with open(file_path, "r", encoding="utf-8") as f:
return f.read()
# Ejecutar servidor
if __name__ == "__main__":
from mcp.server.stdio import stdio_server
stdio_server(app)Example: TypeScript SDK
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { readFileSync, readdirSync } from "fs";
import { join } from "path";
const server = new Server(
{
name: "file-server",
version: "0.1.0",
},
{
capabilities: {
resources: {},
},
}
);
const BASE_PATH = "/path/to/documents";
server.setRequestHandler(
ListResourcesRequestSchema,
async () => {
const resources = [];
function walkDir(dir: string): void {
const files = readdirSync(dir, { withFileTypes: true });
for (const file of files) {
const fullPath = join(dir, file.name);
if (file.isDirectory()) {
walkDir(fullPath);
} else {
resources.push({
uri: `file://${fullPath}`,
name: file.name,
description: `Archivo: ${file.name}`,
mimeType: "text/plain",
});
}
}
}
walkDir(BASE_PATH);
return { resources };
}
);
server.setRequestHandler(
ReadResourceRequestSchema,
async (request) => {
const uri = request.params.uri;
if (!uri.startsWith("file://")) {
throw new Error("URI inválida");
}
const filePath = uri.replace("file://", "");
const content = readFileSync(filePath, "utf-8");
return {
contents: [
{
uri,
mimeType: "text/plain",
text: content,
},
],
};
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main();Resource Types
Resources can represent different types of content. Each type has its own characteristics and use cases.
Text Files
Documents, source code, markdown, JSON, etc. The LLM can read and analyze the content.
Example:
Source code files, documentation, personal notes.
Use case:
Code analysis, documentation generation, summaries.
Database Entries
Rows, documents or database records that the server can query and expose.
Example:
User records, products, transactions, logs.
Use case:
Data queries, information analysis, report generation.
Web Content
Web pages, articles, blog posts that the server can fetch and expose.
Example:
Wikipedia articles, blog posts, API content.
Use case:
Research, content summaries, trend analysis.
Media
Images, videos, audio that can be described or processed by the LLM.
Example:
Images, screenshots, multimedia files.
Use case:
Image description, visual content analysis.
Structured Resources
Data in structured format like JSON, XML, YAML that the LLM can process.
Example:
Configurations, API data, metadata.
Use case:
Configuration analysis, data transformation, validation.
Dynamic Content
Resources generated in real time based on queries or parameters.
Example:
Search results, real-time statistics, metrics.
Use case:
Dashboards, monitoring, real-time analysis.
Practical Examples
Here are complete examples of servers that expose different types of resources.
Example 1: Resources from Database
Expose SQLite database records as MCP resources
from mcp.server import Server
from mcp.types import Resource
import sqlite3
import json
app = Server("database-server")
DB_PATH = "example.db"
@app.list_resources()
async def list_resources() -> list[Resource]:
"""Lista todos los usuarios como recursos"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT id, name, email FROM users")
users = cursor.fetchall()
resources = []
for user_id, name, email in users:
resources.append(Resource(
uri=f"db://users/{user_id}",
name=f"Usuario: {name}",
description=f"InformaciĂłn del usuario {name} ({email})",
mimeType="application/json"
))
conn.close()
return resources
@app.read_resource()
async def read_resource(uri: str) -> str:
"""Lee los datos de un usuario especĂfico"""
if not uri.startswith("db://users/"):
raise ValueError("URI inválida")
user_id = uri.split("/")[-1]
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute(
"SELECT id, name, email, created_at FROM users WHERE id = ?",
(user_id,)
)
user = cursor.fetchone()
conn.close()
if not user:
raise ValueError(f"Usuario {user_id} no encontrado")
user_data = {
"id": user[0],
"name": user[1],
"email": user[2],
"created_at": user[3]
}
return json.dumps(user_data, indent=2)Example 2: Resources from External API
Expose REST API content as MCP resources
from mcp.server import Server
from mcp.types import Resource
import httpx
import json
app = Server("api-server")
API_BASE = "https://api.example.com"
@app.list_resources()
async def list_resources() -> list[Resource]:
"""Lista artĂculos de una API como recursos"""
async with httpx.AsyncClient() as client:
response = await client.get(f"{API_BASE}/articles")
articles = response.json()
resources = []
for article in articles:
resources.append(Resource(
uri=f"api://articles/{article['id']}",
name=article["title"],
description=f"ArtĂculo: {article['title']}",
mimeType="application/json"
))
return resources
@app.read_resource()
async def read_resource(uri: str) -> str:
"""Lee el contenido completo de un artĂculo"""
if not uri.startswith("api://articles/"):
raise ValueError("URI inválida")
article_id = uri.split("/")[-1]
async with httpx.AsyncClient() as client:
response = await client.get(
f"{API_BASE}/articles/{article_id}"
)
article = response.json()
return json.dumps(article, indent=2)Example 3: Resource Search
Implement search to find resources by content
from mcp.server import Server
from mcp.types import Resource
import os
import re
app = Server("searchable-file-server")
@app.list_resources()
async def list_resources() -> list[Resource]:
"""Lista todos los archivos"""
resources = []
for root, dirs, files in os.walk("/docs"):
for file in files:
if file.endswith(".md"):
file_path = os.path.join(root, file)
resources.append(Resource(
uri=f"file://{file_path}",
name=file,
description=f"Documento Markdown: {file}",
mimeType="text/markdown"
))
return resources
@app.search_resources()
async def search_resources(query: str) -> list[Resource]:
"""Busca archivos que contengan el texto de bĂşsqueda"""
matching_resources = []
for root, dirs, files in os.walk("/docs"):
for file in files:
if file.endswith(".md"):
file_path = os.path.join(root, file)
# Buscar en el contenido del archivo
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
if query.lower() in content.lower():
matching_resources.append(Resource(
uri=f"file://{file_path}",
name=file,
description=f"Documento que contiene: {query}",
mimeType="text/markdown"
))
except Exception:
continue
return matching_resourcesBest Practices
Follow these recommendations to create efficient and secure resource servers.
Descriptive Names
Use clear and descriptive URIs for your resources. Example: 'file:///docs/api.md' instead of 'file:///a/b/c.md'.
Rich Metadata
Provide detailed descriptions and useful metadata (mimeType, size, modification date) for each resource.
Pagination
For large lists, implement pagination using the 'limit' and 'cursor' parameters to improve performance.
Validation
Always validate resource request parameters before accessing underlying data.
Smart Cache
Consider implementing cache for resources that don't change frequently to improve response speed.
Security
Never expose sensitive resources without validation. Verify permissions and sanitize content before exposing it.
Ready to create your own resources?
Explore more about tools, prompts and the complete MCP architecture.