Why MCP and ChatGPT Apps Use Double Iframes

Frédéric Barthelet, Alpic20:11 · Jun 2026 · 8,072 views
Thumbnail for Why MCP and ChatGPT Apps Use Double Iframes Watch on YouTube
TL;DR
  1. 1

    ChatGPT cannot safely render third-party app HTML directly because `srcdoc` shares its origin and content security policy blocks external scripts.

  2. 2

    Sandboxing an iframe removes access to origin-based storage, while adding `allow-same-origin` restores the security problem it was meant to solve.

  3. 3

    The double-iframe design isolates each app while allowing its HTML to load, and app developers must declare every external domain in their MCP metadata.

Summary

Frédéric Barthelet explains why ChatGPT renders MCP app views through two nested iframes. A direct `srcdoc` iframe shares ChatGPT's origin, so ChatGPT's content security policy blocks app scripts. Relaxing that policy would let an app access ChatGPT's localStorage and cookies. Sandboxing the iframe removes its origin, which also removes localStorage, IndexedDB, and cookies. Adding `allow-same-origin` restores those capabilities and creates a path to access the parent context. Loading each app from its own domain would require ChatGPT to add every app domain to its frame policy, while proxying all apps through one host would make ChatGPT responsible for untrusted code. The resulting design uses an outer iframe on an isolated, app-specific subdomain. That frame loads a common script, which places the app HTML into an inner `srcdoc` iframe. Barthelet also shows Skybridge's CSP inspector, which compares declared domains with domains actually reached during development.

Key ideas
01:59

MCP app views are HTML snippets attached to tool calls

Views are small HTML documents that can include JavaScript and CSS. An MCP server advertises which tools have a view through metadata in the tool list. When a user invokes one of those tools, the host creates an iframe, injects the tool result, and renders the associated view inside the conversation. Hosts can cache view resources after discovering them, or download them when the tool call happens. This gives conversational agents an interactive surface alongside their text response.

06:03

A direct srcdoc iframe inherits ChatGPT's origin and CSP

Barthelet first considers putting the app HTML directly into an iframe's `srcdoc` attribute. This avoids fetching another document, but the iframe shares the host's origin and therefore its content security policy. ChatGPT's `script-src` policy requires scripts to carry a nonce generated for each request. Third-party app JavaScript does not have that nonce, so the app cannot execute its scripts. The approach fails before the app can behave like an application.

07:29

Relaxing CSP would expose ChatGPT storage to app code

If ChatGPT allowed arbitrary scripts in the `srcdoc` frame, the frame would still share the parent origin. App code could then access origin-indexed data belonging to ChatGPT, including localStorage and cookies. Barthelet gives the concrete risk of an app reading ChatGPT's existing localStorage and sending it to its backend. Restoring the restrictive CSP avoids that direct script execution, but it does not by itself provide a way to run the app.

08:34

Sandboxing removes origin-based storage, and allow-same-origin restores the risk

A sandboxed iframe receives an opaque, effectively null origin, so its scripts cannot access the parent DOM. That isolation also prevents the app from using localStorage, IndexedDB, or cookies, because those features depend on an origin. Adding `allow-same-origin` gives the frame an origin again, but in this setup it brings back the parent's origin. Barthelet describes that combination as returning to the condition where the iframe can escape its sandbox and access parent DOM and storage.

09:36

Loading every app from its own domain does not scale with ChatGPT's CSP

Barthelet next considers the normal iframe `src` attribute, with each app exposing its HTML from its own server. ChatGPT's `frame-src` policy would then need to list every domain allowed to render an iframe. Each new app would require a CSP update, which he says is not workable at store scale. A controlled proxy domain could avoid that list, but the host would have to download and serve unknown third-party code, maintain routing across app subdomains, and operate the required infrastructure.

12:03

The double iframe separates the loader origin from the app HTML

The production design uses an outer iframe on a domain different from ChatGPT. That frame serves a common lightweight script. The script retrieves the app resource and creates an inner iframe whose `srcdoc` contains the app HTML. The inner frame is not placed at the top level, where it would share the wrong origin. Barthelet says the loader uses different subdomains for different apps, so origin-based storage such as localStorage or cookies does not collide between app ABC123 and app ABC456. The pattern also traces back to Facebook's app marketplace.

14:03

App metadata must declare the domains used by the view

MCP app developers must list the domains their applications depend on in the app metadata. An API used by the view belongs in `connect-src`. External scripts, images, and frames need the corresponding metadata directives. The nested iframe setup rewrites these declarations into the app's content security policy. Missing a domain can leave an app unable to reach a service after deployment, and Barthelet connects this problem with ChatGPT app store rejections and production failures.

17:32

Skybridge's CSP inspector compares declarations with real network calls

Barthelet demos Skybridge, Alpic's open source framework built on the official app SDK. Its development tool displays the app's tools and renders their associated views. The CSP inspector compares domains listed in the app metadata with domains the view actually contacts. In the demo, adding a fetch to an IP-location API immediately produces a missing-domain warning. After Barthelet adds that domain to the metadata and reloads the app, the inspector marks the check as green. This gives developers feedback before submitting an app.

"The double iframe mechanism is basically load the same script for everybody, which will be a simple script responsible to recover the resources and initiate an iframe with the source doc attribute."12:03
Who should watch
  • You are building an MCP app with an interactive view and need to understand why it is rendered inside nested iframes.
  • Your app works locally but fails in production or gets rejected because external APIs, scripts, images, or frames are missing from its CSP metadata.
  • You are implementing an MCP app development workflow and want a live check of declared domains against the view's actual network calls.