io.modelcontextprotocol/ui extension — currently claude.ai web and Claude Desktop — render an embedded iframe on top of the tool’s normal JSON result. The same tools called from any other MCP host (Claude Code, Cursor, custom clients) return exactly the same JSON they always did. Interactive apps are purely additive.
Interactive apps are useful when:
- The tool returns visual data (canvases, brand colors, logos) that’s much easier to scan as a grid of thumbnails than as JSON
- The tool starts a long-running job whose progress benefits from a live view
- The user might want to take a follow-up action (search, set as default, remove) without round-tripping through the LLM
Available apps
How it works
Each tool’s result includes a_meta.ui.resourceUri pointing to a ui://moda/... HTML resource. Iframe-aware hosts fetch that resource, hand it the tool result, and render it next to (or in place of) the raw JSON. Apps can call back into the same MCP server via app.callServerTool(...) to refine results, paginate, or perform follow-up actions — those follow-up calls hit the same authenticated session as the originating tool call.
Non-interactive hosts
Hosts that don’t supportio.modelcontextprotocol/ui simply ignore the _meta.ui block and present the raw tool result as before. Every interactive feature has a non-interactive equivalent:
- The Design Task Progress iframe replaces an explicit
get_task_statuspolling loop. On non-interactive hosts, the host (or its LLM) pollsget_task_status(task_id)directly. - The “Set as default” button calls
set_default_brand_kit, which is also callable directly when a user explicitly asks to change their default. - The Remove button calls
remove_brand_kit_image, which is also directly callable.