agentsclimarketplace

Mcp resource patterns

Skill VersoXBT/claude-initial-setup/skills/mcp-development/mcp-resource-patterns

Patterns for MCP resources including URIs, templates, subscriptions, dynamic resources, context provision, and MIME types. Use when the user is exposing data as MCP resources, designing resource URIs, implementing resource templates with parameters, setting up resource subscriptions, or providing context to Claude through resources.From its SKILL.md

Install
npx -y skills add VersoXBT/claude-initial-setup --skill mcp-resource-patterns

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.5 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it

MCP Resource Patterns

Patterns for designing and implementing MCP resources. Covers URI design, templates, subscriptions, dynamic resources, MIME types, and context provision strategies.

When to Use

  • User is exposing data as MCP resources (files, configs, database records)
  • User is designing resource URI schemes
  • User needs parameterized resource templates
  • User wants real-time resource updates via subscriptions
  • User is providing contextual data to Claude through resources

Core Patterns

Static Resources

Expose fixed data sources that Claude can read for context.

import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";

const server = new McpServer({ name: "my-server", version: "1.0.0" });

// Static resource with a fixed URI
server.resource(
  "project-config",
  "config://project",
  { description: "Project configuration including build settings and dependencies." },
  async (uri) => ({
    contents: [{
      uri: uri.href,
      mimeType: "application/json",
      text: JSON.stringify(await loadProjectConfig(), null, 2)
    }]
  })
);

// Static resource for a text file
server.resource(
  "readme",
  "file:///project/README.md",
  { description: "Project README with setup instructions and architecture overview." },
  async (uri) => ({
    contents: [{
      uri: uri.href,
      mimeType: "text/markdown",
      text: await fs.readFile("README.md", "utf-8")
    }]
  })
);

Resource Templates

Parameterized URIs that resolve to specific resources based on input.

// Template with a parameter
server.resource(
  "user-profile",
  new ResourceTemplate("users://{userId}/profile", { list: undefined }),
  { description: "User profile data by user ID." },
  async (uri, { userId }) => {
    const user = await db.users.findById(userId);
    if (!user) {
      return { contents: [] };  // Empty contents signals not found
    }
    return {
      contents: [{
        uri: uri.href,
        mimeType: "application/json",
        text: JSON.stringify({
          id: user.id,
          name: user.name,
          email: user.email,
          role: user.role
        }, null, 2)
      }]
    };
  }
);

// Template with list callback for discovery
server.resource(
  "log-file",
  new ResourceTemplate("logs://{date}/{level}", {
    list: async () => {
      const dates = await getAvailableLogDates();
      return dates.flatMap(date =>
        ["info", "warn", "error"].map(level => ({
          uri: `logs://${date}/${level}`,
          name: `${date} ${level} logs`,
          description: `${level}-level logs from ${date}`
        }))
      );
    }
  }),
  { description: "Application logs filtered by date and level." },
  async (uri, { date, level }) => ({
    contents: [{
      uri: uri.href,
      mimeType: "text/plain",
      text: await readLogFile(date, level)
    }]
  })
);

Resource Subscriptions

Notify clients when resource content changes.

# Python - resource with subscription support
from mcp.server import Server
import mcp.types as types

server = Server("my-server")

@server.list_resources()
async def list_resources() -> list[types.Resource]:
    return [
        types.Resource(
            uri="metrics://system/health",
            name="System Health",
            description="Real-time system health metrics.",
            mimeType="application/json"
        )
    ]

@server.read_resource()
async def read_resource(uri: str) -> str:
    if uri == "metrics://system/health":
        metrics = await collect_system_metrics()
        return json.dumps(metrics)
    raise ValueError(f"Unknown resource: {uri}")

# Notify subscribers when metrics change
async def on_metrics_update():
    await server.request_context.session.send_resource_updated(
        uri="metrics://system/health"
    )

Dynamic Resource Lists

Generate resource lists dynamically based on current state.

// List resources dynamically from a database
server.resource(
  "db-table",
  new ResourceTemplate("db://{schema}/{table}", {
    list: async () => {
      const tables = await db.query(
        "SELECT table_schema, table_name FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog', 'information_schema')"
      );
      return tables.map(t => ({
        uri: `db://${t.table_schema}/${t.table_name}`,
        name: `${t.table_schema}.${t.table_name}`,
        description: `Database table ${t.table_schema}.${t.table_name}`,
        mimeType: "application/json"
      }));
    }
  }),
  { description: "Database table schema and sample data." },
  async (uri, { schema, table }) => {
    const columns = await db.getColumns(schema, table);
    const sample = await db.query(`SELECT * FROM "${schema}"."${table}" LIMIT 5`);
    return {
      contents: [{
        uri: uri.href,
        mimeType: "application/json",
        text: JSON.stringify({ columns, sample_rows: sample }, null, 2)
      }]
    };
  }
);

MIME Types

Choose the right MIME type for resource content.

// Common MIME types for MCP resources
const mimeTypes = {
  "application/json":    "Structured data, API responses, configs",
  "text/plain":          "Logs, raw text, CLI output",
  "text/markdown":       "Documentation, READMEs, notes",
  "text/html":           "Web content (use sparingly)",
  "application/xml":     "XML configs, SOAP responses",
  "text/csv":            "Tabular data, exports",
  "application/pdf":     "Binary documents (base64 encoded)",
  "image/png":           "Screenshots, diagrams (base64 encoded)",
};

// Binary content uses base64 encoding
server.resource("screenshot", "screen://current", {}, async (uri) => ({
  contents: [{
    uri: uri.href,
    mimeType: "image/png",
    blob: await captureScreenBase64()  // base64-encoded string
  }]
}));

Anti-Patterns

  • Using opaque IDs in URIs instead of human-readable paths (res://abc123 vs users://42/profile)
  • Not implementing the list callback on templates (Claude cannot discover available resources)
  • Returning massive resources without summarization (floods context window)
  • Using text/plain for structured data that should be JSON
  • Not handling missing resources (return empty contents, do not throw)
  • Exposing sensitive data (secrets, credentials) through resources without access control
  • Making resource reads slow by including expensive computations (cache instead)

Quick Reference

ConceptPattern
Static resourceFixed URI, single data source
Resource templateParameterized URI with {param} syntax
List callbackDiscovery function returning available resources
SubscriptionServer pushes updates when content changes
Binary contentUse blob field with base64, set correct MIME type

URI scheme conventions:

file:///path/to/file          # Local files
db://{schema}/{table}         # Database objects
config://{section}            # Configuration
logs://{date}/{level}         # Log entries
metrics://{category}          # Monitoring data
repo://{owner}/{name}         # Repository data

Checklist: human-readable URIs, descriptive descriptions, correct MIME types, list callbacks for discoverability, concise content, redacted sensitive data.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most mcp tooling skills give in ~1.6k tokens

Counted across 638 of the 750 authors here whose files we hold, read 2026-08-07

  • Create ten complex or independent read-only evaluation questionsin 69 of 638, across 15 files
  • Test servers using MCP Inspectorin 61 of 638, across 19 files
  • Provide actionable error messages with specific next stepsin 54 of 638, across 12 files
  • Prioritize comprehensive API coverage over specific workflows or workflow toolsin 54 of 638, across 12 files
  • Use TypeScript and Streamable HTTP for remote servers or clientsin 54 of 638, across 8 files
  • Define structured output schemas where possiblein 50 of 638, across 8 files
  • Use Zod or Pydantic for input schemasin 47 of 638, across 5 files
  • Fetch MCP specification pages with markdown suffixin 46 of 638, across 4 files
  • Load framework documentation using WebFetchin 45 of 638, across 3 files
  • Verify each evaluation answer independentlyin 45 of 638, across 3 files
  • Implement API client with authentication and paginationin 45 of 638, across 3 files
  • Define input schemas with validationin 27 of 638, across 9 files

Said here and by no other author read

  • use human-readable URIs
  • provide descriptive resource descriptions
  • set correct MIME types
  • implement list callbacks for discoverable resources
  • keep resource content concise
  • redact sensitive data

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,790. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.