{"record":{"id":"9808da1ecac19230","repo":"Hmbown/CodeWhale","slug":"exceeded-the-page-catalogue-limit","errorCode":null,"errorMessage":"{} exceeded the {}-page catalogue limit","messagePattern":"(.+?) exceeded the (.+?)-page catalogue limit","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp.rs","lineNumber":1312,"sourceCode":"        Self {\n            method,\n            pages: 0,\n            items: 0,\n            bytes: 0,\n            seen_cursors: HashSet::new(),\n        }\n    }\n\n    fn observe_page(\n        &mut self,\n        result: &serde_json::Value,\n        item_count: usize,\n    ) -> Result<Option<String>> {\n        self.pages = self.pages.saturating_add(1);\n        self.items = self.items.saturating_add(item_count);\n        self.bytes = self.bytes.saturating_add(serde_json::to_vec(result)?.len());\n        if self.pages > MAX_MCP_CATALOG_PAGES {\n            anyhow::bail!(\n                \"{} exceeded the {}-page catalogue limit\",\n                self.method,\n                MAX_MCP_CATALOG_PAGES\n            );\n        }\n        if self.items > MAX_MCP_CATALOG_ITEMS {\n            anyhow::bail!(\n                \"{} exceeded the {}-item catalogue limit\",\n                self.method,\n                MAX_MCP_CATALOG_ITEMS\n            );\n        }\n        if self.bytes > MAX_MCP_CATALOG_BYTES {\n            anyhow::bail!(\n                \"{} exceeded the {}-byte aggregate catalogue limit\",\n                self.method,\n                MAX_MCP_CATALOG_BYTES\n            );","sourceCodeStart":1294,"sourceCodeEnd":1330,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/mcp.rs#L1294-L1330","documentation":"McpCatalogBudget caps paginated catalogue discovery per method: observe_page counts each response and bails once pages exceed MAX_MCP_CATALOG_PAGES = 64 (crates/tui/src/mcp.rs:1280, 1311-1317). The failing method name (tools/list, resources/list, prompts/list) is included. It is a resource-exhaustion guard: the connection aborts during discovery rather than walking an unbounded catalogue.","triggerScenarios":"A server paginates one catalogue method into more than 64 pages - e.g. thousands of tools at a small page size, or a server that returns tiny pages with an ever-advancing nextCursor.","commonSituations":"Mega-gateways exposing thousands of tools; servers configured with page size 1; pagination defaults too small for the catalogue.","solutions":["Increase the server's page size so the whole catalogue fits within 64 pages.","Reduce the exposed catalogue (disable unused tool groups server-side).","Split the gateway into several focused MCP servers, each under the limit.","Fix a server that emits near-empty pages while still returning a nextCursor."],"exampleFix":"# before (server): page size 1 with 100 tools -> 100 pages > 64\n# after (server): return up to 128 items per page -> 1 page, well under the limit","handlingStrategy":"validation","validationCode":"#!/usr/bin/env bash\n# Probe pages before wiring the server in; must stay <= 64 per method.\nurl=\"https://mcp.example.com/mcp\"; cursor=\"\"; pages=0\nwhile :; do\n  body=$(curl -s \"$url\" -H 'content-type: application/json' \\\n    -d \"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"id\\\":1,\\\"method\\\":\\\"tools/list\\\"${cursor:+,\\\"params\\\":{\\\"cursor\\\":\\\"$cursor\\\"}}}\")\n  pages=$((pages+1)); [ \"$pages\" -gt 64 ] && { echo \"would exceed 64 pages\"; exit 1; }\n  cursor=$(printf '%s' \"$body\" | jq -r '.result.nextCursor // empty');\n  [ -z \"$cursor\" ] && break\ndone; echo \"pages=$pages ok\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Size server pages so catalogues complete well under 64 pages.","Avoid page-size-1 pagination.","Split mega-gateways into focused MCP servers."],"tags":["mcp","pagination","limits","tools"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}