What is MCP Resource?
MCP Resource is an application-controlled, URI-addressed data contract that an MCP Server exposes for an MCP Client to list or read without automatically exposing the content to a model or making it trusted.
Quick Facts
| Specification | Official Specification |
|---|
How It Works
An MCP Resource is the context-data primitive in the Model Context Protocol. A Server describes and serves data, a Client discovers or reads it, and the Host decides whether, when, and how much to place in a model's context. Registration makes a Resource available through the protocol; it does not inject the content into a conversation or guarantee that a model will see it. Resource is an application-controlled interaction convention, unlike a model-controlled MCP Tool action or a user-controlled MCP Prompt template.
In MCP 2026-07-28, every resources/list, resources/templates/list, and resources/read Request is stateless and carries the protocol version and relevant Client Capabilities in _meta. A Server supporting Resources declares the resources Capability through server/discover, with optional listChanged and subscribe features. Resource lists may be empty or filtered by credentials on the current Request, but they must not vary merely because another Request used the same Connection. The Host must qualify a Resource by its configured Server identity as well as its URI when multiple Servers could expose the same identifier.
resources/list returns concrete, currently known Resources; resources/templates/list returns parameterized URI spaces described by RFC 6570. Both support opaque Cursor Pagination and cacheable Complete Results. A Resource definition includes uri and name, plus optional display title, description, icons, MIME type, raw byte size, annotations, and metadata. A Template replaces uri with uriTemplate; its variables may use completion/complete for suggestions. Template expansion only constructs an identifier. It does not validate the business object, prove existence, or authorize the expanded Tenant, repository, record, or path.
A URI identifies a Resource under RFC 3986; it is not necessarily a browser URL or a safe dereference target. Use https:// only when the Client can fetch that Resource directly from the Web. A file:// Resource can represent filesystem-like data without mapping to a physical local file, while git:// and documented custom schemes can express domain semantics. Never place access tokens, credentials, or sensitive query data in a URI because logs, history, caches, telemetry, and error reports commonly retain identifiers. Parse and validate with scheme-aware libraries instead of concatenating strings.
resources/read takes a concrete URI and returns one or more Text or Base64-encoded Blob content items. Each item repeats its URI and can declare a MIME type; the size descriptor is only a raw-byte estimate before Base64 or tokenization. Enforce response byte, item-count, decompression, decode-time, and media-type limits before rendering or adding content to a model. A claimed MIME type, filename extension, or audience, priority, and lastModified annotation is a hint, not proof of format, freshness, importance, or trust.
Complete List, Template List, and Read Results carry resultType: "complete", non-negative ttlMs, and cacheScope. Use public only when content is identical and safe to share across callers; user-, Tenant-, role-, or token-dependent responses require private and a cache key bound to the Authorization Context. TTL is a freshness hint rather than a consistency guarantee. A notification invalidates an otherwise fresh cache, and paginated pages have no cross-page snapshot guarantee. If a coherent list matters, restart from the first page after changes or an invalid Cursor.
Current subscriptions use a long-lived subscriptions/listen Request. A Client opts into resourcesListChanged or specific resourceSubscriptions; the Server first acknowledges the accepted filter, then correlates notifications with io.modelcontextprotocol/subscriptionId. notifications/resources/list_changed invalidates discovery, while notifications/resources/updated reports a URI and prompts the Client to call resources/read again; it does not carry replacement content. Closing the stream cancels the subscription, and a reconnect requires a new Request. The older resources/subscribe, resources/unsubscribe, and standalone HTTP GET stream belong to legacy protocol revisions.
A resources/read operation may return MRTR resultType: "input_required" when it needs supported Elicitation, Roots, or legacy Sampling input. List operations cannot. The retry is a separate Request with a new JSON-RPC ID, inputResponses, and optional opaque requestState; it is not cacheable. Treat that State as attacker-controlled, protect integrity when it influences identity, authorization, target URI, or query semantics, and bind it to the Principal, method, salient parameters, policy revision, and short expiry. A Client must echo it but must not inspect or modify it.
Error semantics matter for caches and callers. A missing Resource returns JSON-RPC -32602 Invalid Params in 2026-07-28; Clients should still accept legacy -32002, while internal failures use -32603. Do not represent a missing Resource with an empty contents array because that is indistinguishable from a valid empty Resource. Separate Not Found, Denied, Timeout, Too Large, Invalid Encoding, Stale Cursor, and Upstream Failure in internal telemetry, while limiting external detail so errors do not disclose Resource existence across authorization boundaries.
Resource access remains authorization-sensitive even when it is read-oriented. On every Request, validate the authenticated Principal, Server, Tenant, URI scheme, object, requested projection, data classification, purpose, and output policy. For file://, decode and normalize according to the target platform, reject path traversal and disallowed Authority or device names, resolve symlinks, confine the final object to an allowed root, and reduce time-of-check/time-of-use races. For Server-side remote fetches, allowlist schemes and destinations, block loopback, link-local, private and metadata networks, re-check DNS and redirects, and enforce timeout and byte limits to contain SSRF.
Resource content is untrusted data. Documents, issue text, logs, HTML, images with extracted text, and database fields can contain Prompt Injection or instructions that attempt to override Host policy and trigger Tools. Preserve Provenance, delimit data from instructions, minimize what enters context, require citations for grounded claims, and prevent content from granting itself permissions. MCP Resource is also not RAG: MCP standardizes addressable discovery and retrieval, while a RAG system defines chunking, indexing, ranking, evidence selection, and answer evaluation. A Resource can expose RAG outputs or indexes without inheriting their retrieval quality.
Production traces should link an immutable Server build, Resource or Template revision, normalized URI digest, Principal and Tenant, authorization policy, pagination or subscription ID, cache decision, source revision, MIME validation, byte and token estimates, truncation, latency, error class, and model-context inclusion decision. Redact Resource bodies, secrets, personal data, and raw sensitive URIs. A successful resources/read proves that protocol retrieval completed; it does not prove that the bytes are accurate, current, safe to render, or appropriate for a model.
Key Characteristics
- Application-controlled context: the Host chooses discovery, reading, presentation, and model-context inclusion instead of granting the model automatic access
- URI-addressed contract: concrete Resources use RFC 3986 identifiers, while RFC 6570 Templates describe parameterized URI spaces
- Typed bounded content: Read returns text or Base64 Blob items with optional MIME metadata under explicit byte, decode, and context-budget limits
- Cache-aware freshness: Complete Results declare TTL and public/private scope, while notifications invalidate cached discovery or content
- Subscription-driven updates: subscriptions/listen delivers correlated list or Resource change signals and Clients re-read content on demand
- Zero-trust data boundary: every URI, object, path, remote destination, annotation, and returned byte remains subject to authorization and content safety policy
Common Use Cases
- Expose selected repository files and documentation under an allowed root without granting arbitrary filesystem traversal
- Publish Tenant-scoped database schemas or records as private cached context without exposing write operations
- Describe versioned documentation or issue records with URI Templates and permission-filtered completion suggestions
- Notify an application that a configuration, runbook, or live metric Resource changed so it can invalidate and selectively re-read context
- Return large Tool artifacts through scoped Resource links with provenance, size limits, expiration, and explicit context inclusion
Example
Loading code...Frequently Asked Questions
How is an MCP Resource different from an MCP Tool?
A Resource is an application-controlled data contract that a Client reads by URI and a Host may add to context. A Tool is a model-controlled action contract invoked through tools/call. Reading a Resource should not intentionally mutate backend state, but it still requires authorization, limits, and content safety because retrieval can expose sensitive data or trigger expensive upstream work.
Does registering an MCP Resource make it visible to the model?
No. Registration makes metadata discoverable; resources/list does not return the body, and resources/read only returns it to the Client. The Host still decides whether to show the Resource to a user, include selected content in a model request, summarize it, or omit it. That decision must respect permissions, relevance, provenance, and the context budget.
Is an MCP Resource the same as RAG?
No. MCP defines how a Server describes and returns addressable context. RAG defines how a system chunks, indexes, retrieves, ranks, cites, and evaluates evidence for a query. A Resource may expose a document, an index description, or selected RAG output, but MCP does not guarantee retrieval relevance, grounding, or answer faithfulness.
How do caching and Resource update notifications work?
A Complete Result provides ttlMs and public or private cacheScope. TTL indicates when a Client should consider data stale, while an accepted notifications/resources/updated event invalidates the matching cache early. The notification carries a URI rather than new content, so the Client re-reads when needed. Disconnecting ends subscriptions/listen and reconnection requires a new subscription.
How should file and remote MCP Resources be secured?
Authorize the exact Principal, Tenant, scheme, and object on every Request. For file URIs, use platform-aware parsing, resolve the final path and symlinks inside an allowed root, and reject traversal, unsafe Authority values, and device names. For remote fetches, allowlist destinations, block internal networks and redirect escapes, and bound time, bytes, decoding, MIME handling, and model-context inclusion.