{
  "$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"
}