WebSocket streaming added to MCP Apps via connectedDomains CSP
Ashita Prasad demonstrates how to replace polling-based data updates in a Sales Dashboard MCP App with a direct WebSocket push model by declaring `connectedDomains` in the MCP resource's CSP metadata, running on the Goose open source AI Agent.
Score breakdown
The article shows how the `connectedDomains` CSP field in the MCP Apps spec enables direct WebSocket push connections from sandboxed iframes, removing the host relay overhead that the polling pattern requires.
- 01MCP Apps run in sandboxed iframes that block all outbound network requests by default, including WebSocket.
- 02The `connectedDomains` CSP field in `_meta.ui.csp` grants the iframe permission to open outbound WebSocket connections to specified origins.
- 03The polling approach fired a `tools/call` to `get-realtime-sales-snapshot` via the `postMessage` JSON-RPC bridge on a `setInterval`.
Ashita Prasad describes a practical upgrade to a Sales Dashboard MCP App built on the Goose open source AI Agent. The previous version of the app relied on a request-response polling pattern: every two seconds, the sandboxed iframe sent a `tools/call` to `get-realtime-sales-snapshot` via the `postMessage` JSON-RPC bridge, received data from the MCP server, and re-rendered the UI. While functional, this approach added round-trip latency and required the host to relay data that the UI could receive directly.
The solution centers on `connectedDomains`, a CSP field available in the MCP Apps spec under `_meta.ui.csp`.
The solution centers on `connectedDomains`, a CSP field available in the MCP Apps spec under `_meta.ui.csp`. MCP Apps run inside sandboxed iframes that block all outbound network requests by default — no `fetch`, no `XMLHttpRequest`, no WebSocket. The spec provides two relevant escape hatches: `resourceDomains` for loading static assets like scripts and stylesheets from CDNs, and `connectedDomains` for outbound connections including WebSocket. By adding `connectedDomains: ["ws://localhost:8765"]` to the resource registration in `index.ts`, the MCP host injects a targeted `connect-src` CSP directive that permits the iframe to open a WebSocket connection to exactly that origin. The iframe still performs the required `ui/initialize` handshake with the host, but all live data flows over the direct WebSocket connection. The backend pushing data is a standalone Python script using the `websockets` library, which ports the simulation logic — state multipliers, metric nudging, activity feed generation, and KPI aggregation — from the TypeScript data layer and pushes snapshots to connected clients.
Key facts
- 01MCP Apps run in sandboxed iframes that block all outbound network requests by default, including WebSocket.
- 02The `connectedDomains` CSP field in `_meta.ui.csp` grants the iframe permission to open outbound WebSocket connections to specified origins.
- 03The polling approach fired a `tools/call` to `get-realtime-sales-snapshot` via the `postMessage` JSON-RPC bridge on a `setInterval`.
- 04Adding `connectedDomains: ["ws://localhost:8765"]` to the resource registration injects a targeted `connect-src` CSP directive in the iframe.
- 05The WebSocket backend is a standalone Python script using the `websockets` library.
- 06The `ui/initialize` handshake with the host is still required even when data flows over a direct WebSocket connection.
- 07This article is the fourth in Ashita Prasad's series on MCP Apps, following a deployment on Amazon Bedrock AgentCore.
Topics
Summary and scoring are generated automatically from the original article. We always link back to the publisher and never republish images or paywalled content. Last processed Jun 10, 2026 · 15:34 UTC. How this works →