Skip to main content
Resources expose readable data to an AI model’s context. Unlike tools that execute actions with side effects, resources are designed for read-only data retrieval—configuration files, user profiles, documents, API responses, or any content the model needs to reference.
This feature implements the MCP Resources specification. FrontMCP handles all protocol details automatically.
Nx users: Scaffold with nx g @frontmcp/nx:resource my-resource --project my-app. See Resource Generator.

Why Resources?

In the Model Context Protocol, resources serve a fundamentally different purpose than tools: Resources are ideal for:
  • Configuration — expose app settings, feature flags, environment info
  • User data — profiles, preferences, permissions
  • Documents — files, templates, knowledge base articles
  • API responses — cached or live data from external services
  • System state — logs, metrics, status information

Static Resources

Static resources have a fixed URI and return content at that specific address. Use them for singleton data like configuration or global state.

Class Style

Function Style

For simpler resources, use the functional builder:

Resource Templates

Resource templates use dynamic URIs with parameters following RFC 6570 Level 1 syntax. Parameters are extracted automatically and passed to execute().

Class Style

URI Template Patterns

Parameters are extracted into a Record<string, string> and passed as the second argument to execute().

Registering Resources

Add resources to your app via the resources array:
Resources can also be generated dynamically by adapters (e.g., OpenAPI adapter) or plugins.

Loading from npm or Remote Servers

Mix local resources with those loaded from npm or proxied from remote servers:
Resource.esm() and Resource.remote() load individual resources. For loading entire apps, use App.esm() or App.remote().

Return Values

Resources support multiple return formats. The SDK automatically converts your return value to the MCP ReadResourceResult format.

Simple Returns

Full MCP Format

For complete control over the response, return the full ReadResourceResult structure:

Multiple Content Items

Return an array to include multiple content blocks:

Resource Metadata

Static Resource (@Resource)

Resource Template (@ResourceTemplate)

Field descriptions:

Resource Context

Class-based resources have access to a rich execution context via this:

Using Providers

Inject services via the get() method:

Real-World Examples

Configuration Resource

Database-Backed Template

File System Resource

API Proxy Resource


MCP Protocol Integration

Resources integrate with the MCP protocol via three flows: When a client requests resources/read with a URI:
  1. The SDK matches the URI against registered resources and templates
  2. For templates, parameters are extracted from the URI
  3. The execute() method is called with the URI and parameters
  4. The return value is converted to MCP ReadResourceResult format

Capabilities

FrontMCP automatically advertises resource capabilities during MCP initialization:
Per the MCP spec, both capabilities are server-level — they apply to all resources globally, not per-resource. There is no subscribe field on individual Resource or ResourceTemplate objects. The SDK sets these capabilities automatically based on your registered resources:
  • listChanged: true when you have any resources registered
  • subscribe: true when any resources are registered — clients can subscribe to any resource via resources/subscribe
You do not need to add subscribe: true to @Resource() or @ResourceTemplate() decorators. Subscription support is automatic for all resources when the server has any resources registered. Subscriptions work in-memory on single-server deployments (stdio, binary, single-instance HTTP) — no Redis or pub/sub required.

Change Notifications

When resources change dynamically (e.g., via adapters or plugins), FrontMCP automatically sends notifications/resources/list_changed to connected clients. Clients that support this notification will refresh their resource list. For subscribed resources, the server sends notifications/resources/updated when the content changes. Resource authors can trigger this notification by calling this.notifyUpdated() from within a ResourceContext, or programmatically via scope.resources.notifyContentChanged(uri).
Resource subscriptions work out of the box on single-server deployments (stdio, binary, single-instance HTTP) using in-memory tracking — no Redis or pub/sub configuration is needed. The pubsub config is only required for distributed multi-instance deployments where subscription state must be shared across server instances.
For the full protocol specification, see MCP Resources.
To learn how clients discover your resources via MCP flows like resources/list and resources/templates/list, see Discovery APIs.

Best Practices

Do:
  • Use descriptive name and description fields to help models understand resource purpose
  • Return structured data (objects) when possible for better model comprehension
  • Use templates for parameterized data instead of creating many static resources
  • Keep resources focused—one resource per data concern
  • Handle errors gracefully and return meaningful error messages
Don’t:
  • Use resources for operations with side effects (use tools instead)
  • Return extremely large datasets—paginate or summarize when needed
  • Expose sensitive data without proper authentication checks
  • Hardcode values that should come from configuration
  • Add subscribe: true to @Resource() — subscriptions are automatic at the server level per MCP spec

URI Template Encoding

Resource template parameters are percent-encoded per RFC 6570 Level 1 during URI expansion. This is important when parameters contain special characters like ://, /, or spaces. For example, if a tool returns a raw ID like x-coredata://3823FD9C/ICNote/p216 and you use it as a template parameter in notes://note/{noteId}, the expanded URI becomes:
When the framework matches this URI back against the template, parameters are automatically decoded to their original values. The round-trip is consistent:
  • expandUriTemplate("notes://note/{noteId}", { noteId: "x-coredata://..." }) → percent-encoded URI
  • matchUriTemplate("notes://note/{noteId}", encodedUri){ noteId: "x-coredata://..." } (decoded)
When clients construct resource URIs from IDs returned by tools, they must percent-encode the parameters (e.g., using encodeURIComponent()) to match the canonical URI format. The resources/subscribe and resources/read requests use the encoded URI.