different-ai/openwork · error · ExternalMcpDiagnosticError

MCP_CATALOG_ITEM_LIMIT

MCP_CATALOG_ITEM_LIMIT

Error message

MCP_CATALOG_ITEM_LIMIT

What it means

Thrown by collectExternalMcpToolPages when a provider's tools/list returns more than itemLimit (default EXTERNAL_MCP_TOOL_ITEM_LIMIT = 2000) tools in total across all pages. The gateway refuses to ingest catalogs beyond this size to bound memory and agent context usage.

Source

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

  const itemLimit = input.itemLimit ?? EXTERNAL_MCP_TOOL_ITEM_LIMIT
  const deadline = input.deadline ?? createExternalMcpLifecycleDeadline()
  const tools: ExternalMcpToolPage["tools"] = []
  const seenCursors = new Set<string>()
  const seenToolNames = new Set<string>()
  let catalogBytes = 0
  let cursor: string | undefined
  for (let page = 0; page < pageLimit; page += 1) {
    input.diagnostic.begin("MCP_TOOL_DISCOVERY")
    const result = await runExternalMcpRequestWithinDeadline({
      deadline,
      diagnostic: input.diagnostic,
      phase: "MCP_TOOL_DISCOVERY",
      operation: (options) => input.listPage(cursor, options),
    })
    if (tools.length + result.tools.length > itemLimit) {
      throw catalogDiagnosticError({
        tracker: input.diagnostic,
        code: "MCP_CATALOG_ITEM_LIMIT",
        operatorAction: `Reduce the provider catalog below ${itemLimit} tools or use a scoped MCP server.`,
      })
    }
    for (const tool of result.tools) {
      catalogBytes += measureCatalogTool({
        diagnostic: input.diagnostic,
        tool,
        remainingBytes: EXTERNAL_MCP_CATALOG_LIMIT_BYTES - catalogBytes,
      })
      if (seenToolNames.has(tool.name)) {
        throw catalogDiagnosticError({
          tracker: input.diagnostic,
          code: "MCP_CATALOG_DUPLICATE_TOOL",
          operatorAction: "Ensure every tools/list page uses a unique, stable tool name.",
        })
      }
      seenToolNames.add(tool.name)
      tools.push(tool)

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Reduce the provider catalog below 2000 tools
  2. Use a scoped MCP server that exposes only relevant tools
  3. Split one large server into several focused servers and register them separately
  4. If legitimately needed, run with an explicitly larger itemLimit via collectExternalMcpToolPages options (requires gateway-side change)

Example fix

// before: one server with 3500 tools
// after: split into 'db-tools' (300) and 'docs-tools' (120) and connect each scoped server
Defensive patterns

Strategy: validation

Validate before calling

const toolCount = (await fetchAllToolPages()).length
if (toolCount > 2000) throw new Error(`${toolCount} tools exceeds the 2000-tool catalog limit`)

Try / catch

try {
  await connectExternalMcp(...)
} catch (err) {
  if (err instanceof Error && err.message.includes("MCP_CATALOG_ITEM_LIMIT")) {
    console.error("Provider exposes >2000 tools; connect a scoped server instead")
  } else throw err
}

Prevention

When it happens

Trigger: During pagination, tools.length + result.tools.length exceeds 2000, triggering catalogDiagnosticError with code MCP_CATALOG_ITEM_LIMIT.

Common situations: Broad 'everything' MCP servers exposing thousands of tools; aggregated/proxy catalogs; a provider adding auto-generated tools (one per DB table, per endpoint) until the count explodes.

Related errors


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