Module: ActionMCP::Server::Pagination
- Included in:
- TransportHandler
- Defined in:
- lib/action_mcp/server/pagination.rb
Overview
Shared cursor-based pagination for all list endpoints.
Two strategies:
1. Offset-based — for in-memory arrays (tools, prompts, resource templates).
2. Keyset-based — for ActiveRecord relations (tasks). Stable under concurrent writes.
When pagination_page_size is nil (default), returns all items unless the caller passes force: true or the client sends a cursor.
Constant Summary collapse
- DEFAULT_PAGE_SIZE =
10
Instance Method Summary collapse
-
#paginate(collection, cursor: nil, page_size: nil, force: false) ⇒ Array(Array, String|nil)
Offset-based pagination for in-memory collections (tools, prompts, resources).
-
#paginate_by_keyset(relation, cursor: nil, page_size: DEFAULT_PAGE_SIZE, column: :id) ⇒ Array(Array, String|nil)
Keyset-based pagination for ActiveRecord relations.
Instance Method Details
#paginate(collection, cursor: nil, page_size: nil, force: false) ⇒ Array(Array, String|nil)
Offset-based pagination for in-memory collections (tools, prompts, resources). For ActiveRecord relations, use paginate_by_keyset instead.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/action_mcp/server/pagination.rb', line 24 def paginate(collection, cursor: nil, page_size: nil, force: false) effective_page_size = page_size || pagination_page_size items = Array(collection) return [ items, nil ] unless force || effective_page_size || cursor page_size = effective_page_size || DEFAULT_PAGE_SIZE offset = decode_offset_cursor(cursor) page = items.drop(offset).take(page_size + 1) has_more = page.size > page_size page = page.first(page_size) if has_more next_cursor = has_more ? encode_offset_cursor(offset + page_size) : nil [ page, next_cursor ] end |
#paginate_by_keyset(relation, cursor: nil, page_size: DEFAULT_PAGE_SIZE, column: :id) ⇒ Array(Array, String|nil)
Keyset-based pagination for ActiveRecord relations. Uses a single column as cursor (must be unique + ordered). The relation MUST already be ordered by that column.
50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/action_mcp/server/pagination.rb', line 50 def paginate_by_keyset(relation, cursor: nil, page_size: DEFAULT_PAGE_SIZE, column: :id) if cursor value = decode_keyset_cursor(cursor) relation = relation.where(column => ...value) end page = relation.limit(page_size + 1).to_a has_more = page.size > page_size items = has_more ? page.first(page_size) : page next_cursor = has_more ? encode_keyset_cursor(items.last, column) : nil [ items, next_cursor ] end |