MCP Resources & Prompts
Learn how to expose data with resources and create reusable prompt templates.
Beyond tools, MCP servers can expose two other powerful capabilities:
Resources
Expose data sources that AI can read from (files, databases, APIs)
Prompts
Create reusable prompt templates with parameters
What are Resources?
Resources allow MCP servers to expose data sources to AI. Think of them as read-only endpoints that provide content like files, database records, API responses, or any other data.
file:///config.json, user://123)text/plain, application/json, etc.)Basic Resource Example
Here's a simple resource that exposes configuration data:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({
name: "resources-server",
version: "1.0.0",
});
// Define a simple text resource
server.resource(
"config://app", // Resource URI
"Application configuration", // Description
"text/plain", // MIME type
async () => { // Handler function
const config = {
app: "MyApp",
version: "1.0.0",
environment: "production"
};
return {
contents: [{
uri: "config://app",
mimeType: "text/plain",
text: JSON.stringify(config, null, 2)
}]
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);config://) to organize data. The scheme can be anything meaningful for your use case!Dynamic Resources with Parameters
Resources can use URI templates to handle dynamic data. Here's an example that retrieves user profiles by ID:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({
name: "user-db-server",
version: "1.0.0",
});
// Resource with dynamic URI parameters
server.resource(
"user://{userId}", // URI template
"User profile by ID", // Description
"application/json", // MIME type
async (uri) => { // Handler receives the URI
// Extract userId from the URI
const userId = uri.split("://")[1];
// In a real app, fetch from database
const users: Record<string, any> = {
"1": { id: 1, name: "Alice", role: "admin" },
"2": { id: 2, name: "Bob", role: "user" },
"3": { id: 3, name: "Charlie", role: "user" }
};
const user = users[userId];
if (!user) {
throw new Error(`User ${userId} not found`);
}
return {
contents: [{
uri,
mimeType: "application/json",
text: JSON.stringify(user, null, 2)
}]
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);user://1, the handler extracts "1" from the URI and returns that user's data. The same resource definition handles all user IDs!file:///path/to/file.txtdb://users/123api://weather/londonconfig://app/settingsPutting It All Together
Resources, prompts, and tools work together to create powerful MCP servers. Here's an example documentation server that combines all three:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "docs-server",
version: "1.0.0",
});
// Resource: Expose documentation files
server.resource(
"docs://{category}/{page}",
"Documentation pages",
"text/markdown",
async (uri) => {
const [category, page] = uri.split("://")[1].split("/");
// In real app, read from file system or database
const docs: Record<string, any> = {
"getting-started/installation": "# Installation\n\nRun: npm install...",
"getting-started/quickstart": "# Quick Start\n\nCreate your first...",
"api/authentication": "# Authentication\n\nUse API keys to..."
};
const content = docs[`${category}/${page}`];
if (!content) {
throw new Error(`Doc not found: ${category}/${page}`);
}
return {
contents: [{
uri,
mimeType: "text/markdown",
text: content
}]
};
}
);
// Prompt: Help users search documentation
server.prompt(
"find-docs",
"Search documentation by topic",
{
topic: z.string().describe("Topic to search for")
},
async ({ topic }) => {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Find documentation about: ${topic}\n\nSearch through available docs:// resources and provide relevant links and summaries.`
}
}
]
};
}
);
// Tool: List all available docs
server.tool(
"list-docs",
"List all documentation pages",
{},
async () => {
const docsList = [
"docs://getting-started/installation",
"docs://getting-started/quickstart",
"docs://api/authentication"
];
return {
content: [{
type: "text",
text: "Available documentation:\n" + docsList.join("\n")
}]
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);docs:// URIsTry resources, prompts, and tools together
Key Takeaways
Resources
- • Expose data sources to AI
- • Use URI schemes for organization
- • Support dynamic parameters in URIs
- • Specify appropriate MIME types
Prompts
- • Create reusable prompt templates
- • Accept parameters with Zod schemas
- • Ensure consistency across uses
- • Combine with resources and tools
Ready for More?
You now know how to create tools, resources, and prompts. Try building a complete MCP server in the challenges!