MCP Resources are a core feature of the Model Context Protocol that let you expose data and content for LLM interactions.
Unlike MCP Tools, which perform actions, Resources provide read-only access to structured data. Think of them as the "files" your AI can read, while Tools are the "functions" it can execute.
Resources vs Tools: Understanding the Difference#
The key distinction is about control:
Resources are application-controlled: The client application decides when and how resources are used. For example, in an application like Claude Desktop, users explicitly select which resources to include before starting a conversation.
Tools are model-controlled: The AI model itself determines when to invoke tools based on the conversation context and available capabilities.
This difference matters in practice. If you want data to be automatically available to the model, use a Tool. If you want the application or user to control what context gets loaded, use a Resource.
What Makes a Resource#
Resources are identified by URIs following the format protocol://host/path
,
such as:
file:///home/user/documents/report.pdf
postgres://database/customers/schema
config://app/settings
Resources support both text content (UTF-8 encoded) and binary content (base64 encoded), making them work for everything from source code and logs to images and PDFs.
How Resources are Discovered#
Clients discover resources through two main methods: direct resource lists via
the resources/list
endpoint, and
URI templates for dynamic
resources. Resource templates allow servers to define patterns like
file:///{path}
that clients can use to construct valid URIs on demand.
Implement MCP Resources in an MCP Server#
To illustrate how that works in code, we'll use a basic example of returning some HTML content as an MCP Resource.
It all begins in your OpenAPI document, where you can define the Resource route you want to expose:
OpenAPI#
{
"/html": {
"get": {
"operationId": "html",
"description": "Returns the AI applet's HTML",
"x-zuplo-route": {
"corsPolicy": "none",
"handler": {
"export": "default",
"module": "$import(./modules/html)"
}
}
}
}
}
It's advisable to provide additional MCP specific metadata for the resource to
ensure you give the end client and user the best chance of understanding the
intended use. You can use the x-zuplo-mcp-resource
extension for this:
"x-zuplo-mcp-resource": {
"name": "html_doc",
"description": "The HTML document for the AI applet",
"uri": "ui://html",
"mimeType": "text/html"
}
Finally, it can all be connected as an available Resource in the MCP Server Handler:
{
"paths": {
"/mcp": {
"post": {
"x-zuplo-route": {
"handler": {
"export": "mcpServerHandler",
"module": "$import(@zuplo/runtime)",
"options": {
"name": "example-mcp-server",
"version": "1.0.0",
"resources": [
{
"path": "./config/routes.oas.json",
"operationIds": ["html"]
}
]
}
}
}
}
}
}
}
You can find full implementation details in the MCP Resources documentation.
This is all great but where are Resources being used right now?
MCP Resources in the Wild#
While Resources are often discussed in abstract terms like "reading files" or "exposing documentation," one of the most recent implementations can be found in OpenAI's Apps SDK, which uses embedded resources to power custom UI components in ChatGPT.
In the Apps SDK, Resources serve static UI code that agents can retrieve and render, for example:
ui://widget/kanban-board.html
ui://widget/styles.css
ui://widget/app.js
When a tool is invoked that requires this UI the agent fetches the HTML, CSS, and JavaScript from the resource, hydrates it with structured data from the tool response, and renders it in an iframe in ChatGPT.
This embedded resource pattern demonstrates a practical, production-ready use of MCP Resources that goes beyond basic file reading. It shows how Resources can enable rich, interactive experiences while maintaining the application-controlled nature that defines them.
Best Practices for Resources#
Just as with tool implementation, design is key to success with Resources:
Naming and Documentation
- Use clear, descriptive resource names and URIs that indicate what they do
- Include helpful descriptions that guide LLM understanding of when to use the resource
- Ensure you set the appropriate MIME types to help clients process content correctly
URI Design
- Implement custom URI schemes that reflect the domain of the content you are
working with (e.g.,
docs://
,config://
,db://
) - Consider using the default
mcp://resources/{name}
format for simple resources - Keep URIs consistent and predictable across related resources
Performance and Scale
- Cache resource contents when appropriate to reduce latency
- Consider pagination for large resource lists
- Be mindful of resource size, extremely large resources may impact performance
Security
- Expose read-only content that provides useful context to AI systems
- Validate all resource URIs to prevent directory traversal or injection attacks
- Implement appropriate access controls for sensitive data
- Sanitize file paths and user inputs
Possible Use Cases#
Resources sound great and, hopefully, how they should be implemented and why is clear at this point. What kind of things should Resources be used for, though?
Documentation Resources
Expose API documentation, guides, or reference materials that AI systems can use to answer questions about your platform. When users ask "How do I authenticate with the API?" or "What API endpoints are available?", the AI can read your actual documentation and provide accurate answers.
Here's how the above example would be implemented as an MCP Resource in Zuplo's MCP Server handler:
"x-zuplo-mcp-resource": {
"name": "api_guide",
"description": "API usage guide and best practices",
"uri": "docs://api-guide",
"mimeType": "text/markdown"
}
Configuration Resources
Provide access to current configuration, feature flags, or schema information that helps AI understand your system state. This is valuable for questions like "What features are enabled?" or "What's the current API version?"
"x-zuplo-mcp-resource": {
"name": "api_config",
"description": "Current API configuration and settings",
"uri": "config://api",
"mimeType": "application/json"
}
UI Component Resources
Share reusable UI components, templates, or design system elements that AI can reference when helping users build interfaces. AI assistants can read your CSS, HTML templates, or component libraries to provide consistent guidance aligned with your design system.
"x-zuplo-mcp-resource": {
"name": "component_library",
"description": "Available UI components and their usage",
"uri": "ui://components",
"mimeType": "text/html"
}
These patterns let AI agents or local LLM based applications provide accurate, contextually relevant help by accessing your system's documentation, configuration, and resources on demand.
When to Use MCP Resources Rather Than Tools#
Choose Resources rather than Tools when you want the user or application to control what data the AI can access, not the AI model itself. This is important for:
- User-driven context: When users should explicitly choose what information to share (like selecting specific documentation or logs to include in a conversation)
- Sensitive data: When you need users to opt-in before exposing certain information to the AI
- Large reference materials: When you have extensive documentation or data that shouldn't be automatically loaded but should be available on demand
- Compliance requirements: When regulations or policies require explicit user consent before data access
Resources work well for:
- Documentation and guides that users might reference during conversations
- Configuration and state that changes infrequently but provides important context
- Reference materials like schemas, templates, or style guides
- Historical data like logs or records that users explicitly want to analyze
Choose Tools instead when you want the AI model to automatically decide when to access data or perform actions based on the conversation.
For example, if you want the AI to automatically fetch current weather data when a user asks about the weather, that would be a Tool use scenario. If you want the user to explicitly load weather data before the conversation starts, use a Resource.
Resources FTW!#
The application-controlled nature makes Resources ideal when you want explicit control over what context gets loaded, rather than having the model automatically access data. This gives users and applications the power to choose what information the AI can see, making interactions more predictable and controllable.
Ready to implement MCP Resources?
- Explore the official MCP Resources documentation for complete technical details
- Learn how Zuplo provides native support for MCP Resources through standard API routes