{"record":{"id":"baddb06cc19d1a72","repo":"different-ai/openwork","slug":"mcp-tool-catalog-response-was-incomplete","errorCode":null,"errorMessage":"MCP tool catalog response was incomplete.","messagePattern":"MCP tool catalog response was incomplete\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-data.tsx","lineNumber":310,"sourceCode":"  };\n}\n\nexport function useMcpConnectionTools(connectionId: string, enabled: boolean) {\n  const { orgId } = useOrgDashboard();\n  return useQuery({\n    enabled: enabled && Boolean(orgId),\n    queryKey: mcpConnectionQueryKeys.tools(orgId, connectionId),\n    queryFn: async (): Promise<ExternalMcpToolCatalog> => {\n      const { response, payload } = await requestJson(\n        `/v1/mcp-connections/${encodeURIComponent(connectionId)}/tools`,\n        { headers: getOrgScopeHeaders(requireOrgId(orgId)) },\n        30000,\n      );\n      if (!response.ok) {\n        throw getRequestError(payload, response, `Failed to inspect MCP tools (${response.status}).`);\n      }\n      if (!isRecord(payload) || !Array.isArray(payload.tools)) {\n        throw new Error(\"MCP tool catalog response was incomplete.\");\n      }\n      const policy = parseExternalMcpToolPolicy(payload.policy);\n      if (!policy || !payload.tools.every(isExternalMcpTool)) {\n        throw new Error(\"MCP tool catalog response was incomplete.\");\n      }\n      return { tools: payload.tools, policy };\n    },\n  });\n}\n\nexport function useUpdateMcpConnectionToolPolicy(connectionId: string) {\n  const queryClient = useQueryClient();\n  const { orgId } = useOrgDashboard();\n  return useMutation({\n    mutationFn: async (input: Pick<ExternalMcpToolPolicyView, \"allDisabled\" | \"disabledTools\">): Promise<ExternalMcpToolPolicyView> => {\n      const { response, payload } = await requestJson(\n        `/v1/mcp-connections/${encodeURIComponent(connectionId)}/tool-policy`,\n        {","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-data.tsx#L292-L328","documentation":"useMcpConnectionTools inspects an external MCP connection's tool catalog via a 30s requestJson call. Two separate checks throw this same message: (1) payload is not a record or payload.tools is not an array; (2) the parsed policy is null or any entry of payload.tools fails the isExternalMcpTool shape check. It means the server replied ok but the catalog body does not match the expected { tools: [...], policy: {...} } contract.","triggerScenarios":"POST inspect-tools returns 200 with {tools: '...'} or missing tools; a tool object missing required fields (name/inputSchema etc.) failing isExternalMcpTool; payload.policy absent or unparseable by parseExternalMcpToolPolicy.","commonSituations":"MCP server exposing tools with non-standard metadata; den-api version older than the dashboard expecting new tool fields; policy feature-flag disabled server-side so 'policy' is omitted from the response.","solutions":["Log payload and compare each tool against the isExternalMcpTool required fields","Upgrade den-api server to match the dashboard's expected catalog schema (or vice versa)","Check parseExternalMcpToolPolicy against the actual payload.policy shape","If a single malformed tool is the cause, fix or filter it server-side before returning the catalog"],"exampleFix":"// before\nif (!policy || !payload.tools.every(isExternalMcpTool)) {\n  throw new Error(\"MCP tool catalog response was incomplete.\");\n}\n// after\nconst badIndex = payload.tools.findIndex((t) => !isExternalMcpTool(t));\nif (badIndex >= 0) {\n  console.warn(\"Skipping malformed MCP tool at index\", badIndex, payload.tools[badIndex]);\n}\nconst tools = payload.tools.filter(isExternalMcpTool);\nif (!policy || tools.length === 0) {\n  throw new Error(\"MCP tool catalog response was incomplete.\");\n}\nreturn { tools, policy };","handlingStrategy":"type-guard","validationCode":"if (!isRecord(payload) || !Array.isArray(payload.tools)) {\n  // request a refetch or show a catalog-unavailable state\n}","typeGuard":"function isExternalMcpTool(v: unknown): v is ExternalMcpTool {\n  return isRecord(v) && typeof v.name === \"string\" && isRecord(v.inputSchema);\n}","tryCatchPattern":"try {\n  const { tools, policy } = await refetchCatalog();\n} catch (err) {\n  if (err.message === \"MCP tool catalog response was incomplete.\") {\n    showCatalogUnavailable(err); // offer retry\n  }\n}","preventionTips":["Validate one tool at a time and log the offending index instead of failing the whole catalog","Add contract tests asserting {tools:[],policy:{}} shape on the inspect endpoint","Keep dashboard and den-api schema versions in lockstep"],"tags":["api","schema-validation","mcp","response-shape"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}