MCP Apps widgets stopped rendering after staged rollout of server/discover version negotiation (2.1.234)

Status Open
Reported on v2.1.234
Maintainer reply None cached
Activity 6 comments · opened Aug 20, 2026

Summary

All MCP Apps widgets/applets (tools with _meta.ui.resourceUri) from our MCP server stopped rendering in Claude Code mid-evening on 2026-08-20 — with no client update, no server change relevant to widgets. Evidence points to a staged server-side rollout activating the new server/discover version-negotiation probe, after which Claude Code appears to treat the server as having no app support.

Timeline (all times local, single machine, CC 2.1.234 installed Aug 18)

  • ~21:55 — MCP Apps widgets from our server render fine (as they had for weeks).
  • ~22:00-22:40 — no client update (binary unchanged since Aug 18), no relevant server deploy.
  • 22:44 onward — zero widgets render for any tool of this server, in every new session. Tool calls succeed; the model receives results; the host renders no applet.
  • Server logs show Claude Code sending server/discover (a method our MCP Python SDK 1.28.x does not know) — the request dies in a pydantic validation cascade:

``
ReadResourceRequest.method
Input should be 'resources/read' [type=literal_error, input_value='server/discover', ...]
...params: {'_meta': {'io.modelcontextprotocol/...'}, 'elicitation': {}}
``

  • We then implemented server/discover per the 2026-07-28 draft spec (response verified against the published mcp-2.0.0 / mcp_types-2.0.0 wheels: supportedVersions [honest 1.x list: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05], live-derived capabilities, instructions, resultType: complete, cacheScope: private). Claude Code now receives a valid answer (confirmed in logs) — widgets still do not render.

Evidence it's a staged client-side gate

  • strings on the CC binary: server/discover is present in 2.1.222 (Aug 5), 2.1.233, 2.1.234 — dormant for weeks, activated tonight ⇒ server-side flag.
  • Binary strings show the machinery: "Version negotiation probe timed out after", "legacy"/"modern", "Version negotiation failed: the server did not offer pinned protocol version ... via server/discover (no fallback in pin mode)".
  • The identical widgets (same _meta.ui declarations, same ui:// templates) render correctly in ChatGPT's MCP Apps host right now — the server side is spec-conformant.

Questions

  1. Is MCP Apps widget rendering now gated on server/discover results (e.g., a capabilities.extensions declaration)? If so, what must a server on the 1.x Python SDK return to keep widgets rendering?
  2. Is there an env var / setting to pin the protocol version or disable the new negotiation as a temporary workaround?
  3. If a server answers server/discover without offering the 2026-07-28 version (because its SDK is 1.x), is falling back to legacy widget behavior intended? It appears widgets are dropped entirely instead.

Environment

  • Claude Code 2.1.234 (macOS, installed Aug 18; issue began mid-day Aug 20 with no update)
  • MCP server: Python SDK 1.28.1, streamable HTTP, OAuth; tools declare _meta: {"ui": {"resourceUri": "ui://...", "visibility": ["model","app"]}}
  • Reproduces in fresh sessions, both via a local stdio proxy and characteristic of the server generally.

View original on GitHub ↗

6 Comments

liran-ws · 10 days ago

Update after deeper forensics — the trigger correlates to the minute with a remote-config push, and my original server/discover theory is falsified (probes were arriving at the same rate for 2+ days while widgets rendered fine).

New timeline evidence (same machine, CC 2.1.234):

  • ~21:30 local: MCP Apps widget frames from our server still MOUNT in Claude Code.
  • 22:43:06 local: ~/.claude/remote-settings.json is written — content {"channelsEnabled": true} (a server-pushed settings fetch).
  • 22:44 local: first failing test — and from that point NO MCP Apps widget from this server mounts in any fresh session (tools succeed, results arrive, no applet).
  • Server-side changes in that window were prompt-copy-only; an earlier experimental tool-_meta key was fully reverted with no recovery, ruling it out.

So the regression appears tied to the channels feature enablement via remote settings, not to MCP protocol negotiation. Will report back whether locally forcing channelsEnabled: false restores widget rendering.

liran-ws · 10 days ago

Definitive root cause identified: the Claude Desktop app's EMBEDDED claude-code runtime auto-updated to 2.1.234 at 12:13 local on 2026-08-20 — MCP Apps widget rendering died at exactly that boundary.

Corrected facts (supersedes my previous comments — the channels remote-setting was a red herring; widgets were already broken by 22:43):

  • The affected sessions run in the Claude Desktop app (shell 1.32885.1, unchanged since Aug 18), which executes an embedded claude-code runtime under ~/Library/Application Support/Claude/claude-code/.
  • That directory shows 2.1.234 installed at 12:13 on Aug 20 (the previous embedded version was removed in the same minute — Claude Extensions dir touched at 12:13 too).
  • Widgets rendered fine all morning; every session after 12:13 renders NO MCP Apps widget from the same server (tool calls succeed; results arrive; no applet mounts). Reproduced across many fresh sessions.
  • Server-side exonerated by repeated falsification: identical widgets render in another MCP Apps host (ChatGPT) right now; tool _meta.ui byte-stable; templates parse-clean; negotiated protocol identical before/after (protocolEra: legacy, negotiatedProtocolVersion: 2025-11-25 in the app's own mcp logs); connecting the same server under a fresh name changes nothing.
  • No local rollback possible — the updater deleted the prior embedded bundle.

So: embedded runtime ≤2.1.23x + Desktop shell 1.32885.1 rendered MCP Apps; embedded 2.1.234 + same shell does not. Happy to run diagnostics on request; this currently breaks all MCP Apps servers for Desktop users on that runtime.

liran-ws · 10 days ago

Additional finding, same machine/runtime: the Claude Desktop app also silently auto-declines MCP elicitation requests (elicitation/create gets a result with action≠accept immediately, no UI ever shown to the user). Proven by differential test: driving the same MCP server chain programmatically with a client that answers the elicitation → the full round-trip works perfectly; through the Desktop app → instant non-accept, nothing rendered. So on the current Desktop embedded runtime (2.1.234, installed 12:13 Aug 20): MCP Apps widgets don't mount AND elicitation prompts are auto-declined — both interactive MCP surfaces are dark. Terminal Claude Code elicitation appears unaffected.

liran-ws · 10 days ago

Final root cause, with the exact gate: MCP-Apps rendering in Claude Desktop is behind the epitaxyMcpApps feature gate, and it went dark for this account in the Aug 20 ~06:07 shell hot-update (app.asar mtime) — not anything server-side.

Complete evidence chain:

  • The server side is byte-verified correct at every layer, validated against Anthropic's own rendering PDF extension: tool _meta carries BOTH the nested ui.resourceUri and the flat ui/resourceUri key (we added the flat key after extracting it from your extension's SDK shim); ui:// resources listed and readable with text/html;profile=mcp-app; the full tools/resources chain verified over the exact stdio transport the host uses. The host's own detector (app.asar: t?.ui?.resourceUri ?? t?.['ui/resourceUri']) matches our meta.
  • app.asar contains the gate map: epitaxyMcpApps resolved via a statsig lookup with a hardcoded {status: 'unavailable'} fallback (and maturity: 'beta' in an adjacent context). The asar hot-updated 2026-08-20 06:07 local; the user's last confirmed widget render was that morning; every session since renders no MCP-Apps widget from any custom MCP server, while your own directory PDF extension still renders (apparently via a different path).
  • Earlier suspects are all falsified with evidence: server/discover (probe traffic constant across working/broken days), channelsEnabled remote push, embedded-runtime bumps (2.1.234→2.1.235 mid-debug — no effect), server identity, tool-meta shapes.

Ask: was epitaxyMcpApps ramped down / re-bucketed around Aug 20? This silently kills all custom-server MCP Apps for affected Desktop users while directory extensions keep rendering — very hard to debug from the outside (this took ~6 hours of byte-level forensics). A visible state (like the connector card saying 'apps disabled') would help enormously.

liran-ws · 10 days ago

SOLVED — actual root cause, confirmed by fix: the Aug-20 Claude Desktop shell update gates MCP-Apps widget rendering on the extension's install source. "source": "registry" extensions render; "source": "local" (unpublished .mcpb) extensions silently fall back to text-only — no error, no log line, no UI indication.

Proof: flipping the single field source: local → registry in ~/Library/Application Support/Claude/extensions-installations.json for our extension instantly restored all widget rendering, with zero server-side changes. Both extension classes report signatureInfo: unsigned, so it is the source field, not signing.

Everything else in this thread was noise from Anthropic's continuous rollout machinery (runtime bumps, remote-settings pushes, discovery probes) coinciding with the real change. Two asks:

  1. Make this state visible — the extension card should say 'interactive widgets disabled for locally-installed extensions', instead of silently degrading. This cost us a full night of byte-level forensics.
  2. Provide a legitimate local-developer affordance — a 'trust this extension's widgets' toggle or a dev-mode flag — so MCP Apps development doesn't require directory publication or editing installation records by hand.
liran-ws · 10 days ago

Corrected root-cause update (supersedes my earlier analysis in this issue):

Two stacked regressions from the 2026-08-20 desktop update (1.34493.0 / embedded CC 2.1.235):

  1. epitaxyMcpApps feature gate flapping. Code-tab MCP-Apps rendering is gated on a server-evaluated feature (GrowthBook id 3516166472, fetched from /api/desktop/features, cached in the fcache file). It shipped OFF/flapping with the update and came back on ~2026-08-21T01:00Z. During that window every applet appeared 'silently text-only' with zero client-side indication — the visible-degradation-state ask from my original report stands.
  1. Local-stdio widget mounts are dead in the Code tab (still live). With the gate ON, the ccd surface mounts widget iframes only for claude.ai-connector-backed MCP servers. Local stdio servers' widgets never mount. Cleanest repro, using only Anthropic components: in one Code-tab session, (a) the bundled pdf-viewer plugin fails twice with 'Viewer never connected for viewUUID … iframe likely failed to mount', while (b) the same tool-shape served through a claude.ai custom connector renders perfectly. Our own server shows the identical split (bridge-stdio = no mount; connector = renders). Chat tab and claude.ai web are unaffected.

Also confirmed while bisecting, in case it saves someone a night: tool results without the FastMCP structuredContent mirror sent the epitaxy frame into a RenderLoopDetector mount loop ('20 renders in 1000ms'), and _meta["anthropic/alwaysLoad"] correctly exempts a tool from ToolSearch deferral but has no effect on widget mounting.

Asks: (1) restore (or document) widget mounting for local stdio MCP servers in the Code tab — your own pdf-viewer plugin is broken by it; (2) the original ask: a visible state when apps rendering is gate-disabled instead of silent text fallback.