{"record":{"id":"8ee3a184b5c89aca","repo":"different-ai/openwork","slug":"pagination-unsupported","errorCode":"pagination_unsupported","errorMessage":"pagination_unsupported","messagePattern":"pagination_unsupported","errorType":"error_code","errorClass":"SafeProbeFailure","httpStatus":null,"severity":"error","filePath":"apps/server/src/agent-context-cloud-probe.ts","lineNumber":547,"sourceCode":"    throw new SafeProbeFailure(\"invalid_jsonrpc_envelope\");\n  }\n  if (Object.hasOwn(payload, \"error\")) throw new SafeProbeFailure(\"jsonrpc_error\");\n  if (payload.id !== requestId) throw new SafeProbeFailure(\"request_id_mismatch\");\n  if (!isRecord(payload.result)) throw new SafeProbeFailure(\"invalid_jsonrpc_envelope\");\n  return payload.result;\n}\n\nfunction requireSupportedProtocolVersion(initializeResult: Record<string, unknown>): void {\n  const version = initializeResult.protocolVersion;\n  if (typeof version !== \"string\" || version.length === 0 || version.length > MAX_PROTOCOL_HEADER_LENGTH) {\n    throw new SafeProbeFailure(\"invalid_jsonrpc_envelope\");\n  }\n  if (version !== MCP_PROTOCOL_VERSION) throw new SafeProbeFailure(\"unsupported_protocol_version\");\n}\n\nfunction validateCatalog(rpcResult: Record<string, unknown>): { toolIds: string[]; totalToolCount: number } {\n  if (rpcResult.nextCursor !== undefined && rpcResult.nextCursor !== null) {\n    throw new SafeProbeFailure(\"pagination_unsupported\");\n  }\n  if (!Array.isArray(rpcResult.tools) || rpcResult.tools.length > MAX_TOOL_COUNT) {\n    throw new SafeProbeFailure(\"invalid_catalog\");\n  }\n  const seen = new Set<string>();\n  for (const tool of rpcResult.tools) {\n    if (!isRecord(tool) || typeof tool.name !== \"string\" || tool.name.length > MAX_TOOL_ID_LENGTH || !TOOL_ID.test(tool.name)) {\n      throw new SafeProbeFailure(\"invalid_catalog\");\n    }\n    if (seen.has(tool.name)) throw new SafeProbeFailure(\"invalid_catalog\");\n    seen.add(tool.name);\n  }\n  // Additional provider tools are forward-compatible and allowed, but never\n  // reflect provider-controlled catalog names into the diagnostic report. In\n  // particular, a compromised trusted endpoint must not be able to echo the\n  // bearer token back as a syntactically valid tool identifier. Only the\n  // expected allowlisted IDs and the aggregate count are exported.\n  const missing = REQUIRED_TOOL_IDS.filter((toolId) => !seen.has(toolId));","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/agent-context-cloud-probe.ts#L529-L565","documentation":"validateCatalog throws SafeProbeFailure(\"pagination_unsupported\") when the tools/list result contains a non-null nextCursor, meaning the server paginates its tool catalog. The probe fetches only one page and cannot enumerate all tools, so it refuses rather than under-reporting the catalog.","triggerScenarios":"Server's tools/list response includes nextCursor (string cursor) because its tool count exceeds one page or it paginates unconditionally.","commonSituations":"Large MCP servers exposing hundreds of tools that paginate by default; server implementations that always set nextCursor even for full pages; recent server upgrade introducing pagination where none existed before.","solutions":["Configure the server to return its whole catalog in one page (raise/infinite page size)","Follow the cursor by issuing tools/list calls with the cursor param until nextCursor is null, then relax or extend the probe","Check server settings/policy for tool pagination limits","If pagination is intended, the probe itself needs a cursor-following loop added"],"exampleFix":"// before (server)\n{\"tools\":[...],\"nextCursor\":\"page-2\"}\n// after\n{\"tools\":[...all tools...]}","handlingStrategy":"try-catch","validationCode":"const body = JSON.parse(raw);\nconst cursor = (body?.result as Record<string, unknown> | undefined)?.nextCursor;\nif (cursor !== undefined && cursor !== null) {\n  throw new Error(`server paginates tools/list (nextCursor=${String(cursor)}); single-page probe not supported`);\n}","typeGuard":"function isUnpaginatedToolsResult(result: Record<string, unknown>): boolean {\n  return result.nextCursor === undefined || result.nextCursor === null;\n}","tryCatchPattern":"try {\n  const { toolIds, totalToolCount } = validateCatalog(rpcResult);\n} catch (e) {\n  if (e instanceof SafeProbeFailure && e.code === \"pagination_unsupported\") {\n    // either reconfigure the server to a single page or implement cursor-following tools/list paging\n  } else throw e;\n}","preventionTips":["Configure servers with large catalogs to disable tool pagination or raise page size above tool count","Probe server behavior once at onboarding and record whether it paginates","If pagination is expected, implement cursor-following before relying on single-shot probes"],"tags":["mcp","pagination","tools-list"],"backgroundTag":"unexpected-pagination-cursor","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}