modelcontextprotocol / modelcontextprotocol/ext-apps
Claude iOS: template renders but host delivers no lifecycle notifications to MCP App iframes (tool-input, tool-result, size-changed all absent)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.9k
- Forks
- 387
- Avg merge
- 3h 21m
- Merged PRs (30d)
- 6
Description
Environment: Claude iOS app (2026-07-30, Opus 5), remote MCP server via custom OAuth connector. Server: @modelcontextprotocol/ext-apps@1.7.5, @modelcontextprotocol/sdk@1.30.0, Streamable HTTP (stateless per-request). Tool registered with registerAppTool + _meta.ui.resourceUri; single-file HTML template with a version stamp in the footer so screenshots identify exactly which template version a host rendered.
Observed (4 instrumented live test rounds, template versions v1.2.0 → v1.4.0):
- The
ui://template loads and renders — chrome, inputs, buttons, and our version stamp are all visible, so resource fetch + iframe mount work on iOS. ui/notifications/tool-resultis never delivered. The app registersontoolresultbeforeconnect()per SDK guidance; the handler never fires. The same template receives it on Claude Desktop (when Desktop renders at all — see #671).ui/notifications/tool-inputis never delivered either — instrumented separately from v1.3.0 onward.ui/notifications/size-changedfrom the app is ignored — the iframe stays at a short initial height, clipping content (andMcpUiResourceMetaoffers no initial-size hint, so servers have no workaround).- iframe-initiated
tools/callviacallServerToolalso appears non-functional in our v1.4.0 polling fallback, though we have less instrumentation certainty here than for 2–4.
Impact: any tool-result-driven interactive UI is non-functional on Claude iOS — the card renders as permanent chrome with no data and no working actions. We shipped a full accept/regenerate image-review card and had to park it. The workaround that works everywhere is putting next-step instructions in the tool result text and letting the model execute follow-ups conversationally.
Expected: per SEP-1865, the host delivers tool lifecycle notifications to the view after ui/initialize completes.
Repro: any registerAppTool sample whose ontoolresult handler displays received data — on iOS the handler never fires, while the same server renders end-to-end in the basic-host harness and MCPJam. Happy to share our server URL, template source, and timestamped screenshots on request.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with a registerAppTool sample and the ui/initialize lifecycle, then compare notification delivery in Claude iOS with the basic-host harness and MCPJam. Verify whether tool-input, tool-result, and size-changed events reach the iframe, and determine whether the issue is fixable in ext-apps or is a host incompatibility.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100