Skip to content

Serve resources over resources/list and resources/read - #1

Open
la55u wants to merge 2 commits into
chore/prettierfrom
feat/resources
Open

la55u wants to merge 2 commits into
chore/prettierfrom
feat/resources

Conversation

@la55u

@la55u la55u commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Stacked on #3 (Prettier). Review only the top two commits.

Summary

Adds the resources capability, so a server can expose documents (including MCP Apps ui:// views) instead of only tools:

resources: {
  list: [{ uri: "ui://demo/chart", name: "chart", mimeType: "text/html;profile=mcp-app" }],
  read: async (ctx, uri, user) => {
    if (uri !== "ui://demo/chart") return null;
    return { contents: [{ uri, mimeType: "text/html;profile=mcp-app", text: html }] };
  },
},

Behavior

  • resources is advertised only when options.resources is set, so existing servers behave exactly as before. listChanged: false; no subscribe (2026-07-28 replaced it with subscriptions/listen).
  • Three methods in both eras: resources/list, resources/templates/list, resources/read. list and templates are optional and are served as empty when unset: the spec lets UI-only resources stay unlisted, but the advertised capability still promises the methods.
  • Entries are opaque and sent as-is, so _meta, title, size and annotations survive untouched.
  • Errors:
    • read returning null → Resource not found with the URI in error.data: -32602 on MCP 2026-07-28 (SEP-2164) and -32002 on earlier revisions.
    • A missing or non-string uri → -32602 invalid params (not "not found").
    • A throwing handler → generic -32603; the error is logged, never sent (same policy as tool handlers).
  • ttlMs/cacheScope only on the 2026-07-28 path (SEP-2549): the tool-list TTL for the lists, ttlMs: 0 + private for resources/read.
  • The existing Mcp-Name header check already covers resources/read in the modern era.
  • No scopes on resources. Handlers receive the verified user; access control is theirs, the same as for internal functions. Documented in README and DESIGN.

Out of scope

resources/subscribe, notifications/resources/*, and prompts. This is the read path only.

Testing

src/client/index.test.ts:

  • the capability is advertised only when configured, and the methods are -32601 (404 on 2026-07-28) without it
  • legacy list/templates/read with no cache hints
  • modern ttlMs/cacheScope and -32602 + error.data.uri; legacy -32002
  • read-only config serves empty lists
  • non-string uri → -32602
  • a throwing handler → -32603 without leaking the error

npm test → 68 pass · npm run typecheck · npm run lint

MCP Apps rides on top of this: the tool's _meta.ui.resourceUri (convex#7) points at a resource, and the host fetches it with resources/read. Nothing in this PR knows about ui://; the example lands in the next PR.

@la55u
la55u changed the base branch from main to chore/prettier November 14, 2026 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant