different-ai/openwork · error · ExternalMcpDiagnosticError

MCP_CATALOG_PAGE_LIMIT

MCP_CATALOG_PAGE_LIMIT

Error message

MCP_CATALOG_PAGE_LIMIT

What it means

Thrown after the loop when the provider requires more than pageLimit (default EXTERNAL_MCP_TOOL_PAGE_LIMIT = 20) tools/list pages to return its full catalog. This is a hard cap on pagination round-trips, distinct from the tool-item and byte limits.

Source

Thrown at ee/apps/den-api/src/capability-sources/external-mcp-client.ts:744

        tracker: input.diagnostic,
        code: "MCP_CATALOG_BYTE_LIMIT",
        operatorAction: `Reduce the complete serialized tool catalog below ${EXTERNAL_MCP_CATALOG_LIMIT_BYTES} bytes.`,
      })
    }
    catalogBytes += cursorMeasurement.bytes
    if (seenCursors.has(result.nextCursor)) {
      throw catalogDiagnosticError({
        tracker: input.diagnostic,
        code: "MCP_CATALOG_CURSOR_LOOP",
        operatorAction: "Fix the provider's tools/list pagination so each nextCursor advances.",
      })
    }
    seenCursors.add(result.nextCursor)
    cursor = result.nextCursor
  }
  throw catalogDiagnosticError({
    tracker: input.diagnostic,
    code: "MCP_CATALOG_PAGE_LIMIT",
    operatorAction: `Reduce the provider catalog to at most ${pageLimit} pages or use a scoped MCP server.`,
  })
}

export type ExternalMcpConnectResult =
  | { status: "connected" }
  | { status: "needs_auth"; authorizeUrl: string }

/**
 * Attempts to connect. For authType "none"/"apikey" this either succeeds or
 * throws. For "oauth", if there's no valid token yet, the SDK's transport
 * drives discovery (+ dynamic client registration if needed) and returns the
 * authorize URL to send the admin's browser to — no token exchange happens
 * yet, that's connect/callback's job. `signedState` (our own signed token
 * identifying which connection this is for) is passed through as the
 * standard OAuth `state` param, since that's the only param guaranteed to
 * round-trip back to connect/callback on any spec-compliant server.
 */

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Reduce the provider catalog to at most 20 pages worth of tools
  2. Use a scoped MCP server exposing only the needed tools
  3. Increase the server's page size so the catalog fits in fewer pages
  4. Split the provider into multiple smaller servers

Example fix

// before: server pageSize=10 with 500 tools -> 50 pages
// after: server pageSize=100 -> 5 pages (under the 20-page limit)
Defensive patterns

Strategy: validation

Validate before calling

const pages = Math.ceil(totalTools / pageSize)
if (pages > 20) throw new Error(`${pages} pages exceeds the 20-page catalog limit`)

Try / catch

try {
  await connectExternalMcp(...)
} catch (err) {
  if (err instanceof Error && err.message.includes("MCP_CATALOG_PAGE_LIMIT")) {
    console.error("Provider needs >20 tools/list pages; increase page size or reduce catalog")
  } else throw err
}

Prevention

When it happens

Trigger: The while (cursor !== undefined) loop in collectExternalMcpToolPages exits without the diagnostic 'catalog_ready' pass because the iteration count reached pageLimit pages and nextCursor is still defined.

Common situations: Providers with tiny page sizes (e.g. 10 tools/page) and large catalogs (thousands of tools); servers that ignore the client's requested page size; very broad aggregator servers.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/cc5d8580b6d9b1f9. Report an issue: GitHub.