Resources

Resources are application-driven, read-only data sources that provide context to AI models from files, APIs, databases, and other sources.

For the complete documentation index, see llms.txt. Markdown variants of every page are available by appending .md to the URL.

xmcp automatically detects and registers files under the /src/resources/ directory as resources. This path can be configured in your xmcp.config.ts file.

Each resource file should export three elements:

  • Schema: Input parameters defined using Zod schemas
  • Metadata: The resource's identity and behavior configuration
  • Default: The resource handler function

There are two types of resources: static and dynamic. When creating resources, it's important to understand how the folder structure determines the resource URI.

URI composition rules

Each resource is uniquely identified by a URI composed from its file path using these rules:

  • The URI scheme is detected from folders with parentheses. For example, a parent folder named (users) creates the URI scheme users.
  • Static folders become literal path segments.
  • Brackets [] indicate dynamic parameters.

For example, the following file path:

Code
src/resources/(users)/[userId]/profile.ts

Will result in the URI users://{userId}/profile.

1. Static resource

Static resources are files that don't require any parameters. Following the composition rules above, the resource below will have the URI config://app:

src/resources/(config)/app.ts
import { type ResourceMetadata } from "xmcp";

export const metadata: ResourceMetadata = {
  name: "app-config",
  title: "Application Config",
  description: "Application configuration data",
};

export default function handler() {
  return "App configuration here";
}

2. Dynamic resource

Dynamic resources accept parameters. The example below creates a resource with the URI users://{userId}/profile:

src/resources/(users)/[userId]/profile.ts
import { z } from "zod";
import { type ResourceMetadata, type InferSchema } from "xmcp";

export const schema = {
  userId: z.string().describe("The ID of the user"),
};

export const metadata: ResourceMetadata = {
  name: "user-profile",
  title: "User Profile",
  description: "User profile information",
};

export default function handler({ userId }: InferSchema<typeof schema>) {
  return `Profile data for user ${userId}`;
}

References

Schema (optional)

The schema object defines the resource's parameters with:

  • Key: Parameter name.
  • Value: Zod schema with .describe() for documentation and resource inspection. This will be visible through the inspector.
  • Purpose: Type validation and automatic parameter documentation.

This is the exact same as the schema object for tools and prompts.

Metadata (optional)

The metadata object provides:

  • Name: Unique identifier for the resource
  • Title: Human-readable title for the resource
  • Description: Brief explanation of what the resource does
  • MimeType: The MIME type of the resource
  • Size: The size of the resource

Implementation (required)

The default export function that performs the actual work.

  • Parameters: Automatically typed from your schema using the built-in InferSchema.
  • Returns: MCP-compatible response with content type.

Troubleshooting

Resource Loading Errors

When xmcp starts, it loads every file under your resources directory.

  • Empty resource files are skipped with a friendly warning
  • Files without a default export are skipped with a friendly warning
  • Real syntax or import errors still fail normally so you can see the full stack trace

For example, if src/resources/(drafts)/latest.ts is empty, startup will log:

Code
[xmcp] Failed to load resource file: src/resources/(drafts)/latest.ts
   -> File is empty.
[xmcp] 1 resource skipped due to empty files or missing default exports

If the file exists but does not export a default handler, startup will log:

Code
[xmcp] Failed to load resource file: src/resources/(drafts)/latest.ts
   -> File does not export a default resource handler.