---
title: "What are MCP Resources?"
description: "Learn what MCP Resources are and how they differ from MCP Tools. Discover how application-controlled context works in the Model Context Protocol and when to use Resources for AI interactions."
canonicalUrl: "https://zuplo.com/blog/2025/10/17/mcp-resources"
pageType: "blog"
date: "2025-10-17"
authors: "martyn"
tags: "Model Context Protocol"
image: "https://zuplo.com/og?text=What%20are%20MCP%20Resources"
---
MCP Resources are a core feature of the
[Model Context Protocol](https://modelcontextprotocol.io) 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.

<CalloutAudience
  variant="useIf"
  items={[
    `Building MCP servers that expose data
to AI agents`,
    `Need application-controlled context for LLM interactions`,
    `Working with OpenAI Apps SDK or similar AI platforms`,
  ]}
/>

## 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](https://claude.ai/), 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](https://modelcontextprotocol.io/docs/concepts/tools). 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](https://datatracker.ietf.org/doc/html/rfc6570) 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

```json
{
  "/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:

```json
"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:

```json
{
  "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"]
                }
              ]
            }
          }
        }
      }
    }
  }
}
```

<CalloutDoc
  title="MCP Server Handler"
  description={`Transform any API into a remote MCP server with Zuplo's MCP Server Handler.`}
  href="https://zuplo.com/docs/mcp-server/introduction"
  features={[
    `Remote MCP
hosting`,
    `Built-in authentication`,
    `OpenAPI-native config`,
  ]}
/>

<CalloutDoc
  title="MCP Server Resources"
  description={`Learn how to implement MCP Resources in Zuplo, exposing data and content for AI interactions through standard API routes.`}
  href="https://zuplo.com/docs/handlers/mcp-server-resources"
  features={[
    `Resource
URI patterns`,
    `Text and binary content`,
    `OpenAPI integration`,
  ]}
/>

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](https://developers.openai.com/apps-sdk/build/mcp-server),
which uses
[embedded resources](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#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:

```json
"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?"

```json
"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.

```json
"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.

<CalloutSample
  title="Remote MCP Server Example"
  description="A complete working example of a remote MCP server with tools, resources, and security policies."
  deployUrl="https://zuplo.com/examples/remote-mcp-server"
  repoUrl="https://github.com/zuplo/zuplo/tree/main/examples/remote-mcp-server"
  localCommand="npx create-zuplo-api --example remote-mcp-server"
/>

---

**Ready to implement MCP Resources?**

<CalloutNextStep
  label="Learn More"
  title="Official MCP Resources Documentation"
  href="https://modelcontextprotocol.io/docs/concepts/resources"
  external={true}
/>

<CalloutNextStep
  label="Zuplo Docs"
  title="MCP Resources in Zuplo"
  href="https://zuplo.com/docs/handlers/mcp-server-resources"
/>