Key takeaways

  • Pagination and schema validation interact. In SDK 1.30.0, each listTools response replaced the metadata cache rather than preserving validators from earlier pages.
  • After two pages, getToolOutputValidator returned undefined for page_one_score and a validator for page_two_score, although the client had successfully discovered both definitions.
  • The first-page tool then returned {value:"not-an-integer"} successfully. The same invalid shape from the second-page tool raised MCP InvalidParams.
  • The fixture is deliberately nonconforming and uses the low-level Server API. This is a receiving-client cache result, not evidence that normal high-level MCP servers emit malformed output.
  • Aggregate every page into an immutable inventory, compile validators from the aggregate, and prevent agent calls until the complete registry is installed atomically.
01

The sharp question: does a fully paginated AI tool inventory stay fully validated?

A production MCP server can expose more tools than fit in one response. The protocol therefore gives tools/list the same opaque-cursor pagination model used by resources and prompts. An agent host is expected to follow nextCursor until the server omits it, then plan against the discovered inventory. But discovery serves a second function in the TypeScript client: it installs tool-specific output validators.

My local two-page probe found those concerns do not compose automatically in SDK 1.30.0. The first tools/list response installed the first tool’s validator. Fetching the second page cleared it and installed only the second tool’s validator. After traversal was complete, an invalid integer field from the first-page tool passed through, while the same invalid field from the second-page tool raised InvalidParams. The client knew both tool definitions at application level; its internal validator cache remembered only the last response page.

02

Chronology: portable discovery grew into a stateful validation boundary

Anthropic introduced MCP on November 25, 2024 as an open standard for connecting AI assistants to repositories, business tools and data sources. Discovery made tool inventories portable: clients could learn names, descriptions and schemas instead of hard-coding every integration.

The July 28, 2026 protocol defines cursor pagination for tools/list and a structured-output contract in which successful structuredContent must match a declared outputSchema. TypeScript SDK 1.30.0 was released July 27 on the maintained v1.x line. These features meet inside the client cache: pagination determines how definitions arrive, while discovery determines which output validators exist when an agent later invokes a tool.

03

The protocol defines pages, not an application-wide cache algorithm

The pagination specification says a response contains the current results and optionally nextCursor. A client continues by sending that opaque cursor and treats a missing nextCursor as completion. Page size belongs to the server; the client must not infer a fixed size. tools/list is explicitly among the operations that support this flow.

Those rules establish transport behavior. They do not say that one response page is the complete inventory, nor prescribe how an SDK should combine pages into a validator registry. That implementation boundary belongs to the client. A correct loop can retrieve every page yet still leave secondary state incomplete if cache updates are performed page by page.

04

The pinned client clears before it compiles

In the distributed SDK 1.30.0 client source, listTools sends one tools/list request, parses one ListToolsResult and passes result.tools to cacheToolMetadata. The cache method begins by clearing cached output validators and task-support sets. It then compiles metadata only for the tools in that response.

That behavior is coherent for a non-paginated refresh, where one response represents the complete list. With manual pagination, each listTools call is also a refresh from the cache method’s perspective. Page two therefore replaces page one. The source observation predicted a testable asymmetry: after the last page, last-page validators should exist and earlier-page validators should not.

05

The fixture returned two legitimate pages and two illegitimate results

The checked-in audit creates a low-level SDK Server with page_one_score and page_two_score. The first tools/list response contains only page_one_score plus nextCursor:"page-2". A request carrying that cursor receives only page_two_score and no nextCursor. Each definition has the same output schema: an object with one required integer property named value and no extra fields.

Both call handlers deliberately violate that contract by returning structuredContent {value:"not-an-integer"}. This isolates validator state from payload differences. The server is intentionally nonconforming; the point is to observe whether the receiving client applies each discovered contract, not to model expected output from the high-level McpServer API.

06

Page one installed one validator

The client connected through the SDK’s linked InMemoryTransport and called listTools without a cursor. Assertions confirmed that the response contained only page_one_score and nextCursor was exactly "page-2". getToolOutputValidator returned a validator for page_one_score and undefined for page_two_score.

This control proves that the schema compiled and the first cache state behaved as expected. A missing validator at this point would have implicated schema support or fixture construction instead of pagination. The next request changed only the cursor and returned the second definition.

07

Page two completed traversal and displaced page one

The client called listTools({cursor:"page-2"}). The response contained page_two_score and omitted nextCursor, so protocol traversal was complete. Immediately afterward, getToolOutputValidator returned undefined for page_one_score and a validator for page_two_score.

No malformed page, duplicate name, repeated cursor or schema compilation failure was involved. The test retrieved exactly the two advertised pages in order. The disappearing validator followed the source path: the second cacheToolMetadata invocation cleared the map before adding the second page.

08

The first-page invalid result passed through

After complete traversal, the client called page_one_score. The low-level server returned {value:"not-an-integer"}. Client.callTool returned that object successfully to the audit because getToolOutputValidator("page_one_score") no longer found a validator. The generic MCP result shape accepts structuredContent as an object; it does not know this tool’s integer rule.

This is the material AI infrastructure consequence. Downstream routing, memory, planning or application code can receive a shape that contradicts a schema the host did discover earlier in the same session. The failure is not that pagination hid the tool. It is that the tool remained callable after its validation contract had been evicted.

09

The last-page invalid result failed closed

The audit then called page_two_score. Its handler returned the identical invalid shape. This time Client.callTool raised MCP error -32602, InvalidParams: “Structured content does not match the tool’s output schema: data/value must be integer.” The two server handlers both ran, and the only relevant client-side difference was which validator remained cached.

That A/B result is stronger than observing the cache map alone. It ties internal metadata state to externally visible call behavior. It also preserves the timing boundary: output validation occurs after the remote handler has executed, so rejection protects downstream consumption rather than preventing the tool’s own effects.

10

This differs from the public repeated-cursor report

TypeScript SDK issue 2735, opened August 28, 2026, reports that a v2.0.0 automatic pagination path can stop when a server repeats an opaque cursor and then return an apparently complete aggregate. That report concerns page traversal and v2 behavior. It is public momentum around the fragility of MCP pagination, but it does not report, reproduce or independently validate this v1 output-validator cache result.

The local fixture uses a conventional changing cursor and reaches the final page. There is no truncation. Treating the two observations as one bug would obscure the engineering work: one control must prove all pages were retrieved; another must prove every resulting tool contract is present in the installed registry.

11

High-level server validation narrows—but does not erase—the client concern

SDK 1.30.0’s high-level McpServer validates successful structured output against a registered output schema before returning it. The audit uses the low-level Server API specifically so it can create a nonconforming peer. Teams running the high-level server should keep that guard and negative-test it.

A client may still connect to custom implementations, other languages, older releases or buggy deployments. Defense in depth matters because server and client have different trust owners. The observed behavior should not be described as evidence that conforming MCP servers commonly return bad data, a prevalence estimate or a demonstrated exploit against a production agent.

12

Aggregate definitions before mutating trusted state

Build pagination as a transaction. Fetch pages into a temporary collection, bound page count and total tools, reject duplicate names, preserve raw page evidence, canonicalize schemas, and stop on invalid cursors, compilation errors or inconsistent server identity. Do not expose any newly discovered tool to a model while the walk is incomplete.

Only after the terminal page should the host compile every input and output validator from the aggregate and atomically replace the prior registry. Application code should resolve calls through that registry rather than relying on incidental SDK cache state. If the SDK offers no aggregate-install API, maintain the complete validated registry in a wrapper and perform explicit validation before and after each call.

13

Test the registry, not just the returned arrays

A pagination test that concatenates tool names can pass while validation state is wrong. For each page, include at least one schema-bearing tool and a deliberately invalid result fixture. After full traversal, assert that every tool has its expected schema digest and that every negative output is rejected. Repeat with one page, two pages, an empty middle page, maximum page size, duplicate names and a list-change refresh.

Also test schema removal and widening. An atomic refresh should either keep the prior approved registry or install the complete new registry; a timeout or compilation failure must not leave a partial mix. Preserve the server identity, cursor sequence, page count, tool count, schema digests, SDK version and validator decisions in diagnostic evidence without logging sensitive tool content by default.

14

Schema validity is still not semantic trust

Restoring validators solves a structural contract problem, not truth or authorization. An integer can satisfy its schema and still be fabricated. A URL can match a format and still target an unsafe destination. A schema-valid string can carry indirect instructions aimed at the next model. Object and tenant authorization must be computed from trusted identity and policy outside the tool response.

OWASP’s independent prompt-injection guidance treats tool outputs and observations as untrusted and recommends least privilege, tool validation, permission checks and session context. It does not test MCP pagination or this SDK result. It supports the broader control boundary: structural validation is necessary for typed agent pipelines but cannot carry the entire trust decision.

15

What failed, and what the probe does not establish

A first GitHub issue search used form parameters that produced an unexpected response shape, so I discarded that output and repeated the request with explicit query parameters. The corrected inventory surfaced issue 2735. The checked-in local probe itself passed all twelve assertions and removed its temporary dependency tree.

The probe did not test a language model, production host, v2 SDK, automatic aggregation, remote HTTP or stdio, authentication, concurrent calls, reconnects, list-change notifications, task execution, more than two pages, duplicate tools, hostile schema complexity, another language SDK, real side effects or user data. It does not establish prevalence, exploitability, protocol nonconformance by the SDK, or current behavior outside version 1.30.0.

16

Decision: gate autonomous calls on a complete atomic inventory

Deploy a paginated MCP inventory into an autonomous AI agent only when the host proves terminal-page traversal, bounded aggregation, unique tool identity, schema compilation for every page, atomic registry installation, negative output rejection for early and late pages, and independent authorization of tool effects. Keep server-side output validation enabled where available.

Constrain to a synthetic trial when the client’s cache lifecycle is unclear. Reject automatic calls when tools can remain callable outside the complete validated registry, or when a partial refresh silently replaces a known-good inventory. Roll back on missing early-page validators, duplicate identity, schema drift without review, invalid structured data reaching planning, or any assumption that output validation authorizes the upstream action.

17

Copy-ready MCP paginated-inventory gate

Complete this record for one server artifact and one full discovery transaction. A page is transport; the approved unit is the complete, atomically installed tool registry.

Entries stay in this browser tab and are not submitted to AccessAllGPT. Blank responses are copied as [Unresolved].

Operator, endpoint, transport, authentication, artifact digest, deployment identity and review expiry.

Cursor sequence, page and tool limits, terminal-page proof, duplicate handling, timeout behavior and raw-page evidence location.

Complete ordered names, unique identity rule, input/output schema digests, annotations and task-support metadata across every page.

Temporary collection, validation stages, commit point, failure rollback and proof no partial registry is callable.

SDK and JSON Schema validator versions, every tool validator present, early/late-page negative fixtures and exact rejection path.

How model-proposed names resolve only through the approved registry; pre-call arguments and post-call structured output checks.

Schema-valid hostile content handling, tenant/object authorization, credential scope, destinations, consequences and approvals.

List-change and reconnect transaction, schema diff, call suspension, prior-registry preservation and re-approval thresholds.

Server identity, discovery transaction, page count, schema digest, validator decision, handler execution and downstream suppression.

Truncation, missing validator, duplicate, partial refresh, invalid consumption or undeclared effect; kill switch and residue cleanup.

Primary sources

  1. Pagination (version 2026-07-28)Model Context Protocol Specification · Reviewed: Pagination model, response and request formats, supported operations, implementation guidelines and error handling · Retrieved · Supports: The current protocol uses opaque cursor pagination, lists tools/list as paginated, says clients should support paginated flows and defines a missing nextCursor as the end of results.
  2. Tools (version 2026-07-28)Model Context Protocol Specification · Reviewed: Listing tools, tool definition, output schema, structured content, calling tools and security considerations · Retrieved · Supports: The current tools contract makes list results paginated and defines optional outputSchema as the contract that successful structuredContent must match.
  3. @modelcontextprotocol/sdk 1.30.0 client implementationModel Context Protocol TypeScript SDK · Reviewed: Client.listTools, cacheToolMetadata, getToolOutputValidator and callTool output-validation implementation · Retrieved · Supports: The pinned v1 client calls cacheToolMetadata with each page returned by listTools; that method clears existing output validators before compiling validators from that response page.
  4. TypeScript SDK release 1.30.0Model Context Protocol on GitHub · Reviewed: Release identity, branch, publication date and package change record · Retrieved · Supports: The official release record binds the tested package to SDK version 1.30.0, released July 27, 2026 on the v1.x line.
  5. Client.listTools() silently drops pages when a server repeats a cursor (issue 2735)Model Context Protocol TypeScript SDK issue tracker · Reviewed: Issue report, v2.0.0 reproduction, observed truncation, protocol interpretation and open status · Retrieved · Supports: A separate public report documents a different pagination failure in the v2 client: repeated opaque cursors can make automatic aggregation stop early. It does not report or validate the v1 validator-cache replacement reproduced here.
  6. LLM Prompt Injection Prevention Cheat SheetOWASP Cheat Sheet Series · Reviewed: Agent-specific attacks, thought and observation injection, least privilege, tool validation and trust-boundary guidance · Retrieved · Supports: Independent defensive guidance treats tool output as untrusted content and recommends tool validation plus permission and session-context checks; it does not test MCP pagination or this SDK.
  7. Introducing the Model Context ProtocolAnthropic · Reviewed: November 25, 2024 announcement, protocol purpose, architecture, SDKs and ecosystem description · Retrieved · Supports: Anthropic introduced MCP as an open standard for connecting AI assistants to data sources and tools, establishing why a complete discovered inventory matters to agent clients.

Limitations

This is a bounded local reproduction on Node v24.10.0, Darwin arm64, @modelcontextprotocol/sdk 1.30.0 and Zod 3.25.76 using one deliberately nonconforming low-level in-memory server, two one-tool pages, two calls and one shared integer schema. It did not test a model, production MCP client, v2 SDK, automatic aggregation, remote or stdio transport, authentication, concurrency, reconnect, list-change races, task streaming, more pages, duplicate names, another SDK, hostile schemas, content injection, external effects or real data. It demonstrates that separate listTools calls for two pages replaced the tested v1 client’s validator cache and left only the final page validated; it does not measure prevalence, prove exploitability, allege a vulnerability or replace a security review. Issue 2735 concerns a different v2 repeated-cursor behavior, and OWASP guidance is adjacent defensive evidence rather than independent validation of this probe.

Disclosures

AccessAllGPT created and ran only the synthetic local fixture in the checked-in harness. No model, production client, third-party MCP server, credential, external endpoint or user data was used. The MCP project, Anthropic, OWASP and SDK maintainers did not review this article or provide access, private data, payment or endorsement. AccessAllGPT Research is operated by NeuralArc, is independent, and is not affiliated with OpenAI, Anthropic, the MCP project or OWASP. Publication-wide relationships are listed on the disclosures page.

Further AccessAllGPT guidance

  1. MCP Output Validation Depends on Tool Discovery
  2. MCP’s readOnlyHint Is Not a Permission Boundary
  3. MCP Token Passthrough Needs an Audience Boundary
  4. Before You Connect an MCP Server to Production
  5. Prompt Injection: Set the Deployment Gates Before Your LLM Can Act
  6. Design an Agent Benchmark That Predicts Production
  7. AccessAllGPT Research methodology
  8. Publication disclosures

Continue the research

Get evidence-led updates for teams making production AI decisions.