You are reading Nightly documentation for 0.12.4.dev0+g50bde75.

This documentation may describe behavior that differs from Stable.

Open Stable documentation

Documentation version

0.12.4.dev0+g50bde75 · Nightly

MCP Apps

MCP Apps

MCP Apps turn a compatible tool result into an optional interactive view. Holaryn implements the
stable MCP Apps extension, io.modelcontextprotocol/ui version 2026-01-26, while treating every
server, resource, and bridge message as untrusted. The interactive view is an enhancement: the
text or structured tool result always remains available.

Enable and open an app

Approve the apps capability for a server in Settings → MCP, or add it to the server manifest:

approved_capabilities = ["tools", "prompts", "resources", "apps"]

This is an authority ceiling, not a trust declaration. A server may then advertise tool metadata
that references a ui:// resource. Holaryn records that reference during discovery but does not
fetch or execute it. After the tool finishes, the conversation shows an app card:

  • Load app fetches, validates, pins, and opens the exact resource.
  • Open as structure shows the bounded text or structured result without running scripts.
  • Inspect shows the server/tool identity, trust, resource URI, origin, requested permissions
    and network origins, integrity digest, size, and data sent/received.
  • Refresh pinned resource intentionally fetches a newer copy.
  • Close returns keyboard focus to the opener.
  • Revoke deletes the pinned resource and prevents the view from reopening.

If a pinned file disappears or is corrupt, the card becomes unavailable and the structured
fallback remains usable. Refresh is explicit; Holaryn never silently substitutes a changed resource.

The security boundary

An app never shares the Holaryn document origin. A trusted, fixed proxy runs on
mcp-app.localhost; the server-supplied HTML runs inside a second iframe with an opaque origin.
The inner frame has scripts but not allow-same-origin. It receives no cookies, bearer tokens,
provider credentials, local storage shared with Holaryn, parent DOM access, referrer, direct
filesystem access, clipboard access, popups, or top-level navigation.

Holaryn validates the source window, origin, app-session identifier, JSON shape, byte limit, and
monotonic action sequence on every bridge message. The resource CSP always denies objects, forms,
ancestors, base URLs, and navigation. Declared HTTPS origins and browser permissions are requests,
not grants; the host policy can only narrow them. This release grants no app network origin.

App-originated tool calls may target only the same MCP server and tools visible to app. They run
through the same consequence classification, approval prompt, canonical events, result bounds,
and error handling as model-originated calls. Opening a link, requesting a download, writing the
clipboard, selecting a file, or sharing data is a typed host action and is ask-first. Unsupported
or unavailable actions fail closed.

Accessibility and display

The app card and its host controls are semantic HTML with visible focus. They work at 200% zoom,
support reflow and high contrast through the normal Holaryn tokens, and honor reduced-motion
preferences. App-requested height is clamped. Because third-party app markup may not be accessible,
Open as structure is always available and does not rely on the app script.

Screen-reader users should inspect the identity and permissions before loading unfamiliar UI.
The structured fallback is the supported recovery path if a third-party app traps focus, fails to
initialize, or exposes inaccessible controls.

Developer contract

A server advertises the extension during initialization, places
_meta.ui.resourceUri (or the compatibility key _meta["ui/resourceUri"]) on a tool, and serves
that URI as text/html;profile=mcp-app. Tool visibility defaults to both model and app; use
_meta.ui.visibility to narrow it. Resource metadata may declare prefersBorder, CSP origins, and
browser permissions, but declarations never create host authority.

The host bridge uses JSON-RPC over postMessage via the official AppBridge package. It provides
theme, locale, timezone, bounded dimensions, tool input/result, resizing, follow-up tool calls,
links, downloads, messages, and model-context updates. Unknown methods, cross-server calls,
replayed sequences, malformed payloads, and oversized messages are rejected.

Use the repository fixture under tests/fixtures/mcp_apps/ and the checks in
docs/mcp-apps-a11y-checklist.md when developing or reviewing an app. The upstream protocol is
documented in the MCP Apps overview
and versioned specification.