"Runtime error" on all resource widgets in developer mode
@mstoiber
On every request the ChatGPT Client:
Calls
resources/list— discovers all resourcesCalls
resources/readfor every resource — sequentially, one by oneCalls
tools/list— discovers toolsCalls
tools/call— executes a tool, which references a singleresourceUriRenders one widget
Steps 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.
For 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).
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.
Requested
Lazy loading — fetch
resources/readafter a tool returnsresourceUri, not before. The tool result already specifies which widget to render — there’s no need to prefetch all of them speculatively.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.Decouple resources from tool selection — tool selection should be driven by
tools/listand tool descriptions, not by which resources are inresources/list. Servers should be able to filter resources without it affecting which tools ChatGPT decides to call.
Why this matters
The 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.
With 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.
Environment
ChatGPT developer mode, MCP Apps with Streamable HTTP, April 2026. Reproducible with any MCP app that has 3+ resource-bound tools.
Discussion in the ATmosphere