
This page is part of our MCP specification reference, a plain-English guide to the Model Context Protocol spec (version 2026-07-28), within The MCP Guide. Building a server? See MCP development.
Status in the 2026-07-28 spec: core (server utility)
Pagination in MCP is how a server splits a long list, such as hundreds of tools or thousands of resources, into smaller pages. The server returns one page plus a nextCursor token. The client sends that token back to get the next page, and stops when no cursor comes back.
MCP uses cursors, not page numbers. The pagination page of the 2026-07-28 spec calls it "an opaque cursor-based approach." This page explains how it works, which methods use it, and the small rules that trip clients up.
Key Takeaways
- MCP list methods return results in pages, with an optional
nextCursorwhen more exist. - The cursor is an opaque string. Clients must not parse, change or guess at it.
- The server decides page size, and clients must not assume a fixed size.
- A missing
nextCursormeans the end of results. An empty string is still a valid cursor. - In 2026-07-28, list results also carry
resultType,ttlMsandcacheScope.
Why pagination exists
Some servers expose a lot. A document server might list thousands of files as resources. A large platform might offer hundreds of tools. Sending everything in one response is slow and memory-hungry, especially over the internet.
The spec says pagination "is especially important when connecting to external services over the internet, but also useful for local integrations to avoid performance issues with large data sets."
How it works
Which methods paginate
The 2026-07-28 spec lists four core operations:
| Method | What it lists |
|---|---|
tools/list | Available tools |
resources/list | Available resources |
resources/templates/list | Resource templates |
prompts/list | Available prompts |
Extensions reuse the same pattern. The Skills extension says skills/list "supports pagination," for example.
The flow
- The client sends a list request with no cursor.
- The server returns the first page. If more results exist, it adds
nextCursor. - The client sends the same list request with
"cursor"set to that value. - Repeat until a response has no
nextCursor.
Here is a page of results, from the spec:
{
"jsonrpc": "2.0",
"id": "123",
"result": {
"resultType": "complete",
"resources": [],
"nextCursor": "eyJwYWdlIjogM30=",
"ttlMs": 300000,
"cacheScope": "public"
}
}
(We emptied the resources array for brevity. The spec shows it as [...].)
The client then asks for the next page:
{
"jsonrpc": "2.0",
"id": "124",
"method": "resources/list",
"params": { "cursor": "eyJwYWdlIjogMn0=" }
}
In real 2026-07-28 traffic, each request also carries required _meta fields such as the protocol version. The spec's examples omit them for brevity.
The rules for each side
The spec's implementation guidelines are short:
- Servers should provide stable cursors and handle invalid cursors gracefully.
- Clients should treat a missing
nextCursoras the end and support both paginated and non-paginated servers. - Clients must treat cursors as opaque: no assumptions about format, no parsing, no edits.
An invalid cursor should return JSON-RPC error -32602 (Invalid params).
What changed across spec versions
Pagination has been in MCP since the first spec, 2024-11-05. The model itself has stayed the same. Two things changed in 2026-07-28, compared with 2025-11-25:
| Change | What it means |
|---|---|
| New fields on list results | Results now include resultType and, per the changelog, required ttlMs and cacheScope caching hints |
| Rule on cursor values | Old text said "don't persist cursors across sessions." New text says clients must not judge a cursor by its value, and "an empty string is a valid cursor" |
The old line about sessions disappeared because sessions were removed. See why MCP became stateless.
The changelog also asks servers to return tools/list in a deterministic order. That helps client caching and model prompt caching, and it makes pages more predictable.
Common mistakes
- Treating an empty string as "done". The spec says an empty string "MUST NOT be treated as the end of results." Only a missing (or null)
nextCursorends the list. - Decoding the cursor. The example cursor looks like base64 JSON. That is an implementation detail. Clients must not parse or build cursors.
- Assuming a page size. The server sets it, and it can change.
- Only reading the first page. A client that ignores
nextCursorsilently misses tools. Users then wonder why a server "has no tool for that." - Unstable server cursors. If your cursor depends on an order that shifts between calls, clients may see duplicates or gaps.
- Ignoring caching hints. With
ttlMs, clients can reuse a list instead of paging through it again on every request.
Who needs to care
If you are evaluating an MCP client for a large server, check that it pages through full lists. If you build servers, paginate long lists and keep the order stable. Both points belong in a technical review, alongside the items in how to choose MCP servers.
Next step
Pagination is one of several small utilities in the spec. Next, see how long operations report status in MCP progress notifications, or return to the MCP specification reference.
Frequently asked questions
Does MCP use page numbers?
No. MCP uses opaque cursor strings. The server returns nextCursor when more results exist, and the client passes it back as cursor to get the next page.
Who decides the page size in MCP?
The server. The spec says clients must not assume a fixed page size, and a server can return different page sizes at different times.
Which MCP methods support pagination?
In the 2026-07-28 core spec: tools/list, resources/list, resources/templates/list and prompts/list. Some extensions, such as Skills over MCP, also paginate their list methods.
What should a client do with an invalid cursor error?
The server should return error -32602 (Invalid params). A sensible client restarts the listing from the beginning without a cursor.
Is an empty nextCursor the end of the list?
No. An empty string is a valid cursor and must not be treated as the end. Only a missing nextCursor means there are no more results.











