{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreigg6nomrdwdjatxm3r6xxlt4ym32zxaomwum2jcetumjxmjgvwphe",
"uri": "at://did:plc:lk3jfj3zq4k4wxnk474axylu/app.bsky.feed.post/3mkbcxmspstf2"
},
"path": "/t/runtime-error-on-all-resource-widgets-in-developer-mode/1379591#post_4",
"publishedAt": "2026-04-24T18:41:39.000Z",
"site": "https://community.openai.com",
"tags": [
"@mstoiber"
],
"textContent": "# @mstoiber\n\nOn every request the ChatGPT Client:\n\n1. Calls `resources/list` — discovers all resources\n\n2. Calls `resources/read` for **every** resource — sequentially, one by one\n\n3. Calls `tools/list` — discovers tools\n\n4. Calls `tools/call` — executes a tool, which references a single `resourceUri`\n\n5. Renders **one** widget\n\nSteps 1-2 download all resource HTML upfront even though only one widget is rendered per tool call. This repeats on every turn — nothing is cached across messages.\n\nFor N resources of ~150KB each, that’s N × 150KB re-downloaded every turn regardless of which tool is called. As apps grow in complexity (more screens, more widgets), the per-turn cost grows linearly while the value stays constant (1 widget rendered).\n\n**Resource filtering doesn’t work either.** When a server returns a subset from `resources/list`, ChatGPT changes its tool selection behavior — it avoids calling tools whose associated resources are missing from the list, falling back to text responses. This means `resources/list` is implicitly coupled to tool planning, preventing servers from optimizing resource delivery independently.\n\n### Requested\n\n1. **Lazy loading** — fetch `resources/read` after a tool returns `resourceUri`, not before. The tool result already specifies which widget to render — there’s no need to prefetch all of them speculatively.\n\n2. **Caching** — resource URIs already include cache-busting identifiers (e.g. `ui://widget-abc123`). When the URI hasn’t changed between turns, skip the re-fetch.\n\n3. **Decouple resources from tool selection** — tool selection should be driven by `tools/list` and tool descriptions, not by which resources are in `resources/list`. Servers should be able to filter resources without it affecting which tools ChatGPT decides to call.\n\n### Why this matters\n\nThe prefetch-all model caps app complexity. Every resource added increases the per-turn bandwidth cost linearly, but only one widget is shown at a time. Multi-step apps (guided flows, wizards, checkout processes) naturally need many widgets — one per step — but the current behavior makes them progressively slower with each widget added.\n\nWith lazy loading or decoupled resource/tool selection, servers could dynamically serve only the widget needed for the current step. This removes the scaling ceiling and enables richer MCP apps without hitting timeout or bandwidth limits.\n\n### Environment\n\nChatGPT developer mode, MCP Apps with Streamable HTTP, April 2026. Reproducible with any MCP app that has 3+ resource-bound tools.",
"title": "\"Runtime error\" on all resource widgets in developer mode"
}