Inline MCP Apps fail to render in bundled builds: CSP lacks frame-src for the local goose serve proxy
- Dominant language
- TypeScript
- Stars
- 909
- Forks
- 116
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 156
Description
### Before filing
- [x] I searched [open and closed issues](https://github.com/block/berd/issues?q=is%3Aissue) for duplicates.
- [x] I reproduced this on the [latest release](https://github.com/block/berd/releases).
- [x] This is one bug, not several bundled together.
### Closest existing issue
#98 (in-app page viewing) is the nearest by topic, but it's a feature request unrelated to this rendering bug — no existing report of this found.
### What's broken
## Summary
MCP App widgets ("apps" returned by MCP servers) render correctly in `just dev`, but in a bundled release build (`just bundle`) the same tool result shows **"Unable to render MCP App inline."** The cause is the production CSP in `src-tauri/tauri.conf.json`: it has no `frame-src` directive, so iframes fall back to `default-src 'self' asset:`, which blocks the MCP app sandbox iframe pointed at the local goose serve proxy (`http://127.0.0.1:/mcp-app-proxy?...`).
## Steps to reproduce
1. Connect an MCP server whose tool results include an MCP App UI resource (reproduced with a streamable-HTTP server; any app-returning server should do).
2. Build and install a release bundle: `just setup && just bundle`, then launch the built `Berd.app`.
3. New chat (Claude Sonnet via Anthropic in my case; model doesn't appear to matter), send a prompt that triggers the MCP tool that returns an app.
4. The tool call completes, but the widget area shows "MCP APP — Unable to render MCP App inline."
5. Same server, same prompt under `just dev`: the app renders fine.
## Expected
Inline MCP Apps render in bundled builds the same way they do in dev builds.
## Actual
Bundled builds always show the `message.mcpAppRenderError` fallback ("Unable to render MCP App inline."); dev builds render the app.
## Frequency
Every time, in bundled builds only.
## Version and platform
- Berd 0.6.3, built from source at `main` @ `977d35fc` (newer than the latest published release; bug present in the pinned config on that commit)
- macOS 26.5.2, Apple Silicon (aarch64)
## Analysis (from reading the source)
- The MCP app sandbox iframe URL is built in `src/features/chat/ui/useMcpAppSandbox.ts` (`buildProxyUrl`) as `http://127.0.0.1:/mcp-app-proxy?...` against the local goose serve HTTP base URL.
- The production CSP in `src-tauri/tauri.conf.json` (`app.security.csp`) defines no `frame-src` (and no `child-src`), so iframe loads fall back to `default-src: 'self' asset:` — which does not permit `http://127.0.0.1:*`. The webview blocks the iframe and `McpAppView` shows the render-error fallback.
- `connect-src` already allows `http://localhost:* ws://localhost:* http://127.0.0.1:* ws://127.0.0.1:*`, so the WebSocket/HTTP side of the same server is permitted — the iframe case looks like an oversight.
- Dev builds don't hit this because no `devCsp` is configured, so the dev webview runs without the production CSP — which is why the bug only appears in bundles.
Suggested fix (one line in `tauri.conf.json`):
```json
"frame-src": "'self' http://localhost:* http://127.0.0.1:*"
```
## Logs
`~/Library/Logs/xyz.block.berd/berd.log` contains no relevant lines — the CSP violation surfaces in the webview console, not the app log. Happy to capture a webview console log from a `just bundle-debug` build if useful.
## Prior issues
Searched open and closed issues for "mcp app render", "csp", "iframe", "frame-src", "unable to render" — none found.
### Steps to reproduce
1. Build and install a release bundle from source: `just setup && just bundle` (macOS, Apple Silicon), then launch the built `Berd.app`.
2. Connect an MCP server whose tool results include an MCP App UI resource. Mine is a remote streamable-HTTP server (`https://mcp.superstock.com/mcp`, OAuth via dynamic client registration), but any app-returning MCP server should reproduce it.
3. Start a new chat (Claude Sonnet via Anthropic; fresh chat, no prior history — model/provider don't appear to matter) and send a prompt that triggers the MCP tool that returns an app (for me: an image search).
4. The tool call completes, but the widget area shows "MCP APP — Unable to render MCP App inline."
5. Run the same server + same prompt under `just dev`: the app renders correctly.
Cause (from reading the source): the MCP app sandbox iframe is pointed at the local goose serve proxy, `http://127.0.0.1:/mcp-app-proxy?...` (`src/features/chat/ui/useMcpAppSandbox.ts`, `buildProxyUrl`). The production CSP in `src-tauri/tauri.conf.json` defines no `frame-src` (and no `child-src`), so iframes fall back to `default-src: 'self' asset:`, which blocks `http://127.0.0.1:*` — the webview blocks the iframe and `McpAppView` shows the `message.mcpAppRenderError` fallback. `connect-src` already allows `http://localhost:* http://127.0.0.1:*` (plus the ws: variants), so the WebSocket/HTTP side of the same server is permitted — the iframe case looks like an oversight. Dev builds don't hit it because no `devCsp` is configured, so the dev webview runs without the production CSP.
Suggested one-line fix in `src-tauri/tauri.conf.json`:
"frame-src": "'self' http://localhost:* http://127.0.0.1:*"
Verified locally: adding that line and rebuilding the bundle makes the same MCP app render inline.
Version: Berd 0.6.3 built from `main` @ `977d35fc`; macOS 26.5.2 (aarch64). Logs: `~/Library/Logs/xyz.block.berd/berd.log` has no relevant lines — the CSP violation surfaces in the webview console, not the app log; happy to capture a `just bundle-debug` webview console log if useful.
### What you expected to happen
Inline MCP Apps render in bundled release builds the same way they do in `just dev`.
### What actually happened
In bundled builds, every MCP App shows the fallback "Unable to render MCP App inline." instead of the app — every time, bundles only; the identical server and prompt render fine in dev builds.
### How often does it happen?
Every time — reliably reproducible
### Berd version
0.6.3 (built from source, main @ 977d35fc)
### Operating system
macOS (Apple Silicon)
### Model and provider
(irrelevant to the bug — reproduces regardless of model)
### Relevant log output
```text
No relevant log output — berd.log has no lines around the failure. The block
happens inside the webview (CSP violation), which logs to the webview console
rather than the app log. Happy to capture a webview console log from a
`just bundle-debug` build if useful.
```
### Screenshots, recordings, or other context
_No response_
Contributor guide
Research direction
Start in src-tauri/tauri.conf.json and inspect app.security.csp, then compare it with the iframe URL built by buildProxyUrl in src/features/chat/ui/useMcpAppSandbox.ts. Verify a bundled build with an MCP App server after allowing the local proxy as a frame source; done means the inline app renders in the bundle as it does under just dev.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- desktop, security
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- Under an hour
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 91/100