{"record":{"id":"ea308fff92b7e354","repo":"different-ai/openwork","slug":"mcp-app-resource-resolution-failed","errorCode":"MCP_APP_RESOURCE_RESOLUTION_FAILED","errorMessage":"safeMcpAppDiagnosticMessage(cause, \"The interactive view resource could not be resolved.\")","messagePattern":"safeMcpAppDiagnosticMessage\\(cause, \"The interactive view resource could not be resolved\\.\"\\)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/app/src/components/chat/mcp-app-frame.tsx","lineNumber":597,"sourceCode":"  useEffect(() => {\n    let cancelled = false\n    setApp(null)\n    setError(null)\n    if (!result || !openworkServerClient || !workspaceId) return () => { cancelled = true }\n    const startedAt = performance.now()\n    void openworkServerClient.resolveMcpApp(workspaceId, part.toolName, launch ?? undefined)\n      .then(({ app: resolved }) => {\n        if (cancelled) return\n        // A preserved MCP result is neutral transport data. A null resolution\n        // means the current tool definition does not advertise an MCP App, so\n        // ordinary tools such as save_artifact_view render only their normal\n        // result without claiming an unavailable interactive view.\n        setApp(resolved)\n      })\n      .catch((cause) => {\n        if (!cancelled && isActionableMcpAppResolutionError(cause)) {\n          const diagnostic: McpAppDiagnostic = {\n            code: \"MCP_APP_RESOURCE_RESOLUTION_FAILED\",\n            ...(cause instanceof OpenworkServerError ? { causeCode: cause.code } : {}),\n            stage: \"resource-resolution\",\n            message: safeMcpAppDiagnosticMessage(cause, \"The interactive view resource could not be resolved.\"),\n            toolName: part.toolName,\n            elapsedMs: Math.round(performance.now() - startedAt),\n            checkpoints: [\"resolve-started\"],\n          }\n          console.error(`[OpenWork MCP App] ${diagnostic.code}`, diagnostic)\n          setError(diagnostic)\n        }\n      })\n    return () => { cancelled = true }\n  }, [launch, openworkServerClient, part.toolName, result, workspaceId])\n\n  if (!result || (!app && !error)) return null\n  if (error) return <McpAppDiagnosticNotice error={error} notice={CHAT_MCP_APP_UNAVAILABLE_NOTICE} />\n  if (!app) return null\n  return (","sourceCodeStart":579,"sourceCodeEnd":615,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/app/src/components/chat/mcp-app-frame.tsx#L579-L615","documentation":"Emitted by McpAppFrame when resolving the interactive view resource for an MCP app part fails with an actionable error (isActionableMcpAppResolutionError). The component builds an McpAppDiagnostic with code MCP_APP_RESOURCE_RESOLUTION_FAILED, stage 'resource-resolution', and a message produced by safeMcpAppDiagnosticMessage(cause, fallback) - falling back to 'The interactive view resource could not be resolved.' It surfaces why the embedded MCP app UI could not be fetched/resolved, including the underlying OpenworkServerError causeCode when present.","triggerScenarios":"The resource fetch for the MCP app's interactive view rejects: the resource URI no longer exists (404), the server returns an OpenworkServerError during resolution, network failure while fetching the view resource, or the resolved payload is not a usable app after retries within the cancellation window.","commonSituations":"MCP server restarted and its resource handles became invalid; chat history referencing a tool result whose resource expired; server version mismatch changing resource resolution routes; transient network interruption while loading the frame.","solutions":["Check the diagnostic's causeCode/stage to see the underlying resolution failure (e.g. 404 vs network).","Re-run the tool call so a fresh interactive view resource is generated and re-resolve it.","Verify the MCP server that owns the resource is running and its resource endpoints are reachable.","If resources expire, configure longer retention or have the client re-request the view instead of caching stale URIs."],"exampleFix":"// before: resolving a stale stored resource URI\nsetApp(await resolveApp(part.resourceUri))\n// after: fall back to a fresh resolution on failure\ncatch (cause) { setApp(await rerunToolAndResolve(part.toolName)); }","handlingStrategy":"fallback","validationCode":"const res = await fetch(viewUrl, { method: 'HEAD' });\nif (res.status === 404) throw new OpenworkServerError('RESOURCE_EXPIRED', 'Interactive view resource no longer exists');","typeGuard":"function isResolutionFailed(d: McpAppDiagnostic): boolean {\n  return d.code === 'MCP_APP_RESOURCE_RESOLUTION_FAILED';\n}","tryCatchPattern":"resolveApp(part).then(setApp).catch((cause) => {\n  if (!cancelled && isActionableMcpAppResolutionError(cause)) {\n    setDiagnostic({ code: 'MCP_APP_RESOURCE_RESOLUTION_FAILED', stage: 'resource-resolution', causeCode: cause instanceof OpenworkServerError ? cause.code : undefined });\n  }\n});","preventionTips":["Handle resolution failure with a visible fallback UI instead of a blank frame","Re-request the tool result when the stored resource URI returns 404","Propagate OpenworkServerError causeCode into diagnostics for root-cause triage","Guard against state updates after unmount with the cancelled flag"],"tags":["mcp","resource-resolution","ui","diagnostics"],"backgroundTag":"resource-resolution-failed","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}