MCP Apps: client stopped issuing resources/read; ui:// widgets don't mount (regression in 3.9.16)

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Since Cursor 3.9.16, MCP Apps UI widgets (SEP-1865 — HTML resources served at
ui:// URIs) no longer render inline. The client declares the
io.modelcontextprotocol/ui capability and lists the resource, but never issues
the resources/read call needed to fetch the widget HTML, so the tool result
falls back to raw text/JSON instead of mounting the widget.

I bisected this to an exact release: it works through 3.9.8 and is broken from
3.9.16 onward (details + protocol traces in Additional Information below).

Notes:

  • The client still DECLARES io.modelcontextprotocol/ui and lists the resource;
    it just never reads it.
  • Transport- and mechanism-independent (see Additional Information).
  • Distinct from the known “_meta stripped from ui/notifications/tool-result”
    issue, which presupposes the widget already mounted — this fails one step earlier.

Steps to Reproduce

  1. Run a minimal MCP server (@modelcontextprotocol/sdk + @modelcontextprotocol/
    ext-apps) that registers:
    • one ui:// HTML resource (registerAppResource), and
    • one tool that links that resource via tool-definition _meta.ui.resourceUri
      (registerAppTool).
  2. Connect it to Cursor and, in a chat, call the tool.
  3. Observe the MCP server’s inbound JSON-RPC log.

Result: the server receives initialize → tools/list → resources/list →
tools/call, but NO resources/read — so the widget never mounts and the result
renders as raw text.

Each version below was tested in an isolated profile (–user-data-dir /
–extensions-dir), confirmed by its About dialog, against the same server.

Expected Behavior

The client fetches the linked resource (sends resources/read for the ui:// URI)
and mounts the returned HTML inline as an MCP App widget — the behavior in
Cursor 3.9.8 and earlier.

Operating System

MacOS

Version Information

Version: 3.10.20
VS Code Extension API: 1.125.0
Commit: 23b9fb205fe595ea2be29da7214e19762d037fc0
Date: 2026-07-07T07:03:33.071Z
Layout: Agent Window
Build Type: Stable
Release Track: Default
Electron: 40.10.3
Chromium: 144.0.7559.236
Node.js: 24.15.0
V8: 14.4.258.32-electron.0
xterm.js: 6.1.0-beta.256
OS: Darwin arm64 24.6.0

For AI issues: which model did you use?

Opus 4.8

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey there! Thanks for the report. The JSON-RPC traces and per-version isolation testing made this quick to dig into.

Two things up front: this isn’t a code regression, and it’s not your server or config. We compared the widget render path across 3.9.8, 3.9.16, and 3.10.20 and it’s unchanged, so the bisect isn’t pointing at a code change you can work around. resources/read never fires because the inline MCP Apps widget rendering isn’t currently active for your session. That’s controlled on our end (not toggleable on yours), which is also why the result falls back to text. Same root cause as this thread.

Two quick things that’d help us pin it down, if you don’t mind:

  1. Does the widget fail to mount on every tool call, or does it sometimes render?
  2. Does a window reload (Cmd+Shift+P → “Developer: Reload Window”) or toggling the MCP server off/on in settings ever make it appear? (If it does, that’s also a stop-gap for you.)

I’m tracking this internally and will update here when there’s progress.

  1. It hasn’t popped up again since the upgrade.

  2. Reloading the window doesn’t seem to do anything to show it.

Seems like we’ll just have to wait until widely available

Thanks Mohit!

  1. Every call vs. sometimes: I can’t answer this well from the bisect (too few calls). In normal use on 3.10.20 I haven’t seen it render at all, which is what kicked off the investigation. Happy to run a batch of repeated calls on 3.10.20 if a clean “N calls, M mounts” number would help.

  2. Reload / toggle: reconnecting the MCP server didn’t make it appear in my runs, but I didn’t do a rigorous reload-then-retry loop, so I wouldn’t call that conclusive either. I can test that specifically if useful.