Note
Grok responding on behalf of Julius.
Thanks for the detailed write-up. I checked this against main at 3143335fc3, which includes the MCP Apps host from #16236. I haven't reproduced it in a running app, and I can't see the Jira shell, so everything about its HTML comes from your report.
Confirmed in code: a card that never initializes stays blank, with no failure state and no way to see the tool result
- When a completed tool item carries an app reference, it becomes an
mcp-approw instead of the normal tool row (session-logic.ts#L733-L750). The app card is therefore the only view of that result. - The frame reserves its height up front:
MCP_APP_DEFAULT_HEIGHT = 320(mcpApp.ts#L21, McpAppFrame.tsx#L94, #L496). - The only error text covers failing to get the asset URL: "Unable to load the … app" (McpAppFrame.tsx#L542-L546). The code itself notes that "a frame cannot report a failed load" (#L126-L129).
- The host sends
tool-input/tool-resultonly afterui/notifications/initialized(host.ts#L202-L211, #L389-L396). The spec requires that ordering (apps.mdx#L485). But the host has no timer except the 2 s teardown one (host.ts#L478-L481), and it doesn't tell the frame whether the app ever initialized.
So if the app's script fails to load or throws before ui/initialize, the result is exactly what you describe: a 320 px empty box that stays that way, with the successful tool result unreachable.
What would block the Jira shell (candidates, none confirmed)
The Confluence documents have their JS inline and render. Per your report, the Jira shell is an empty root plus an external module script and stylesheet. Under the host's policy, that difference matters:
- Injected CSP. At capture time the server writes a CSP
<meta>into the document (McpAppSnapshot.ts#L90-L96). Itsscript-src/style-srcare only'unsafe-inline'plus the declaredresourceDomains, andconnect-srcdefaults to'none'(mcpApp.ts#L178-L195). Declared domains are filtered to bare origins: scheme + host (optional leading*.) + optional port (mcpApp.ts#L63-L76). A declared entry with a path or a trailing/would be silently dropped. Your note says the declared CSP permits the module's origin, but that's not the same as the injected one. Could you check the<meta http-equiv="Content-Security-Policy">at the top of the captured Jira attachment and confirm the module/stylesheet origin appears inscript-src/style-src? Please also check whether any API origin the app fetches appears inconnect-src. - Opaque origin. The frame is
sandbox="allow-scripts allow-forms"and neverallow-same-origin(McpAppFrame.tsx#L535-L536). The asset route also sendsContent-Security-Policy: sandbox allow-scripts allow-forms allow-popups(http.ts#L56-L61). Module scripts are fetched with CORS (MDN), so a request from an opaque origin needs a permissiveAccess-Control-Allow-Origin, which you saw (*). More likely to matter: in an opaque origin,localStoragethrowsSecurityError(MDN). An app that touches storage during startup would die beforeui/initialize. The spec's web-host design runs the view inside a sandbox proxy withallow-scripts+allow-same-originon a separate origin (apps.mdx#L474-L475). T3 omitsallow-same-originon purpose. - No
'unsafe-eval'inscript-src(also true of the spec's sample policy). It only matters if the bundle evals.
Which of these hits the Jira app needs the iframe console, so it's not pinned yet.
Possible fixes (for discussion)
- Add an init deadline to the host, e.g. expose an
initialized/stalledsignal. If the app hasn't sentui/notifications/initializedwithin N seconds, the frame swaps the blank box for "The {server} app didn't load" with a toggle that shows the plain tool call/result (it already has that data viauseTurnItemDetail, McpAppFrame.tsx#L150-L162). This fixes the blank space whatever the root cause. - Optionally surface CSP violations from the frame, so a blocked origin is visible instead of silent. That depends on the app document reporting them, so it needs a design pass.
- Whether to loosen the opaque-origin sandbox, e.g. a dedicated per-app origin like the spec's sandbox proxy, is a separate security/design decision. It shouldn't be bundled with the fallback.
Not verified: the actual runtime failure in the Jira iframe, the injected CSP in your captured document, and mobile/web behavior (mobile uses a separate McpAppWebView). No open PR currently touches McpAppFrame.tsx, host.ts, mcpApp.ts or McpAppSnapshot.ts. Related but separate: #16991 (Confluence dark-mode contrast).