KEY TAKEAWAYS

  • Follow every valid nextCursor unchanged, including an empty string. A small page or resultType: complete does not establish that enumeration has ended.[1][5]
  • A completed traversal describes one caller scope over an observation window. MCP supplies no cross-page consistency guarantee, so it does not prove a single-instant snapshot.[2][3]
  • Check freshness per page and invalidate on a relevant received notification. A failed refresh leaves the current inventory unresolved; it does not establish zero tools.[3]

A first page cannot settle what is missing

Before rejecting an integration because a needed tool is missing, establish whether its tool list was fully traversed. Model Context Protocol (MCP) supports pagination for tools/list. The server determines page size, and clients MUST NOT assume a fixed size.[1] Two returned tools might be the entire catalog or just the first page.

The decisive field is nextCursor. The captured pagination guidance says clients SHOULD treat a missing nextCursor as the end of results. Clients MUST treat cursors as opaque and MUST NOT treat an empty string as the end.[1] Do not decode, trim or otherwise modify the returned string. A check that stops on a falsy value would lose a valid empty-string continuation.

A response with resultType: complete may still carry nextCursor: the schema combines the tool array, pagination and caching fields in one result.[5] That label identifies a completed response, not an exhausted catalog. The useful decision is whether enumeration is sufficiently complete, scoped and fresh for your comparison.

Define which inventory you are comparing

The Tools contract allows the set to be empty, to change over time and to vary with authorization presented on each request. It forbids variation merely by connection or as a side effect of other requests on the connection.[2] A list collected with one caller's access therefore cannot establish what another caller can discover.

Before collection, state the intended decision: finding a named tool, comparing configurations or refreshing a catalog. Record the endpoint/configuration, client build, transport, actual client/server protocol contract, a nonsecret reference to the authorization context and the observation window. These are our recordkeeping choices, not new MCP wire fields. Establish the actual edition before applying this guide's 2026-07-28 refresh rules.

Keep server-listed definitions separate from tools the client accepts and tools exposed to the model. For example, Streamable HTTP clients MUST exclude definitions with invalid x-mcp-header values; other transports MAY ignore those annotations.[2] A client rejection is a filtering result, not a missing pagination page. Preserve its reason when available. For multiple servers, retain a reliable server identity with each tool name: names can collide, and serverInfo.name is not guaranteed unique.[2]

Collect the pages, then reconcile the result

Use this procedure with your existing authorized client. It is documentary guidance, not a tested adapter or a reason to invoke discovered tools. The proposed completion rule deliberately requires a valid terminal response and an intact chain of pages.

  • 1. Start tools/list without a cursor. Keep the agreed endpoint, configuration, protocol and authorization context throughout the traversal. Identify whether each page came from a fresh fetch or a particular cached response.
  • 2. Record each valid page's receipt time, listed definitions, cache hints and continuation state in appropriate private evidence. Keep credentials and actual opaque cursor values out of shared reports; a private evidence reference can identify the page chain.
  • 3. If nextCursor contains a valid string, send it back unchanged, even when it is empty. Continue even if the tools array is short or empty. Stop successfully when a valid page omits nextCursor, following the documented end guidance.[1][5]
  • 4. If a request fails, a page is malformed, the scope changes or a required continuation is not collected, classify the affected traversal as incomplete or unresolved. The captured Cursor type is string, not null; our policy does not count a null or malformed value as a successful terminal response.[5] Use existing bounded timeout/retry limits rather than an endless loop.
  • 5. Reconcile all pages and client exclusions before comparing coverage. Retain duplicate observations and their page provenance before deduplicating names. Duplicates can indicate list changes; removing them does not recover tools lost in a gap. An invalid cursor calls for discarding cached pages and starting again without a cursor.[3]

Preserve the terminal response and the chain that led to it, not just a total. If the valid traversal returns no definitions, it supports an empty list for that scope and observation window. A network, authorization, schema or cursor error does not. Invalid cursors SHOULD produce -32602 (Invalid params); that is an error, not an empty tools array.[1][2]

Completion is not an atomic snapshot

The server SHOULD provide stable cursors and deterministic tool ordering.[1][2] Those recommendations help traversal and caching; they do not freeze the list. The Caching contract explicitly gives no cross-page consistency guarantee and says changes between fetches may produce duplicates or gaps.[3] A clean-looking list can therefore still lack snapshot evidence.

For an exploratory configuration comparison, a recorded complete traversal may be sufficient if you accept the scope, observation window and freshness limits. Compare equivalent caller scopes and the same counting layer. Report a needed tool as listed when it appears; report an unlisted tool as not observed in that traversal, rather than unavailable to every user.

If the decision requires proof that a tool was absent at one instant, seek a separate implementation-specific snapshot or revision contract. MCP recommends fetching again from the beginning when a consistent full list is needed, but that restart does not create an atomicity guarantee.[3] Leave the stronger absence claim unresolved without the stronger evidence. A complete ordinary tools/list inventory also does not certify every nested function or grant permission to call a listed tool.

Refresh pages without confusing freshness with stability

Each page is independently cacheable. Its freshness clock starts at its own receipt time, and pages can have different ttlMs values. All pages of a given list request MUST share cacheScope.[3] A recent final page does not reset an older first page's clock. Cache identity includes the method and result-affecting parameters, including cursor; one page cannot stand in for another.[3]

ttlMs is a freshness hint, not a promise that data remains unchanged. Expired pages SHOULD be re-fetched on next access; TTL SHOULD NOT become an automatic background-polling interval.[3] Private cache entries cannot cross authorization contexts. Public entries can be shared when they contain no user-specific data, including at authenticated endpoints; cacheScope is not access control.[3]

A relevant received notification invalidates a cached response even if its TTL has not expired.[3] In this edition, tool-list notifications use a declared listChanged capability and an opened subscriptions/listen stream requesting toolsListChanged: true; sending those notifications is SHOULD guidance.[2] Inspect the initial acknowledgment: it reports the subset the server accepted and can omit unsupported notification types.[4] A capability flag or requested filter alone is not proof of an active accepted subscription.

  • On a relevant tools-list change notification, mark the cached catalog stale. Our coverage policy is to collect a new full traversal before the next current comparison; the protocol also permits refreshing individual stale pages.[3]
  • On subscription closure, stop treating the stream as continuous change evidence. Transport closure ends the subscription; stdio reconnection MUST re-send subscriptions/listen.[4] This guide establishes no replay assurance. Notification silence is not proof of an unchanged catalog.
  • On an authorization, configuration or protocol change, collect evidence for the new scope before comparing it with the old one. If a cursor becomes invalid, discard cached pages and restart.[3] Keep operational retries bounded.
  • If refresh fails, retain an older valid catalog separately as stale evidence. The contract permits serving stale responses during refresh errors, but our policy does not relabel them as freshly verified current coverage.[3] Record the failed refresh and the condition for trying again.

Completed hypothetical: the missing tool was on the next page

This completed documentary example is fictional and was not executed. Example Catalog and Example Client are fictional. Assume the 2026-07-28 contract and one unchanged finance-reader authorization context. The page descriptions below are assumptions, not captured server responses; no real endpoint, credential, client or tool was used.

  • First page: lookup_invoice and list_customers are listed; nextCursor is present as an empty string. The initial conclusion, export_report is absent, is unsupported because continuation remains. The empty string is valid under the documented rule.[1]
  • Continuation: Example Client sends the empty string unchanged. The assumed response lists export_report and omits nextCursor. The fictional record now contains three entries and three unique tool names across two pages, with the terminal response recorded.
  • Corrected decision: export_report is listed for the assumed caller scope, and enumeration reached the documented terminal condition in this fictional traversal. No permission to invoke it and no atomic-snapshot guarantee follows.
  • Later refresh: assume listChanged was declared, toolsListChanged was requested and acknowledged, and a relevant notification arrives while TTL remains. The completed decision is to mark the cached catalog stale and collect a new traversal before another current coverage assessment.[2][3][4]

If the continuation instead returned a cursor error, the decision would be inventory incomplete; discard cached pages and restart. It would not be two tools total or export_report absent.[1][3] That countercase is a hypothetical disposition, not a measured failure or recovery.

Source dates and implementation limits

This guide uses official pagination, tools, caching, subscriptions and TypeScript schema bytes captured on 7 October 2026 KST.[1][2][3][4][5] These sources belong to one MCP publisher family: complementary contract evidence, not independent empirical confirmation. Document publication/update dates were not established. The 2026-07-28 edition label and retrieval date are not launch or rollout dates. The schema was captured from mutable main; its preserved bytes, rather than an immutable commit or original July publication, define the evidence used here.

The pagination and tools examples omit _meta for brevity and group clientInfo with required metadata.[1][2] The captured schema requires _meta with io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities, while io.modelcontextprotocol/clientInfo is optional with SHOULD inclusion unless configured otherwise.[5] Keep that prose/schema tension visible. This guide supplies no abbreviated copy-and-run wire JSON.

No implementation experiment was performed. Deployed client/server support, actual pagination and filtering behavior, subscription delivery and snapshot support remain unverified. The proposed procedure lets an operator record what a traversal supports and when to refresh it; it does not certify an integration's coverage or controls.

Sources & scope

Documentary guide checked 7 October 2026 KST against the observed MCP 2026-07-28 pagination, tools, caching, subscriptions and schema. The procedure is our proposed operator policy, not additional protocol requirements. The completed example is fictional and unexecuted; no real server, client or tool was tested. Prepared edition time is not production activation.

  1. MCP 2026-07-28: Pagination ↗

    Official document captured 7 October 2026 KST; publication/update date unknown. Server-determined page size, opaque cursors, empty-string continuation, missing-nextCursor end guidance and invalid-cursor errors. Contract evidence, not a tested client.

  2. MCP 2026-07-28: Tools ↗

    Official document captured 7 October 2026 KST; publication/update date unknown. Authorization-scoped listing, ordering guidance, list-change subscription path, name collisions and HTTP definition exclusions. No deployed support established.

  3. MCP 2026-07-28: Caching ↗

    Official document captured 7 October 2026 KST; publication/update date unknown. Cache keys, per-page freshness, public/private sharing, invalidation and lack of cross-page consistency. Full restart is guidance, not an atomic snapshot warranty.

  4. MCP 2026-07-28: Subscriptions ↗

    Official document captured 7 October 2026 KST; publication/update date unknown. Requested filters, initial acknowledged subset, closure and stdio re-subscription. No notification replay or delivery outcome verified.

  5. MCP 2026-07-28: TypeScript schema, captured revision ↗

    Official raw schema captured 7 October 2026 KST; publication/update date unknown. Cursor/string and optional pagination fields, ListToolsResult and request metadata. Mutable main capture, not an immutable-commit or original-July-byte claim; SHA256 742750af0bb8c716e7030c4977c992b55d1adc4407e9e66997db5846baedc2cd.

Publication history
  • — Initial prepared documentary guide with scoped enumeration, refresh decisions and a completed fictional example. Production activation requires separate evidence.

Have a correction or a different perspective? Contact Palanthos.