Skip to main content

Module pagination

Module pagination 

Source
Expand description

MCP pagination helpers.

ClickUp’s paginated endpoints come in four flavours:

  • page-based (v2): ?page=N, response carries last_page: bool.
  • cursor-based (v3): ?cursor=X, response carries next_cursor: string or null.
  • start-id-based (v2 comments): ?start=<unix_ms>&start_id=<id> pair, response is a bare array, termination inferred from page-size hint.
  • body-based (v3 audit-log): pagination state lives inside the POST body as pagination: { pageRows, pageTimestamp, pageDirection }.

This module hides the loop logic and response-shape glue so each MCP tool dispatch can be a one-liner.

§Contract

Schema. Every paginated tool’s inputSchema gains one of:

  • page style: page (int ≥0), limit (int ≥1), all (bool); or
  • cursor style: cursor (opaque string), limit (int ≥1), all (bool); or
  • start-id style: start (int ms), start_id (string), limit (int ≥1), all (bool); or
  • body style: page_rows, page_timestamp (int ms), page_direction ("NEXT"/"PREVIOUS"), limit, all.

Output. The contract is opt-in:

  • If the caller passes NO pagination arg, the response is unchanged from pre-pagination: a bare compact array. Back-compat for existing clients.

  • If the caller passes ANY pagination arg, the response becomes an envelope:

    {
      "items": [...],
      "pagination": {
        "style": "page" | "cursor" | "start_id" | "body",
        "page": 0,                       // page style only
        "last_page": false,              // page style only
        "next_cursor": "...",            // cursor style only, omitted when exhausted
        "next_start": 1700000000,        // start_id style only, omitted when exhausted
        "next_start_id": "...",          // start_id style only, omitted when exhausted
        "next_page_timestamp": 1700000,  // body style only, omitted when exhausted
        "page_direction": "NEXT",        // body style only, echoes caller input
        "has_more": true,
        "returned": 42,
        "all": false
      }
    }

Calling code uses PageArgs::from_args / CursorArgs::from_args / StartIdArgs::from_args / BodyPaginationArgs::from_args to parse pagination input, then page_dispatch / cursor_dispatch / start_id_dispatch / body_pagination_dispatch to run the fetch loop.

Structs§

BodyPaginationArgs
Parsed body-pagination input. ClickUp’s v3 audit-log endpoint (POST /v3/workspaces/{ws}/auditlogs) puts pagination state inside the request body as pagination: { pageRows, pageTimestamp, pageDirection }, not in query params. pageDirection is "NEXT" or "PREVIOUS"--all walks in whatever direction the caller passes, defaulting to "NEXT" (newer events) if unspecified.
CursorArgs
Parsed cursor-based pagination input.
PageArgs
Parsed page-based pagination input.
StartIdArgs
Parsed start-id-based pagination input. ClickUp’s v2 comment endpoints (/v2/task/{id}/comment, /v2/list/{id}/comment, /v2/view/{id}/comment, /v2/comment/{id}/reply) use this style: pass ?start=<unix_ms>&start_id=<id> to retrieve items older than that boundary. Both params are required as a pair when paginating; omitting them returns the first page (newest first). The response is a bare { "comments": [...] } array — no pagination metadata — so termination is inferred when the returned array is shorter than the endpoint’s page size (25 for ClickUp’s comment endpoints).

Functions§

body_pagination_dispatch
Run a body-pagination POST loop for endpoints like the v3 audit-log query. Pagination state lives inside the request body as pagination: { pageRows, pageTimestamp, pageDirection }.
cursor_dispatch
Run a cursor-based pagination loop. build_path(cursor) should return a path including any ?cursor=... query when cursor is Some, or no cursor query when None. items_keys is the list of candidate response keys to extract the array from; first match wins. Typical: &["data", "<legacy>"] where <legacy> is the pre-v3 key ("channels", "replies", etc.) for back-compat with any older envelope shape.
page_dispatch
Run a page-based pagination loop and return either a bare compact array (no pagination args) or a {items, pagination} envelope (any pagination arg). build_path(page) should return a path including any ?page=N query, e.g. /v2/list/123/task?page=2. items_key is the response field holding the array (e.g. "tasks").
start_id_dispatch
Run a start-id-based pagination loop. build_path(start, start_id) should return a path including the ?start=...&start_id=... query when both are Some, or no pagination query when both are None. (ClickUp requires the params as a pair — passing only one is a caller bug.) items_key is the response array’s field name ("comments" for both comment endpoints).