different-ai/openwork · error · ExternalMcpDiagnosticError

MCP_CATALOG_BYTE_LIMIT

MCP_CATALOG_BYTE_LIMIT

Error message

MCP_CATALOG_BYTE_LIMIT

What it means

Thrown by measureCatalogTool when measuring an individual tool's serialized JSON would exceed the remaining budget of EXTERNAL_MCP_CATALOG_LIMIT_BYTES (8 MiB). The gateway caps the entire serialized tool catalog per provider so downstream storage and agent contexts stay bounded.

Source

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

    value: input.tool.description,
    field: "description",
    limit: EXTERNAL_MCP_TOOL_DESCRIPTION_LIMIT_BYTES,
    code: "MCP_CATALOG_TOOL_DESCRIPTION_LIMIT",
  })
  validateToolSchema({ diagnostic: input.diagnostic, schema: input.tool.inputSchema })
  if (input.tool.outputSchema !== undefined) {
    validateToolSchema({ diagnostic: input.diagnostic, schema: input.tool.outputSchema })
  }

  const measurement = measureSerializedJson(
    input.tool,
    Math.max(0, input.remainingBytes),
    EXTERNAL_MCP_TOOL_SCHEMA_DEPTH_LIMIT + 4,
  )
  if (!measurement.ok) {
    throw catalogDiagnosticError({
      tracker: input.diagnostic,
      code: "MCP_CATALOG_BYTE_LIMIT",
      operatorAction: `Reduce the complete serialized tool catalog below ${EXTERNAL_MCP_CATALOG_LIMIT_BYTES} bytes.`,
    })
  }
  return measurement.bytes
}

export async function collectExternalMcpToolPages(input: {
  listPage: (cursor: string | undefined, options: RequestOptions) => Promise<ExternalMcpToolPage>
  diagnostic: ExternalMcpDiagnosticTracker
  pageLimit?: number
  itemLimit?: number
  deadline?: ExternalMcpLifecycleDeadline
}): Promise<ExternalMcpToolPage["tools"]> {
  const pageLimit = input.pageLimit ?? EXTERNAL_MCP_TOOL_PAGE_LIMIT
  const itemLimit = input.itemLimit ?? EXTERNAL_MCP_TOOL_ITEM_LIMIT
  const deadline = input.deadline ?? createExternalMcpLifecycleDeadline()
  const tools: ExternalMcpToolPage["tools"] = []
  const seenCursors = new Set<string>()

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Reduce the number of tools exposed by the provider
  2. Shrink each tool's inputSchema/outputSchema (drop redundant fields, flatten oneOfs)
  3. Split the provider into multiple scoped MCP servers and connect only the needed ones
  4. Register the provider with a narrower tool allowlist if the gateway supports scoping

Example fix

// before: server exposes 500 tools with ~20KB schemas each (~10MB total)
// after: expose only the 50 tools the org actually uses (~1MB total)
Defensive patterns

Strategy: validation

Validate before calling

const catalogBytes = new TextEncoder().encode(JSON.stringify({ tools })).byteLength
if (catalogBytes > 8 * 1024 * 1024) throw new Error(`catalog too large: ${catalogBytes} bytes (limit 8MiB)`)

Type guard

function fitsCatalogBudget(serialized: string): boolean {
  return new TextEncoder().encode(serialized).byteLength < 8 * 1024 * 1024
}

Try / catch

try {
  await connectExternalMcp(...)
} catch (err) {
  if (err instanceof Error && err.message.includes("MCP_CATALOG_BYTE_LIMIT")) {
    console.error("Serialized catalog exceeds 8MiB; reduce tool count/schema size")
  } else throw err
}

Prevention

When it happens

Trigger: Cumulative catalogBytes plus the current tool's measured size surpasses 8 MiB, so measureSerializedJson is called with remainingBytes <= 0 or too little room and reports failure.

Common situations: One provider exposing thousands of very large tools; servers shipping huge JSON Schemas per tool; aggregating gateways that proxy many upstream servers into one catalog.

Related errors


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