{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreigwast5fm5hdzjvkbnkyurvk4ywu7ck6toftwokggcad6kqc677ua",
    "uri": "at://did:plc:lk3jfj3zq4k4wxnk474axylu/app.bsky.feed.post/3mkaos6tefuy2"
  },
  "path": "/t/mcp-app-updatemodelcontext-silently-dropped-for-live-rendered-iframes-works-after-page-refresh/1379700#post_1",
  "publishedAt": "2026-04-24T13:32:15.000Z",
  "site": "https://community.openai.com",
  "tags": [
    "@modelcontextprotocol"
  ],
  "textContent": "# Bug Report: `ui/update-model-context` silently dropped for live-rendered iframes in ChatGPT MCP Apps\n\n## Summary\n\nWhen 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.\n\nThis 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).\n\n## Steps to Reproduce\n\n  1. Start a new chat in ChatGPT.\n\n  2. Trigger an MCP tool that returns a UI resource (`ui://...`).\n\n  3. The iframe loads and connects via the SDK.\n\n  4. The app calls `app.updateModelContext({ content: [...], structuredContent: {...} })`.\n\n  5. The host responds with a successful JSON-RPC result (no error).\n\n  6. The user sends a follow-up message asking the model about the context that was just pushed.\n\n  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.\n\n\n\n\n## Workarounds that “fix” the issue (Confirming it’s a host-side state bug)\n\nThe context _is_ successfully surfaced to the model if any of the following conditions are met:\n\n  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).\n\n  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.\n\n  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).\n\n\n\n\n## What we’ve ruled out (Client-side troubleshooting)\n\nWe spent significant time debugging the iframe client to rule out implementation errors:\n\n  * **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.\n\n  * **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.\n\n  * **Not a capability issue:** The host explicitly advertises `updateModelContext: true` in its capabilities during the `ui/initialize` handshake.\n\n  * **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.\n\n\n\n\n## Hypothesis\n\nThere 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.\n\nWhen 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.\n\nThe 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.\n\n## Request\n\nCould 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.",
  "title": "MCP App updateModelContext silently dropped for live-rendered iframes (works after page refresh)"
}