Add resources primitive (resources/list, resources/read, templates) #5
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Add the Resources primitive — server exposes addressable, read-only content (files, URIs, generated views) that clients can list, read, and reference in prompts without going through a tool call. This is the largest single missing surface vs. the MCP spec (
2025-06-18).Goal
Let an MCP client browse and read content the server owns, the same way it browses tools today. Tools-only servers force the client to spend a
tools/callround-trip for every read, with no caching key the client can use. Resources fix that with stable URIs and explicit text/binary types.Methods to add
resources/list{ resources: [{ uri, name, description?, mimeType? }], nextCursor? }. Cursor-paginated.resources/read{ uri }→{ contents: [{ uri, mimeType, text | blob }] }.blobis base64 for binary.resources/templates/listfile:///{path}) clients can fill in.notifications/resources/list_changedDefer to a v2 (separate issue):
resources/subscribe,resources/unsubscribe,notifications/resources/updated. They require server-initiated transport (depends on the Streamable-HTTP issue).API for lmcp (Lua surface)
Mirror the existing
server:tool(name, desc, schema, handler)shape:Handler return convention: string → single text content; table with
blob/mimeType→ binary content; raise → JSON-RPC error. Matches the existing tool handler ergonomics.Capabilities advertisement
initializeresponse gains:Scope (v1)
resources/list,resources/read,resources/templates/list.notifications/resources/list_changedif a resource is registered after init.resources/list(even if lmcp returns everything in one page today — keeps the contract spec-conformant).Out of scope (separate issues)
resources/subscribe+notifications/resources/updated— needs server-initiated SSE._metafield passthrough — covered by the "structured tool output" issue.Priority
High — biggest single MCP-spec gap in lmcp. Unlocks a class of client patterns (resource-pickers, attach-to-prompt UI, cached reads) that tools-only servers can't reach. Estimated 1 day.
Implemented in lmcp.lua. Resources primitive:
server:resource(uri, opts, handler)+server:resource_template(uriTemplate, opts, handler);resources/list,resources/read,resources/templates/listdispatch;notifications/resources/list_changedqueue (delivery NYI per #16); template captures via(.+)greedy substitution; binary blob auto-base64 viamime.b64; -32002 for not-found, -32602 for invalid params, -32603 for handler errors.Capability advertised iff a resource/template is registered OR
opts.resources = true(opt-in for late registration).Verified live: capability emission, text/binary/template reads, error paths, backwards compat preserved. Sample resources in example_server.lua:
text://greeting,data://lmcp.png,file:///{path}.Memory: project_json_empty_table_gotcha.md captures the
{}→[]encoding trap that bit notification.params — workaround was to omitparamsentirely. Later issue #19 added thejson.empty_objectsentinel for cases where omission isn't an option.