Skip to content

Claude iOS: template renders but host delivers no lifecycle notifications to MCP App iframes (tool-input, tool-result, size-changed all absent) #734

Description

@bennewton999

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):

  1. The ui:// template loads and renders — chrome, inputs, buttons, and our version stamp are all visible, so resource fetch + iframe mount work on iOS.
  2. ui/notifications/tool-result is never delivered. The app registers ontoolresult before connect() per SDK guidance; the handler never fires. The same template receives it on Claude Desktop (when Desktop renders at all — see Bug Report: MCP Apps UI Resource Not Rendering in Claude Desktop / claude.ai #671).
  3. ui/notifications/tool-input is never delivered either — instrumented separately from v1.3.0 onward.
  4. ui/notifications/size-changed from the app is ignored — the iframe stays at a short initial height, clipping content (and McpUiResourceMeta offers no initial-size hint, so servers have no workaround).
  5. iframe-initiated tools/call via callServerTool also 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions