Add cursor pagination to list methods (tools/list etc.) #12

Closed
opened 2026-05-17 15:56:09 +00:00 by claude-noether · 1 comment
Collaborator

Add cursor-based pagination to list methods (tools/list, and eventually resources/list, prompts/list, resources/templates/list).

Goal

The MCP spec defines list methods as cursor-paginated: response carries optional nextCursor; request carries optional cursor. lmcp's tools/list returns everything at once with no cursor field. This is non-conformant — strict clients may reject the response shape or fail to handle a server that suddenly grows past their default page.

Method signatures to align

Method Request adds Response adds
tools/list params.cursor (opaque string) result.nextCursor (opaque string, optional)
(later) resources/list, prompts/list, resources/templates/list same same

API for lmcp

No surface change for tool authors. Server-side: implement a paginate(items, cursor, limit) helper that:

  • decodes cursor (e.g. base64-encoded offset string),
  • returns (page, next_cursor_or_nil).

Default page size: 50 (well above today's tool count; mostly a contract-conformance change).

Cursor format

Opaque to clients per spec. lmcp can use b64(offset) or b64(last_name) — implementation detail. Don't expose offset semantics.

Scope (v1)

  • Add cursor param parsing and nextCursor emission to tools/list.
  • Implement paginate() helper.
  • Apply to resources/list / prompts/list etc. as those land — or piggyback on this issue and update once Resources/Prompts merge.

Out of scope

  • Server-driven hint about page-size; spec doesn't require it.
  • Reverse pagination.

Priority

Low. Pure conformance fix; no current-user impact (no lmcp server is anywhere near 50 tools). Hour of work.

Add **cursor-based pagination** to list methods (`tools/list`, and eventually `resources/list`, `prompts/list`, `resources/templates/list`). ## Goal The MCP spec defines list methods as cursor-paginated: response carries optional `nextCursor`; request carries optional `cursor`. lmcp's `tools/list` returns everything at once with no cursor field. This is non-conformant — strict clients may reject the response shape or fail to handle a server that suddenly grows past their default page. ## Method signatures to align | Method | Request adds | Response adds | |---|---|---| | `tools/list` | `params.cursor` (opaque string) | `result.nextCursor` (opaque string, optional) | | (later) `resources/list`, `prompts/list`, `resources/templates/list` | same | same | ## API for lmcp No surface change for tool authors. Server-side: implement a `paginate(items, cursor, limit)` helper that: - decodes `cursor` (e.g. base64-encoded offset string), - returns `(page, next_cursor_or_nil)`. Default page size: 50 (well above today's tool count; mostly a contract-conformance change). ## Cursor format Opaque to clients per spec. lmcp can use `b64(offset)` or `b64(last_name)` — implementation detail. Don't expose offset semantics. ## Scope (v1) - Add `cursor` param parsing and `nextCursor` emission to `tools/list`. - Implement `paginate()` helper. - Apply to `resources/list` / `prompts/list` etc. as those land — or piggyback on this issue and update once Resources/Prompts merge. ## Out of scope - Server-driven hint about page-size; spec doesn't require it. - Reverse pagination. ## Priority **Low**. Pure conformance fix; no current-user impact (no lmcp server is anywhere near 50 tools). Hour of work.
Author
Collaborator

Implemented. paginate(items, cursor) helper in lmcp.lua; wired into tools/list, resources/list, resources/templates/list. Default page size 50. Cursor is opaque base64(offset).

Verified with 60-tool synthetic server: page 1 returns 50 + nextCursor NTA= (base64 of 50); page 2 returns 10, no nextCursor. Malformed cursors are tolerated (treated as offset 0). Backwards-compatible: requests with no cursor param work as before.

Production server.lua (9 tools) emits no nextCursor — still single-page, contract is now spec-conformant.

Implemented. `paginate(items, cursor)` helper in lmcp.lua; wired into `tools/list`, `resources/list`, `resources/templates/list`. Default page size 50. Cursor is opaque base64(offset). Verified with 60-tool synthetic server: page 1 returns 50 + nextCursor `NTA=` (base64 of `50`); page 2 returns 10, no nextCursor. Malformed cursors are tolerated (treated as offset 0). Backwards-compatible: requests with no cursor param work as before. Production server.lua (9 tools) emits no nextCursor — still single-page, contract is now spec-conformant.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marfrit/lmcp#12