{"record":{"id":"968a8cfcae32bf1e","repo":"different-ai/openwork","slug":"mcp-catalog-schema-depth-limit-mcp-catalog-schema","errorCode":"MCP_CATALOG_SCHEMA_DEPTH_LIMIT|MCP_CATALOG_SCHEMA_CYCLE|MCP_CATALOG_SCHEMA_SIZE_LIMIT","errorMessage":"Flatten each tool schema below ${EXTERNAL_MCP_TOOL_SCHEMA_DEPTH_LIMIT} nested levels.","messagePattern":"Flatten each tool schema below (.+?) nested levels\\.","errorType":"error_code","errorClass":"ExternalMcpDiagnosticError","httpStatus":null,"severity":"error","filePath":"ee/apps/den-api/src/capability-sources/external-mcp-client.ts","lineNumber":613,"sourceCode":"  schema: unknown\n}): void {\n  const measurement = measureSerializedJson(\n    input.schema,\n    EXTERNAL_MCP_TOOL_SCHEMA_LIMIT_BYTES,\n    EXTERNAL_MCP_TOOL_SCHEMA_DEPTH_LIMIT,\n  )\n  if (measurement.ok) return\n  const code = measurement.reason === \"depth\"\n    ? \"MCP_CATALOG_SCHEMA_DEPTH_LIMIT\"\n    : measurement.reason === \"cycle\"\n      ? \"MCP_CATALOG_SCHEMA_CYCLE\"\n      : \"MCP_CATALOG_SCHEMA_SIZE_LIMIT\"\n  const operatorAction = measurement.reason === \"depth\"\n    ? `Flatten each tool schema below ${EXTERNAL_MCP_TOOL_SCHEMA_DEPTH_LIMIT} nested levels.`\n    : measurement.reason === \"cycle\"\n      ? \"Return JSON-serializable, acyclic tool schemas.\"\n      : `Reduce each serialized tool schema below ${EXTERNAL_MCP_TOOL_SCHEMA_LIMIT_BYTES} bytes.`\n  throw catalogDiagnosticError({ tracker: input.diagnostic, code, operatorAction })\n}\n\nfunction measureCatalogTool(input: {\n  diagnostic: ExternalMcpDiagnosticTracker\n  tool: ExternalMcpToolPage[\"tools\"][number]\n  remainingBytes: number\n}): number {\n  validateToolCatalogField({\n    diagnostic: input.diagnostic,\n    value: input.tool.name,\n    field: \"name\",\n    limit: EXTERNAL_MCP_TOOL_NAME_LIMIT_BYTES,\n    code: \"MCP_CATALOG_TOOL_NAME_LIMIT\",\n  })\n  validateToolCatalogField({\n    diagnostic: input.diagnostic,\n    value: input.tool.title,\n    field: \"title\",","sourceCodeStart":595,"sourceCodeEnd":631,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/capability-sources/external-mcp-client.ts#L595-L631","documentation":"During catalog ingestion, each tool's JSON schema is measured via measureSerializedJson; failures are classified by reason (depth, cycle, size) and converted into one of the codes MCP_CATALOG_SCHEMA_DEPTH_LIMIT, MCP_CATALOG_SCHEMA_CYCLE, or MCP_CATALOG_SCHEMA_SIZE_LIMIT with this operator action for the depth case. The gateway refuses schemas deeper than EXTERNAL_MCP_TOOL_SCHEMA_DEPTH_LIMIT, cyclic, or too large, to protect enterprise clients from pathological schemas.","triggerScenarios":"tools/list ingestion calls the schema validation with a tool whose inputSchema measurement fails: nesting exceeds EXTERNAL_MCP_TOOL_SCHEMA_DEPTH_LIMIT, the schema object contains a reference cycle, or its serialized form exceeds EXTERNAL_MCP_TOOL_SCHEMA_LIMIT_BYTES.","commonSituations":"Providers with deeply nested oneOf/allOf JSON Schemas generated from SDK types; recursive schema definitions ($ref cycles) that break naive serializers; monolithic schemas embedding large enums or embedded examples.","solutions":["Flatten the tool schema to fewer than EXTERNAL_MCP_TOOL_SCHEMA_DEPTH_LIMIT nested levels (collapse oneOf/allOf nesting, hoist shared subschemas)","Remove recursive/cyclic $ref structures or make the schema acyclic and JSON-serializable","Minimize schema size: trim long descriptions, cap enum sizes, drop embedded defaults/examples","Check the thrown code (DEPTH vs CYCLE vs SIZE) to know which measurement failed"],"exampleFix":"// before\nschema: { a: { b: { c: { d: { e: { f: { type: \"string\" } } } } } } } // too deep\n// after\nschema: { a: { type: \"object\", properties: { b: { $ref: \"#/definitions/leaf\" } } }, definitions: { leaf: { type: \"string\" } } }","handlingStrategy":"validation","validationCode":"function schemaDepth(s: unknown, d = 0): number {\n  if (d > EXTERNAL_MCP_TOOL_SCHEMA_DEPTH_LIMIT) throw new Error(\"schema too deep\");\n  if (s && typeof s === \"object\") for (const v of Object.values(s)) schemaDepth(v, d + 1);\n  return d;\n}\nschemaDepth(tool.inputSchema);","typeGuard":"null","tryCatchPattern":"try {\n  await listExternalMcpTools(conn);\n} catch (e) {\n  const code = String(e);\n  if (code.includes(\"SCHEMA_DEPTH\")) flattenSchemas();\n  else if (code.includes(\"SCHEMA_CYCLE\")) breakRefCycles();\n  else if (code.includes(\"SCHEMA_SIZE\")) shrinkSchemas();\n  else throw e;\n}","preventionTips":["Keep JSON Schemas shallow; hoist shared subschemas instead of deep nesting","Avoid recursive $ref cycles in generated schemas","Trim schema size: cap enums, drop embedded examples","Validate schemas with the same measurement logic before exposing tools"],"tags":["mcp","json-schema","validation","limits"],"backgroundTag":"mcp-catalog-limit-exceeded","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}