Skip to content

refactor(mcp): eliminate duplicate cursor cycle detection by delegating paginateAll to PaginateAll#8049

Merged
lpcox merged 3 commits into
mainfrom
copilot/duplicate-code-fix-pagination
Jun 24, 2026
Merged

refactor(mcp): eliminate duplicate cursor cycle detection by delegating paginateAll to PaginateAll#8049
lpcox merged 3 commits into
mainfrom
copilot/duplicate-code-fix-pagination

Conversation

Copilot AI commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

paginateAll and PaginateAll in internal/mcp/pagination.go each independently implemented cursor cycle detection and page-limit enforcement — identical safety logic duplicated across ~30 lines, with subtly divergent ordering and error messages.

Changes

  • internal/mcp/pagination.gopaginateAll is now a thin adapter over PaginateAll. A closure bridges the paginatedPage[T] fetch signature to PaginateAll's ([]T, string, error) contract, adding per-page logging. Errors are wrapped with serverID/itemKind context to preserve richer diagnostics:

    func paginateAll[T any](serverID, itemKind string, fetch func(cursor string) (paginatedPage[T], error)) ([]T, error) {
        result, err := PaginateAll(paginateAllMaxPages, func(cursor string) ([]T, string, error) {
            page, err := fetch(cursor)
            if err != nil {
                return nil, "", err
            }
            logConn.Printf("list%s: received page of %d %s from serverID=%s", itemKind, len(page.Items), itemKind, serverID)
            return page.Items, page.NextCursor, nil
        })
        if err != nil {
            return nil, fmt.Errorf("list%s: backend serverID=%s: %w", itemKind, serverID, err)
        }
        logConn.Printf("list%s: received %d %s total from serverID=%s", itemKind, len(result), itemKind, serverID)
        return result, nil
    }
  • internal/mcp/pagination_test.go, internal/mcp/connection_test.go — Updated two test cases whose error-message assertions referenced the old paginateAll wording ("more than" / "pages") to match the PaginateAll format ("exceeded" / "page limit").

The mid-pagination "total so far" log is intentionally dropped; PaginateAll logs its own per-page progress, and the final total is still emitted after all pages are collected.

GitHub Advanced Security started work on behalf of lpcox June 24, 2026 14:58 View session
GitHub Advanced Security finished work on behalf of lpcox June 24, 2026 14:59
paginateAll now delegates to PaginateAll for cursor cycle detection and
page-limit enforcement instead of reimplementing that logic independently.
An adapter closure bridges the paginatedPage[T] fetch signature to the
([]T, string, error) signature expected by PaginateAll, and errors are
wrapped with serverID/itemKind context to preserve richer diagnostics.

Per-page "total so far" logging is intentionally removed in favour of the
per-page log emitted inside the adapter and the final total log after
PaginateAll returns. PaginateAll itself also logs per-page progress.

Updated tests in pagination_test.go and connection_test.go to match the
new error-message format ("exceeded N-page limit" instead of
"more than N pages").
Copilot AI changed the title [WIP] Fix duplicate cursor cycle detection logic in pagination refactor(mcp): eliminate duplicate cursor cycle detection by delegating paginateAll to PaginateAll Jun 24, 2026
GitHub Advanced Security started work on behalf of lpcox June 24, 2026 15:06 View session
Copilot finished work on behalf of lpcox June 24, 2026 15:06
Copilot AI requested a review from lpcox June 24, 2026 15:06
GitHub Advanced Security finished work on behalf of lpcox June 24, 2026 15:06
@lpcox lpcox marked this pull request as ready for review June 24, 2026 15:10
Copilot AI review requested due to automatic review settings June 24, 2026 15:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors MCP pagination so the internal paginateAll helper delegates the core cursor pagination logic (cycle detection + page limit enforcement) to the shared PaginateAll implementation, reducing duplicated safety logic while keeping server-scoped logging and error context.

Changes:

  • Refactor paginateAll to call PaginateAll via an adapter closure and wrap errors with serverID/itemKind context.
  • Update error-message assertions in tests to match the PaginateAll error wording.
Show a summary per file
File Description
internal/mcp/pagination.go Refactors paginateAll to delegate pagination mechanics to PaginateAll while retaining list logging and contextual error wrapping.
internal/mcp/pagination_test.go Updates assertions to match the new page-limit error message text.
internal/mcp/connection_test.go Updates assertions to match the new page-limit error message text.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 3/3 changed files
  • Comments generated: 1

Comment on lines +72 to +84
result, err := PaginateAll(paginateAllMaxPages, func(cursor string) ([]T, string, error) {
page, err := fetch(cursor)
if err != nil {
return nil, err
return nil, "", err
}
all = append(all, page.Items...)
logConn.Printf("list%s: received page of %d %s (total so far: %d) from serverID=%s", itemKind, len(page.Items), itemKind, len(all), serverID)
cursor = page.NextCursor
logConn.Printf("list%s: received page of %d %s from serverID=%s", itemKind, len(page.Items), itemKind, serverID)
return page.Items, page.NextCursor, nil
})
if err != nil {
return nil, fmt.Errorf("list%s: backend serverID=%s: %w", itemKind, serverID, err)
}
logConn.Printf("list%s: received %d %s total from serverID=%s", itemKind, len(all), itemKind, serverID)
return all, nil
logConn.Printf("list%s: received %d %s total from serverID=%s", itemKind, len(result), itemKind, serverID)
return result, nil
@lpcox

lpcox commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

GitHub Advanced Security started work on behalf of lpcox June 24, 2026 15:21 View session
GitHub Advanced Security finished work on behalf of lpcox June 24, 2026 15:22

Copilot AI commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Addressed in commit da8a2f7. paginateAll now normalizes a nil delegated result to a non-nil empty slice so list responses keep array shape ([]), and the helper test now asserts the empty result is non-nil.

Copilot finished work on behalf of lpcox June 24, 2026 15:22
@lpcox lpcox merged commit 848479a into main Jun 24, 2026
27 checks passed
@lpcox lpcox deleted the copilot/duplicate-code-fix-pagination branch June 24, 2026 15:24
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.

3 participants