External Publication
Visit Post

MCP App updateModelContext silently dropped for live-rendered iframes (works after page refresh)

OpenAI Developer Community April 24, 2026
Source

Bug Report: ui/update-model-context silently dropped for live-rendered iframes in ChatGPT MCP Apps

Summary

When an MCP App calls ui/update-model-context (via the @modelcontextprotocol/ext-apps SDK or raw postMessage), ChatGPT acknowledges the JSON-RPC request with a success result ({}), but the context is silently dropped and never surfaced to the model on the next user turn.

This failure occurs whenever the iframe is rendered live as part of the active chat (i.e., in direct response to a tool call). It is not limited to the first iframe in a session — every iframe instantiated through normal chat surfacing is affected, including subsequent calls to the same tool. The only iframes that do work are those rendered from rehydrated chat history (see Workarounds below).

Steps to Reproduce

  1. Start a new chat in ChatGPT.

  2. Trigger an MCP tool that returns a UI resource (ui://...).

  3. The iframe loads and connects via the SDK.

  4. The app calls app.updateModelContext({ content: [...], structuredContent: {...} }).

  5. The host responds with a successful JSON-RPC result (no error).

  6. The user sends a follow-up message asking the model about the context that was just pushed.

  7. Result: The model has no knowledge of the pushed context. Furthermore, all subsequent calls to updateModelContext during this session are also silently ignored by the model.

Workarounds that “fix” the issue (Confirming it’s a host-side state bug)

The context is successfully surfaced to the model if any of the following conditions are met:

  1. Other MCP Hosts: The exact same MCP server and UI code works flawlessly on first load in other compliant MCP App hosts (e.g., MCPJam Inspector).

  2. Rehydrated Chat History: If the app is used in an older chat, or if the user simply refreshes the ChatGPT browser tab (rehydrating the chat history) and then interacts with the app, updateModelContext works perfectly.

  3. DevTools Open During Render: If Chrome DevTools is open while the iframe is initially rendering , the context updates work. (Opening DevTools after the initial render does not fix it).

What we’ve ruled out (Client-side troubleshooting)

We spent significant time debugging the iframe client to rule out implementation errors:

  • Not an SDK bug: We bypassed @modelcontextprotocol/ext-apps entirely and sent raw ui/update-model-context JSON-RPC messages via window.parent.postMessage. The behavior is identical.

  • Not a timing/delay issue on our end: We tried delaying the updateModelContext calls (using setTimeout and requestIdleCallback for up to 5 seconds after initialization). The host still silently drops the context.

  • Not a capability issue: The host explicitly advertises updateModelContext: true in its capabilities during the ui/initialize handshake.

  • Not a legacy protocol issue: We verified via postMessage interception that the host is exclusively using the ui/* namespace, not falling back to legacy openai/* methods.

Hypothesis

There appears to be a race condition or state-binding failure in ChatGPT’s host implementation during the live render of any MCP App iframe inside an active chat turn.

When the iframe sends its ui/initialize or ui/notifications/initialized handshake during a live tool-call render, the host’s internal plumbing that binds the iframe’s updateModelContext channel to the active model context is not yet ready (or is being torn down/replaced as the assistant turn streams). Because the host still returns a success result to the RPC call, the app has no way of knowing the data was dropped.

The DevTools workaround suggests that slowing down the iframe’s initial execution allows the host’s binding logic to complete before the handshake occurs. The rehydration workaround (page refresh, older chats) suggests that the host follows a different, working code path when restoring iframes from saved chat history versus instantiating them live.

Request

Could the team investigate the lifecycle binding of the updateModelContext channel for iframes that are instantiated live during an active chat turn (as opposed to those restored from chat history)? A reliable way for the app to know the channel is actually bound — or deferring the JSON-RPC success response until it is — would prevent this silent failure.

Discussion in the ATmosphere

Loading comments...