MCP Framework
Resources

Resources Overview

Managing external data sources and APIs with MCP Framework resources

Resources

What are Resources?

Resources are data sources that AI models can read or subscribe to. Think of them as a way to provide context, data, or state to your AI interactions!

Understanding Resources

Resources can be:

  • Files
  • API endpoints
  • Database queries
  • Real-time data streams
  • Configuration data

Here's a simple example:

import { MCPResource } from "mcp-framework";

class ConfigResource extends MCPResource {
  uri = "resource://config";
  name = "Configuration";
  description = "System configuration settings";
  mimeType = "application/json";

  async read() {
    return [
      {
        uri: this.uri,
        mimeType: this.mimeType,
        text: JSON.stringify({
          version: "1.0.0",
          environment: "production",
          features: ["analytics", "reporting"],
        }),
      },
    ];
  }
}

Creating Resources

Using the CLI

mcp add resource my-resource

This creates a new resource in src/resources/MyResource.ts.

Resource Structure

Every resource has:

  1. Metadata
uri = "resource://my-data";
name = "My Data Resource";
description = "Provides access to my data";
mimeType = "application/json";
  1. Read Method
async read(): Promise<ResourceContent[]> {
  // Fetch or generate your data
  return [{
    uri: this.uri,
    mimeType: this.mimeType,
    text: JSON.stringify(data)
  }];
}

Resource Types

Static Resources

class DocumentationResource extends MCPResource {
  uri = "resource://docs";
  name = "Documentation";
  mimeType = "text/markdown";

  async read() {
    return [
      {
        uri: this.uri,
        mimeType: this.mimeType,
        text: "# API Documentation\n\nWelcome to our API...",
      },
    ];
  }
}

Dynamic Resources

class MarketDataResource extends MCPResource {
  uri = "resource://market-data";
  name = "Market Data";
  mimeType = "application/json";

  async read() {
    const data = await this.fetch("https://api.market.com/latest");
    return [
      {
        uri: this.uri,
        mimeType: this.mimeType,
        text: JSON.stringify(data),
      },
    ];
  }
}

Real-time Resources

Real-time Updates

Use subscription methods to handle real-time data streams!

class StockTickerResource extends MCPResource {
  uri = "resource://stock-ticker";
  name = "Stock Ticker";
  mimeType = "application/json";
  private ws: WebSocket | null = null;

  async subscribe() {
    this.ws = new WebSocket("wss://stocks.example.com");
    this.ws.on("message", this.handleUpdate);
  }

  async unsubscribe() {
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
  }

  async read() {
    const latestData = await this.getLatestStockData();
    return [
      {
        uri: this.uri,
        mimeType: this.mimeType,
        text: JSON.stringify(latestData),
      },
    ];
  }
}

Title, Icons, Size, and Annotations

Resources now support additional metadata fields per MCP spec 2025-11-25, enabling richer display in client UIs and providing behavioral hints to clients.

import { MCPResource } from "mcp-framework";

class ProjectResource extends MCPResource {
  uri = "resource://project/readme";
  name = "README";
  title = "Project Documentation";  // Human-readable display name
  description = "Project README file";
  mimeType = "text/markdown";
  size = 4096;  // Optional: size in bytes

  // Optional: icons for client UI
  icons = [{ src: "https://example.com/doc-icon.png", mimeType: "image/png" }];

  // Optional: annotations for client behavior hints
  resourceAnnotations = {
    audience: ["user", "assistant"],  // Who this is for
    priority: 0.8,                    // 0.0 (optional) to 1.0 (critical)
    lastModified: "2025-01-12T15:00:58Z",
  };

  async read() {
    return [{
      uri: this.uri,
      mimeType: this.mimeType,
      text: "# My Project\n\nProject documentation...",
    }];
  }
}

Field Reference

  • title — Optional human-readable name for display in client UIs. Falls back to name if not set.
  • icons — Optional array of icon objects with src (URL or data URI), optional mimeType, and optional sizes.
  • size — Optional size in bytes. This is a hint; actual content returned from read() may differ.
  • resourceAnnotations — Optional metadata hints for client behavior:
    • audience — Array of "user" and/or "assistant" indicating who the resource is intended for.
    • priority — Number from 0.0 to 1.0 indicating importance (1.0 = most important, 0.0 = least important).
    • lastModified — ISO 8601 timestamp of the last modification.

Annotations Are Hints

Annotations are purely informational. Clients may use them for display ordering, filtering, or UI hints, but they do not enforce any behavior.

Resource Templates with Metadata

When using resource templates, title and icons defined on the class also apply to the template definition:

class FileResource extends MCPResource {
  uri = "resource://files/{path}";
  name = "Project Files";
  title = "Project File Browser";
  icons = [{ src: "https://example.com/file-icon.png", mimeType: "image/png" }];

  protected template = {
    uriTemplate: "resource://files/{path}",
    description: "Access project files",
  };
  // title and icons on the class also apply to the template definition

  async read() {
    // ...
  }
}

Best Practices

  1. URI Naming
uri = "resource://domain/type/identifier";
// Example: "resource://finance/stocks/AAPL"
  1. Error Handling
async read() {
  try {
    const data = await this.fetchData();
    return [{
      uri: this.uri,
      mimeType: this.mimeType,
      text: JSON.stringify(data)
    }];
  } catch (error) {
    throw new Error(`Failed to read resource: ${error.message}`);
  }
}
  1. Caching
class CachedResource extends MCPResource {
  private cache: any = null;
  private lastFetch: number = 0;
  private TTL = 60000; // 1 minute

  async read() {
    if (this.cache && Date.now() - this.lastFetch < this.TTL) {
      return this.cache;
    }

    const data = await this.fetchFreshData();
    this.cache = data;
    this.lastFetch = Date.now();
    return data;
  }
}

Advanced Usage

Combining with Tools

class DataResource extends MCPResource {
  uri = "resource://data";
  name = "Data Store";

  async read() {
    return [
      {
        uri: this.uri,
        mimeType: "application/json",
        text: JSON.stringify(await this.getData()),
      },
    ];
  }
}

class DataProcessor extends MCPTool {
  async execute(input) {
    const resource = new DataResource();
    const [data] = await resource.read();
    return this.processData(JSON.parse(data.text));
  }
}

Next Steps