resource() and register its definition beside
your tools. Toolgrain never fetches URLs or maps URIs to local files automatically.
Declare and register a resource
resource() to create another definition. Raw
objects and spreads are not valid registrations. Duplicate URIs fail server
construction. Readonly registration arrays and content arrays are accepted.
Registration copies display metadata without invoking readers. resources/list
returns this fixed list in registration order. resources/read matches URI strings
exactly and invokes the matching reader. Custom schemes, including ui:// and
urn:, are accepted when they form valid absolute URIs.
Return explicit contents
A reader returns{ contents, _meta? }, synchronously or asynchronously. Every
entry supplies its own URI, optional MIME type and _meta, and exactly one of
text or base64 blob. One read can return several entries. Listing metadata
is not automatically copied onto content entries.
contents: []; an unknown URI returns a resource-not-found error instead.
Use context and authorization
read(uri, ctx) receives the existing ToolContext: frozen request/client
metadata, ctx.signal, auth accessors, and lazy context providers.
Providers resolve only on access and cache per read request. Readers own their
application services and should pass ctx.signal to cancellable work.
Configured endpoint authentication runs before resource work. The static list is
the same for every authorized caller; resource-specific authorization policies
and dynamic discovery are not provided. Readers can use the verified identity
through JWT/Clerk’s useAuth(ctx) when producing content.
For direct calls in tests, use guide.read(guide.uri, toolContext()) after importing
toolContext from @toolgrain/mcp. Direct reads remain raw: they bypass endpoint
auth and result validation. Context provider overrides work through toolContext().
Protocol behavior and limits
Both MCP2026-07-28 and 2025-06-18 support listing and reading over the existing
transports. Modern HTTP reads require Mcp-Method: resources/read and a Mcp-Name
header matching the URI, plus the usual request metadata and version header. See
HTTP transport for header encoding and hosting requirements.
Supplying resources, even [], advertises resources: {}. Omitting it leaves
resource methods disabled. Lists are unpaginated and reject every supplied cursor.
resources/templates/list returns an empty list; template declarations,
subscriptions, and list-change notifications are not supported.
Modern resource results include resultType: "complete", ttlMs: 0, and
cacheScope: "private". Legacy results omit those fields and listing icons.
Unknown URIs return Resource not found with code -32602 in modern mode or
-32002 in legacy mode. Unexpected reader/provider/output failures return
-32603 with Internal error; onError(error) receives the original failure.
Cancelled requests suppress late results and diagnostics.
Resource and content-item _meta are preserved, including UI security metadata.
Use this resource foundation with the native MCP Apps integration.
The host renders widgets; Toolgrain serves HTML and links tools through metadata.
See the resource API reference, the runnable
Elysia example,
and the MCP resource specification.