agentleFS
Tamircohen28Tamircohen28/tamirs-superpowers/skills/mcp/mcp-pagination/SKILL.md

mcp-pagination

Skill2 starsChanged 3 months agoMITView on GitHub

Internal guardrail invoked by mcp-builder only — audits MCP tool schemas with list_*, search_*, find_*, get_all_* or SQL-executing operations for missing pagination (limit, offset, cursor) and unbounded results. Not for general MCP questions, single-item getters, or mutation-only tools.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 4 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If mcp-builder passes planned tool names or API pagination params, use them as input for Steps 1–3 below.

    line 57
  2. Distinctive:

    Use these defaults unless the tool's documentation specifies lower maximums:

    line 91
  3. Distinctive:

    If a tool has no pagination parameter, narrow scope with filters before fetching:

    line 104
  4. Distinctive:

    Do NOT pre-fetch all pages and merge results — this defeats the guardrail entirely.

    line 134
  5. Distinctive:

    Before approving any MCP server design that includes list or search tools, verify:

    line 212
  6. Very specific:

    When invoked from mcp-builder Phase 4.1, report pass/fail per item.

    line 224

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

MCP Pagination Guardrails (Internal)

Why this skill exists

MCP tools that return lists or search results have no built-in safety net against unbounded responses. Calling list_issues, search_code, or any similar tool without a limit parameter can return hundreds or thousands of items, consuming 10-100x more tokens than needed, slowing responses, and inflating API costs. Naive implementations skip pagination because the tool "works" without it — this guardrail enforces limits before that mistake reaches production.

This skill is invoked by mcp-builder via Skill("mcp-pagination") when list/search operations appear in an MCP server design. It is not user-facing — users should run mcp-builder instead.

When mcp-builder invokes this skill

mcp-builder phaseWhy
Phase 1.3 — after cataloging collection endpointsSet pagination strategy before any tool schemas
Phase 3.0 — before each list_* / search_* / SQL toolApply limits and cursor mapping per tool
Phase 4.1 — after Inspector testingRun quick-reference checklist against implemented tools
Phase 5 — eval designConfirm evals use caller-driven pagination, not full scans

If mcp-builder passes planned tool names or API pagination params, use them as input for Steps 1–3 below.

Workflow

Step 1 — Identify list/search operations in the MCP server design.

Any tool whose name matches these patterns needs a limit strategy:

  • list_* — always paginated
  • search_* — always paginated
  • get_* that returns an array at the top level — treat as paginated (name prefix alone does not exempt a tool; return type is what matters)
  • SQL-executing tools — require LIMIT clause enforcement

Exempt from guardrails (do not flag these):

  • Single-item getters: get_issue(id), get_user(id) — return one object, not an array
  • Mutations: create_*, update_*, delete_* — not collection operations
  • Streaming/generative tools: LLM completion streams, SSE feeds, WebSocket subscriptions — these push generated data, not paginated lists

For API-specific pagination parameter names (GitHub REST per_page, GraphQL first/after, Slack cursor, Notion page_size, etc.), load references/pagination-patterns.md.

Step 2 — Verify each operation has a limiting mechanism.

For each identified operation, confirm one of the following is present:

MechanismWhen to useExample parameter
limit / max_results / per_pagePrimary list endpoints (REST)limit=20
page + per_pageOffset paginationpage=1, per_page=10
cursor / page_tokenToken-based continuation (REST)cursor="<token>"
first + afterGraphQL Relay cursor paginationfirst=20, after="<endCursor>"
SQL LIMIT clauseAny tool that executes raw SQLSELECT ... LIMIT 50
Date/time filterWhen no explicit limit param existssince="2024-06-01T00:00:00Z"

Step 3 — Set safe starting limits.

Use these defaults unless the tool's documentation specifies lower maximums:

Operation typeSafe starting limitRationale
Code search5-10Results are large; 10 is usually enough to find the target
Issue / PR search10-20Each item has metadata; 20 fits comfortably in context
Channel / message list50-100Lightweight items; higher limit reduces round-trips
SQL queries50-100Depends on row width — prefer lower for wide schemas
GraphQL list20Use first=20; avoid last unless reverse pagination needed
Generic list20Safe default when no guidance exists

Step 4 — Add alternative filters when no limit param exists.

If a tool has no pagination parameter, narrow scope with filters before fetching:

# Date filtering — prefer ISO 8601 with timezone
since="2024-06-01T00:00:00Z"
before="2024-07-01T00:00:00Z"

# State filtering — exclude irrelevant items
state="open"       # or "closed", "merged"
status="active"    # or "inactive", "archived"

# Owner/author filtering
author="username"
assignee="username"

# Path/extension filtering (code search)
path="src/api"
extension="ts"

Step 5 — Enforce incremental fetching.

The server design must not auto-paginate through all results. The correct pattern:

1. Fetch first page with safe limit
2. Return results to caller
3. Only fetch next page if caller explicitly requests more

Do NOT pre-fetch all pages and merge results — this defeats the guardrail entirely.

Hard Rules

  1. Never generate or approve a list/search MCP tool that has no limiting strategy — every such tool must expose at least one of: limit, max_results, per_page, cursor, first, or a date filter parameter.
  2. Never set a default limit above 100 — even if the tool supports higher values; the caller can increase it explicitly.
  3. Never auto-paginate — fetching page 2+ without an explicit caller request is forbidden; it silently multiplies token consumption.
  4. Always start at the low end of the safe range — prefer 10 over 50 when context size is unknown.
  5. SQL-executing tools must reject queries without a LIMIT clause — validate the SQL string server-side before executing.
  6. Do not exempt a tool from guardrails based on name prefix alone — a get_* tool that returns an array needs limits just like list_*.
  7. Do not apply guardrails to streaming/generative tools — LLM completions, SSE, and WebSocket tools are not collection-listing operations.
  8. Do not hardcode absolute paths or employer-specific tool names in server designs — keep examples generic (owner="my-org", not a real org name).

Anti-patterns

Missing limit entirely:

# BAD — no limit; can return thousands of items
list_issues(repo="my-repo", state="open")

# GOOD
list_issues(repo="my-repo", state="open", limit=20)

Auto-paginating all results:

# BAD — fetches every page and returns merged array
results = []
page = 1
while True:
    batch = list_issues(repo="my-repo", page=page, per_page=100)
    if not batch: break
    results.extend(batch)
    page += 1
return results

# GOOD — return page 1 and expose a cursor for the caller to continue
return list_issues(repo="my-repo", page=1, per_page=20, cursor=None)

Unbounded SQL:

-- BAD
SELECT * FROM events WHERE user_id = $1

-- GOOD
SELECT * FROM events WHERE user_id = $1 ORDER BY created_at DESC LIMIT 50

Overly broad search without filters:

# BAD — searches entire GitHub with no scope
search_code(query="auth")

# GOOD
search_code(query="auth", repo="my-org/my-repo", path="src/auth", limit=10)

GraphQL auto-cursor-following:

# BAD — follows all cursors before returning
cursor = None
all_items = []
while True:
    page = client.issues(first=100, after=cursor)
    all_items.extend(page.nodes)
    if not page.pageInfo.hasNextPage:
        break
    cursor = page.pageInfo.endCursor
return all_items

# GOOD — return first page with cursor for caller to continue
page = client.issues(first=20, after=after_cursor)
return {"items": page.nodes, "endCursor": page.pageInfo.endCursor, "hasNextPage": page.pageInfo.hasNextPage}

Quick-reference checklist

Before approving any MCP server design that includes list or search tools, verify:

  • Every list_* tool has limit or per_page (REST) or first (GraphQL) with a documented default <= 100
  • Every search_* tool has limit or max_results with a documented default <= 20
  • GraphQL list tools expose first + after and return pageInfo.endCursor + pageInfo.hasNextPage
  • SQL-executing tools validate for a LIMIT clause before running
  • No tool auto-paginates; pagination is always caller-driven
  • Streaming/generative tools (LLM completions, SSE, WebSocket) are correctly exempted
  • get_* tools that return arrays are treated as list operations (not exempted by name prefix)
  • Date/state/author filters are available as fallback when no limit param exists
  • Default limits are at the conservative end of the safe range for the operation type

When invoked from mcp-builder Phase 4.1, report pass/fail per item. Return control to mcp-builder only after all items pass or you list concrete fixes for each failure.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.