block / block/berd

Inline MCP Apps fail to render in bundled builds: CSP lacks frame-src for the local goose serve proxy

Open Beginner friendly
#119 0 comments 0 reactions 0 assignees View on GitHub
bug
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.