Resources

Purpose and Scope

A resource is read-only data that a connected MCP client can discover, read, and attach as context for a model. In this SDK, resources are deliberately application-controlled: the host or user decides which resource to inspect, while tools are the model-controlled action surface. That distinction matters when designing a server. Use resources for stable context such as configuration, reports, rows, files, profiles, or generated summaries. Use tools when the model should choose to run behavior. A well-designed resource gives the client enough metadata to decide whether a read is useful before spending a request on the contents.

Sources: docs/servers/resources.md

The server guide presents resources as a high-level feature of McpServer rather than a transport-specific behavior. The same resource registration can be exercised by an in-memory test client, a stdio host, or an HTTP host because the protocol surface is still resources/list and resources/read. The server owns the read callback, the client owns the decision to call it, and the returned content array is passed back without being reshaped. That makes resources a good place to expose context that should be auditable, repeatable, and safe to read.

Sources: docs/servers/resources.md

Relevant Source Files

  • docs/servers/resources.md - Defines the resource concept, static resource registration, multi-item read results, resource templates, and client read examples.
  • docs/servers/completion.md - Explains completion for resource template variables alongside prompt arguments, including how server-side suggestions are exposed to clients.
  • docs/servers/elicitation.md - Shows request-scoped server-to-client input flows that are relevant when resource-adjacent workflows need user participation.
  • docs/servers/errors.md - Defines how resource callbacks report invalid parameters and missing resources through protocol errors rather than tool-style isError results.
  • docs/servers/input-required.md - Describes input_required as the 2026-era pattern available to resources/read, prompts/get, and tools/call when a handler needs client-supplied input.
  • docs/servers/logging-progress-cancellation.md - Documents handler context helpers for notifications, logging, progress, and cancellation that apply across server handlers.

Core Resource Primitives

The primary server primitive is registerResource. For a static resource, the server supplies a registration name, a fixed URI, metadata, and an asynchronous read callback. Metadata such as title, description, and MIME type is advertised when clients list resources, while the callback runs only when a client reads the URI. The callback receives a URL-like URI value and returns an object with a contents array. Each content item echoes the URI it answers for and then carries either text or a base64 blob, optionally with its own MIME type.

Sources: docs/servers/resources.md

server.registerResource(
    'config',
    'config://app',
    { title: 'Application Config', mimeType: 'text/plain' },
    async uri => ({
        contents: [{ uri: uri.href, text: 'log_level=info' }]
    })
);

The distinction between resource-level and item-level MIME types is important. The registration metadata describes the resource as it appears in resources/list, which helps a client or host present it before reading. The MIME type on each returned content item describes that particular payload. A single read can return multiple content entries, such as a markdown report and a PNG chart for the same report URI. Clients receive the callback result array unchanged, so the server should return content in the order that is most useful for the consuming host.

Sources: docs/servers/resources.md

Defining Static Resources and Templates

A static resource is appropriate when the server knows the exact URI ahead of time, such as config://app or report://latest. A resource template is appropriate when the server owns a URI pattern, such as a user profile URI keyed by an identifier. ResourceTemplate registers the pattern and requires a list option; when instances are unbounded, the guide passes undefined for list. When a matching URI is read, parsed variables arrive as the second callback argument, allowing the handler to load the requested profile, row, document, or object without hand-parsing the URI string.

Sources: docs/servers/resources.md

server.registerResource(
    'user-profile',
    new ResourceTemplate('users://{userId}/profile', { list: undefined }),
    { title: 'User Profile', mimeType: 'application/json' },
    async (uri, { userId }) => ({
        contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify({ userId, plan: 'pro' }) }]
    })
);

Templates also connect to completion. The completion guide defines completion as server-side autocomplete for prompt arguments and resource template variables. A client sends the partial value that a user has typed, and the server returns matching suggestions. The first completable field registers the completion handler and advertises the completions capability automatically. For resource-heavy servers, this means a host can guide users toward valid template variables before issuing resources/read, reducing invalid reads and making large or unbounded resource spaces navigable without requiring the server to list every possible instance.

Sources: docs/servers/completion.md, docs/servers/resources.md

Client Consumption Flow

From the client point of view, resource use starts with discovery and ends with reading a chosen URI. The server guide says resources/list advertises static registrations with their metadata, and resources/read runs the matching callback. Client-side calling guidance adds that listResources and listResourceTemplates aggregate paginated server lists in the same style as listTools and listPrompts, unless the caller explicitly passes a cursor to request one raw page. That aggregation is useful for ordinary hosts, while cursor control remains available for applications that manage pagination themselves.

Sources: docs/servers/resources.md

A typical flow is: register the resource on the server, connect a client, list available resources or templates, choose a URI, and call readResource with that URI. The read result contains the content array returned by the server. If the resource is cacheable in a larger deployment, server cache hints can allow a client response cache to avoid repeated network reads while the result remains fresh, and per-resource cache hints can override a general resources/read policy. The resource itself remains read-only; freshness only changes whether the client must call back to the server.

Sources: docs/servers/resources.md

Errors, Input, and Handler Context

Resource callbacks do not have the tool error channel where a handler can return a successful result with isError true. The errors guide is explicit: resource, prompt, and completion callbacks should throw ProtocolError when the request itself is wrong. The example validates a note identifier, throws InvalidParams for malformed values, and throws ResourceNotFoundError when the URI is syntactically valid but no resource exists. This keeps client-visible failure semantics aligned with JSON-RPC errors for bad resource reads, instead of pretending that a failed read is normal resource content.

Sources: docs/servers/errors.md

For workflows that need user input, the 2026-era input_required pattern applies to resources/read as well as tools/call and prompts/get. A handler can return embedded input requests, the client answers them, and the original operation is retried with inputResponses. The input-required guide also emphasizes validation: responses come from the client and should be treated as untrusted, with schema validation used before accepted content influences the handler. Older push-style elicitation is documented for tool handlers, but the resource-compatible pattern to prefer for the current protocol surface is the retry-based input_required result.

Sources: docs/servers/input-required.md, docs/servers/elicitation.md

Every handler receives request-scoped context, and the logging, progress, and cancellation guide describes helpers on ctx.mcpReq. Although the examples focus on tools, the design guidance is still useful when a resource read performs expensive work such as rendering a report or loading many backing objects. Only send progress when the client supplied a progress token, and honor cancellation for long-running reads. MCP logging is marked deprecated for the 2026-07-28 protocol version, so production servers should prefer stderr for stdio deployments or observability systems such as OpenTelemetry.

Sources: docs/servers/logging-progress-cancellation.md

Compact Reference

ConcernServer behaviorClient-visible effect
Static resourceRegister a fixed URI with metadata and a read callbackresources/list advertises the URI; resources/read runs the callback
Read resultReturn contents with text or blob entriesClient receives the content array unchanged
Resource templateRegister a URI pattern with ResourceTemplateMatching variables are passed to the callback
CompletionProvide suggestions for template variablesHosts can autocomplete user input before reading
Missing or invalid resourceThrow ProtocolError or ResourceNotFoundErrorClient receives a protocol error, not an isError tool result
Additional inputReturn input_required from resources/read when neededClient answers and retries with inputResponses

Next Steps

After defining resources, test them through the same client path a real host will use: list resources, read a static URI, read a templated URI, and verify error cases. Add completion when users must choose among known identifiers, and use input_required only when a read cannot safely continue without client-supplied information. If the resource is expensive but stable, review client caching behavior and cache hints. For adjacent server features, read the pages on tools, prompts, completion, input required, errors, and logging or cancellation so each handler type reports success, failure, and user interaction consistently.