Tuesday, 14 July 2026

Understanding MCP Resources: A Complete Beginner’s Guide

  

Modern AI applications are only as powerful as the context they can access. While large language models (LLMs) excel at reasoning and generation, they often lack real-time awareness of your application’s data, whether it’s files, database schemas, APIs, or internal knowledge systems.

 

This is where the Model Context Protocol (MCP) comes in.

 

MCP introduces a standardized way for applications (servers) to expose structured, discoverable, and dynamic context to AI systems (clients). Instead of hardcoding integrations or manually stitching together data sources, MCP allows context to be treated as a first-class concept and accessible through well-defined interfaces.

 

At the heart of this protocol lies Resources. Resources represent any piece of data that can provide context to an AI model:

 

·      A source code file

·      A database schema

·      A configuration file

·      Or even dynamically generated application data

 

Each resource is uniquely identified using a URI and can be discovered, read, and even subscribed to for updates.

 

In this guide, we’ll understand what are MCP Resources from the ground up and cover how they work, how clients interact with them, and how you can leverage them to build smarter, context-aware AI applications.

 

Whether you're building developer tools, internal copilots, or enterprise AI systems, understanding MCP Resources is a key step toward designing scalable and flexible context sharing architectures.

 

1. User Interaction Model: Who Decides the Context?

One of the most important and often overlooked aspects of MCP Resources is this "MCP does not dictate how users interact with resources".

 

Instead, it follows an application-driven model, where the host application is fully responsible for deciding how resources are discovered, selected, and used as context for the AI.

 

This design choice is intentional. Different applications have very different needs, and a rigid interaction model would limit flexibility.

 

1.1 What Does Application-Driven Really Mean?

In traditional systems, the backend often controls what data gets passed around. But with MCP:

 

·      The server exposes resources

·      The client understands what’s available

·      And the application decides how to use them

 

This separation gives you the freedom to design experiences that best fit your users. Let’s look at a few practical ways applications can expose and use MCP resources:

 

a. Explicit Selection (User in Control)

Applications can present resources in a UI like a file explorer:

 

·      Tree view (folders, files)

·      List view (flat resource list)

 

Users can manually select what context to include before interacting with the AI.

 

Example:

A developer tool where users pick one of the following files before asking "Explain how configuration is loaded in this project"

 

·      main.java

·      application.yml

 

This approach gives maximum control and transparency.

 

b. Search and Filter (Guided Discovery)

When the number of resources grows, manual browsing becomes inefficient. Applications can provide:

 

·      Search bars

·      Filters (by type, name, tags, annotations)

 

Example:

Typing "schema" filters resources to:

 

·      user_schema.sql

·      order_schema.json

 

This improves discoverability and usability at scale.

 

c. Automatic Context Inclusion (System in Control)

In some cases, users shouldn't have to think about context at all. Applications can automatically select relevant resources based on:

 

·      Heuristics (e.g., recently used files)

·      User actions (e.g., current screen)

·      AI-driven selection

 

Example:

If a user is viewing a database table, the app automatically includes:

 

·      Table schema

·      Related queries

 

This enables seamless, low-friction experiences.

 

d. No One-Size-Fits-All

MCP is flexible by design, it defines what resources are, not how they should be used.

 

You are free to:

·      Build a fully manual system (like a file picker)

·      A fully automated system (like a smart assistant)

·      Or a hybrid of both

 

This flexibility unlocks powerful design possibilities:

 

·      Developer tools: precise, manual selection

·      Enterprise copilots: automated, context-aware assistance

·      Search systems: dynamic filtering and ranking

 

By decoupling resource exposure from user interaction, MCP allows you to innovate on the experience layer without changing the protocol itself.

 

2. Capabilities: What Can Your MCP Server Actually Do?

Before a client starts interacting with resources, it needs to understand one thing, what features does the server support?. This is where capabilities come into play.

 

In MCP, capabilities are declared during the initial handshake between the client and the server. They act as a contract which clearly defines what the server can and cannot do.

 

f a server supports resources, it must declare the resources capability.

 

At its simplest, it looks like this:

{
    "result": {
        "capabilities": {
            "resources": {
                "listChanged": true,
                "subscribe": false
            },
            "tools": {
                "listChanged": true
            },
            "prompts": {
                "listChanged": true
            }
        },
        "serverInfo": {
            "name": "employee-mcp-server",
            "version": "0.0.1"
        },
        "protocolVersion": "2024-11-05"
    },
    "id": 1,
    "jsonrpc": "2.0"
}

   

This tells the client that MCP Server support resources, tools and prompts, resource subscription is not supported.

 

3. Resource Capabilities

The resources capability can include two optional features:

 

·      subscribe: Indicates whether clients can subscribe to individual resources. Enables real time updates when a resource changes

·      listChanged: Indicates whether the server will notify when the list of resources changes. Useful when resources are dynamic (e.g., new files, tables, APIs)

 

MCP is flexible, servers can support only Subscriptions, only List Changes, both Features (Full Support), or neither as well.

 

Only Subscriptions

 

{
  "capabilities": {
    "resources": {
      "subscribe": true
    }
  }
}

   

Only List Changes

 

{
  "capabilities": {
    "resources": {
      "listChanged": true
    }
  }
}

Both Features (Full Support)

{
  "capabilities": {
    "resources": {
      "subscribe": true,
      "listChanged": true
    }
  }
}

Neither Feature

{
  "capabilities": {
    "resources": {}
  }
}

4. Listing Resources: Discovering What’s Available

Before a client can use any resource, it first needs to answer a simple question "What resources does this server offer?". In MCP, this discovery step is handled through the resources/list API.

 

The resources/list request allows clients to fetch all available resources exposed by the server. At its simplest, the request looks like below.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "resources/list"
}

What Does the Server Return?

The server responds with a structured list of resources.

{
  "result": {
    "resources": [
      {
        "name": "Company Organization Chart",
        "description": "Complete organizational structure showing departments, teams, and reporting lines",
        "mimeType": "application/json",
        "uri": "resource://employee/org-chart"
      }
    ]
  }
}

   

Each resource acts like a metadata descriptor, not the actual data. Each resource in the list provides key information:

 

·      uri: Unique identifier (used later to read the resource)

·      name: Short, user-friendly label

·      description: What the resource contains

·      mimeType: Type of content (JSON, Markdown, etc.)

 

Sample CURL

 

curl --location 'http://localhost:8080/mcp' \
--header 'Content-Type: application/json' \
--data '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "resources/list"
}'

   

5. Reading Resources: Accessing the Actual Data

After discovering available resources using resources/list, the next logical step is "Give me the actual content behind this resource". This is exactly what the resources/read API is designed for.

 

To read a resource, the client simply provides its URI.

 

Sample Request

 

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "resources/read",
  "params": {
    "uri": "resource://employee/org-chart"
  }
}

   

Sample Response

 

{
  "result": {
    "contents": [
      {
        "uri": "resource://employee/org-chart",
        "mimeType": "text/plain",
        "text": "....."
      }
    ]
  }
}

   

In the response:

·      contents is an Array, even though we requested a single resource, the response returns a list of content blocks. It is because, a resource can be composed of multiple parts and useful for chunked data, multi-file responses, or mixed formats.

 

·      Each content block can contain either:

o   text: for readable formats (JSON, Markdown, code, etc.)

o   blob: for binary data (images, PDFs, etc., base64 encoded)

 

Text Content

 

{
  "uri": "file:///example.txt",
  "mimeType": "text/plain",
  "text": "Resource content"
}

   

Binary Content

 

{
  "uri": "file:///example.png",
  "mimeType": "image/png",
  "blob": "base64-encoded-data"
}

   

·      mimeType tells the client how to interpret the content.

 

6. Resource Templates: Dynamic Access to Data

So far, we’ve seen how MCP allows clients to:

 

·      Discover resources (resources/list)

·      Read their contents (resources/read)

 

But what if the data isn’t static? What if you want to access data dynamically, like:

 

·      A specific employee by ID

·      A department by its identifier

·      A file by its path

 

This is where Resource Templates come in. Resource templates allow servers to define parameterized resources using URI templates. Instead of exposing thousands of static resources like:

 

·      resource://employee/101

·      resource://employee/102

·      resource://employee/103

 

You expose a single template: resource://employee/{employeeId}

 

The client fills in the {employeeId} dynamically.

 

6.1 Discovering Templates

Clients can fetch available templates using below request payload.

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "resources/templates/list"
}

   

Sample Response: Available Templates

 

{
    "result": {
        "resourceTemplates": [
            {
                "uriTemplate": "resource://employee/{employeeId}",
                "name": "Employee Profile",
                "description": "Access employee details by employeeId",
                "mimeType": "application/json",
                "title": "Employee Profile",
                "icons": [
                    {
                        "sizes": [
                            "48x48"
                        ],
                        "src": "https://example.com/user-icon.png",
                        "mimeType": "image/png"
                    }
                ]
            }
        ]
    },
    "id": 3,
    "jsonrpc": "2.0"
}

   

Here, each template includes

·      uriTemplate: Parameterized URI

·      name: Friendly name

·      description: What it represents

·      mimeType: Expected response format

·      title / icons: For UI enhancements

 

Sample CURL

curl --location 'http://localhost:8080/mcp' \
--header 'Content-Type: application/json' \
--data '{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "resources/templates/list"
}'

   

7. List Changed Notification: Keeping Clients in Sync

So far, we’ve seen how clients can:

 

·      Discover resources using resources/list

·      Read them using resources/read

 

But there’s an important question, what happens when the available resources change?

 

For example:

·      A new file is added

·      A dataset is removed

·      A new API backed resource becomes available

 

Without a mechanism to detect this, clients would be stuck with stale knowledge.

 

7.1 The Solution: list_changed Notifications

If a server supports the listChanged capability, it can proactively notify clients whenever the resource list changes.

 

Here’s what the notification looks like:

{
  "jsonrpc": "2.0",
  "method": "notifications/resources/list_changed"
}

   

No parameters. No payload. Just a signal: "Hey, something changed—refresh your resource list". When a client receives this notification, the expected behaviour is simple:

 

·      Receive notification

·      Call resources/list again

·      Update local state / UI

 

This keeps the system event-driven instead of polling-based.

 

8. Subscriptions: Real-Time Updates for Individual Resources

So far, we’ve covered:

 

·      resources/list: discover available resources

·      list_changed: detect when the list changes

 

But what if the resource itself changes? What if you want to track updates to a specific resource in real time?

 

That’s where Subscriptions come in.

 

What Are Subscriptions?

Subscriptions allow clients to listen for changes to a specific resource. Instead of repeatedly calling resources/read, the client can say "Notify me whenever this resource changes".

 

Subscribe Request

To start listening, the client sends a resources/subscribe request:

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "resources/subscribe",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}

   

This tells the server that I’m interested in updates to this specific resource.

 

Update Notification

When the resource changes, the server sends a notification.

{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}

   

Why Not Send the Updated Data Directly?

You might ask "Why not include the updated content in the notification?", this is intentional:

 

·      Keeps notifications lightweight

·      Avoids sending large payloads unnecessarily

·      Gives clients control over when and how to fetch updates

 

In summary, MCP Resources redefine how AI systems access and interact with context. Instead of tightly coupled integrations or hardcoded data pipelines, MCP introduces a standardized, flexible, and scalable approach to exposing and consuming context.

 

Let’s quickly recap the journey:

·      Resources (resources/list): Help clients discover what data is available

·      Reading (resources/read): Enables access to the actual content behind a resource

·      Resource Templates: Introduce dynamic, parameterized access to large datasets

·      Capabilities: Define what the server can support, enabling adaptive clients

·      List Changed Notifications: Keep clients in sync when available resources evolve

·      Subscriptions: Provide real-time updates for specific resources

 

Together, these concepts form a powerful pattern Discover Select Read React Repeat

 

This transforms MCP into more than just a protocol, it becomes a context delivery layer for AI systems.

 

 

Previous                                                    Next                                                    Home

No comments:

Post a Comment