[BUG] Desktop/Code: MCP widget sandbox frame blocked by CSP renders nothing — no error surfaced, and the tool result still reports "rendered"
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
On a network where a web gateway intercepts framed requests, the MCP widget sandbox iframe is redirected from its allowlisted origin to the gateway's own origin, which is not in the app's frame-src. Chromium blocks the frame and the widget never paints.
Two things turn that into lost work rather than a cosmetic gap:
- No error surfaces anywhere in the UI. The tool result degrades to printing the raw
widget_codeHTML as literal text inside a collapsedUsed <connector>: Show widget ›disclosure. Expanding it shows the call parameters, not a render. - The MCP server reports success unconditionally. It returns
"Content rendered and shown to the user. Please do not duplicate the shown content in text because it's already visually represented."regardless of what the client did. The model reads that as confirmation and therefore suppresses the text equivalent, so the user gets nothing at all while the agent believes it delivered.
That combination cost two round trips in one session before a screenshot established that nothing had rendered. A result string authored by the callee cannot attest to a client-side render.
What Should Happen?
Either of these would be sufficient:
- Surface a visible error when the widget sandbox frame is blocked, instead of silently falling back to raw text.
- Signal render failure back to the model so it can fall back to a text equivalent, rather than suppressing it on the strength of a success string the server has no way to substantiate.
Error Messages/Logs
From ~/Library/Logs/Claude/claude.ai-web.log (gateway origin redacted):
Framing 'https://<corp-gateway>:8070/' violates the following Content Security Policy directive:
"frame-src 'self' a-cdn.claude.ai a.claude.ai ... https://www.claudemcpclient.com
*.claudemcpcontent.com https://sandbox.claudemcpcontent.com https://claude.ai
*.livepreview.claude.ai *.livepreview.claude.app". The request has been blocked.
No other error is logged, and nothing is shown in the UI.
Steps to Reproduce
- Use Claude Code desktop on a network whose web gateway intercepts and rewrites framed requests.
- Have a connector installed that returns visual content via a widget tool.
- Count CSP violations in
~/Library/Logs/Claude/claude.ai-web.log. - Trigger one widget call.
- Re-count.
Observed: exactly one new CSP frame violation per widget call — 769 before a single call, 770 four seconds later. The widget does not render; the transcript shows a collapsed tool-call row whose expanded view is the raw widget_code.
Is this a regression?
Unknown — there is no evidence it ever rendered on this network.
Claude Code Version
Desktop app 2.2553.1, Agent SDK 0.3.275
Platform
Claude Code Desktop app
Operating System
macOS (Darwin 25.6.0)
Terminal/Shell
N/A — desktop app (underlying shell zsh)
Additional Information
Not a duplicate of #88566. That report traces widgets never rendering to the MCP Apps gate being false in deploymentMode: 3p. Here the gate is demonstrably on: [mcp-ext-apps-host] is active and parsing UI declarations from other connectors, the deployment is first-party (ANTHROPIC_BASE_URL=https://api.anthropic.com, no deploymentMode key present), and the frame is genuinely attempted and then blocked. Same visible symptom, different cause.
Ruled out locally: the connector is healthy (status: connected), and tool-name resolution is not involved — the friendly alias and the id-based tool name behave identically. DNS is clean and curl from the same machine to https://sandbox.claudemcpcontent.com/ returns 307 directly to the vendor address, so the redirection is scoped to the renderer rather than the machine.
The network-side fix is being pursued separately with the network owner; this report is about the silent failure and the unconditional success string, which affect any user behind an intercepting proxy.