The Model Context Protocol (MCP) and A2UI address complementary problems: MCP standardises how clients discover and call agent capabilities; A2UI standardises how agents describe rich, interactive user interfaces. Together they let a single MCP server deliver both the logic and the UI for an experience, with the client knowing exactly how to render each piece. This guide covers all three integration directions — serving A2UI from an MCP server, embedding A2UI renderers inside MCP Apps, and hosting sandboxed MCP Apps inside an A2UI surface.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/a2ui-project/a2ui/llms.txt
Use this file to discover all available pages before exploring further.
A2UI over MCP
Return A2UI JSON from MCP tools and resources so any A2UI-capable client can render rich UI.
A2UI in MCP Apps
Use A2UI inside a sandboxed MCP App for consistent, agent-controlled UI styling.
MCP Apps in A2UI Surfaces
Host third-party HTML-based MCP Apps securely inside an A2UI-rendered page.
Agent SDK
Use the SDK for schema management, validation, and prompt generation in any of these patterns.
A2UI over MCP
An MCP server can deliver A2UI content through two mechanisms: Resources for static UI that does not depend on runtime parameters, and Tools for dynamic UI generated from conversational context or live data. In both cases the client identifies the payload by its MIME type —application/a2ui+json — and routes it to an A2UI renderer.
Regardless of whether a payload arrives as a direct Resource read or inside a Tool’s
CallToolResult, the MIME type must always be application/a2ui+json. This uniform identification allows client middleware to intercept and route both static and dynamic responses identically.Quick start — run the sample
The A2UI repository includes a ready-to-run MCP recipe demo:- MCP Inspector
- Web App Client
In a separate terminal, launch the MCP Inspector:
- Set Transport Type to
SSE - Connect to
http://localhost:8000/sse - Click List Resources → you will see the “Recipe Form” resource
- Read
a2ui://recipe-form→ the content is the A2UI JSON for a static selection form - Click List Tools → you will see
get_recipe_a2ui - Run the tool → the response contains A2UI JSON that renders a dynamic recipe card
Resources vs. Tools
MCP Resource (resources/read) | MCP Tool (tools/call) | |
|---|---|---|
| Best for | Static forms, settings screens, stable layouts | Dynamic content driven by user input, live data, or conversation history |
| Trigger | Client reads a URI (e.g., a2ui://recipe-form) | Client or agent calls a named tool with arguments |
| Overhead | Minimal — no LLM call required | Higher — the server generates content at call time |
| Wrapping | Raw ResourceContents with mimeType | EmbeddedResource inside CallToolResult |
Serving static UI via Resources
Serving dynamic UI via Tools
Always include aTextContent fallback alongside the EmbeddedResource — clients that do not support A2UI will display the text rather than dropping the response silently.
Catalog Negotiation
Before a server can send A2UI to a client, they must agree on which component catalogs are supported. There are two approaches depending on whether your server is stateful or stateless.- During Initialization (Recommended)
- Per-Message Metadata (Stateless Servers)
MCP is a stateful session protocol. Declare A2UI support once during connection setup — the server stores the capabilities for the entire session:
Handling User Actions
Interactive A2UI components route user interactions back to the server as MCP tool calls.Define a button with an action
In your A2UI JSON, attach an
action object to any interactive component. The context maps human-readable keys to JSON Pointer data-binding paths:Client sends the action as a tool call
When the user clicks the button, the client resolves the data bindings against the current surface state and sends a standard MCP
tools/call:Error Handling
Clients can report A2UI rendering errors back to the server via a dedicated tool call, giving the server a chance to log the error, retry, or send a fallback UI:Verbalization and Visibility Control
MCP Resource Annotations control whether the LLM can “read” A2UI payloads in subsequent turns:| Audience | Behavior |
|---|---|
| (empty) | Visible to both user and LLM |
["user"] | Rendered for the user; hidden from LLM context |
["assistant"] | Available to LLM for follow-up reasoning; not rendered for the user |
Using the Agent SDK for Validation
For production deployments, the A2UI Agent SDK handles schema management, validation, and prompt generation:A2UI in MCP Apps
MCP Apps are sandboxed web applications that an MCP server delivers to a host client. By including the A2UI SDK inside your MCP App bundle, you can have those sandboxed applications render agent-generated UI with the same fidelity and consistency as a native A2UI surface.Architecture
Three actors collaborate through a layered communication chain:Loading A2UI components in your MCP App
Inline your app bundle
MCP Apps are delivered as a single HTML resource from the MCP Server. Build your application and use a post-build script or a Vite plugin to inline all JavaScript and CSS into a single self-contained file:
Fetch A2UI data via the host bridge
Inside your inlined app, use JSON-RPC over
postMessage to request A2UI payloads from the MCP Server:Inlined MCP App HTML structure
The following pseudocode shows the structure of a compiled, inlined MCP Application that initialises the App Bridge, fetches its initial A2UI layout, and handles interactive events:MCP Apps in A2UI Surfaces
This pattern is the inverse of the previous one: instead of an MCP App that contains A2UI, here A2UI is the outer surface and it hosts untrusted MCP Apps as sandboxed widgets alongside native A2UI components.The double-iframe isolation model
Running untrusted third-party HTML inside a host application requires strict isolation. A2UI uses a double-iframe pattern to achieve this without compromising the host application:Why two iframes?
Why two iframes?
A single iframe with
allow-scripts and allow-same-origin can escape its sandbox — the app can programmatically interact with the parent DOM or remove its own sandbox attribute. By strictly omitting allow-same-origin from the inner iframe, A2UI prevents all DOM-level escape vectors. The inner iframe gets a unique opaque origin, losing access to localStorage, sessionStorage, IndexedDB, and cookies. All communication happens exclusively through the structured JSON-RPC postMessage channel.Security guarantees
| Constraint | Effect |
|---|---|
No allow-same-origin | Inner app cannot access host DOM or storage |
| Unique opaque origin | Cookies, IndexedDB, and Web Storage are isolated per app instance |
| Explicit source validation | Incoming messages are validated against window.parent, not by origin string (which is "null" in the sandbox) |
| No direct sibling access | Sandboxed components cannot communicate directly with native A2UI siblings — all state flows through the host shell |
Registering the McpApp component
The McpApp component is a custom node in your A2UI catalog. Register it in your client application before rendering:
Using the McpApp component in A2UI messages
An agent or server sends a standard A2UI message that references McpApp as a custom component:
How the sibling update loop works
When a sandboxed MCP App needs to update state shared with native A2UI components (such as a scoreboard alongside a Pong game), the update must flow through the host shell rather than directly between siblings:Initialize postMessage bridge
The host shell instantiates the double-iframe sandbox and establishes a secure message relay bridge with the
McpApp component.Tool action request
When the user interacts inside the sandboxed app, the app triggers a tool action by posting a JSON-RPC message over the bridge.
Action delegation
The host layout engine intercepts the action and delegates it to the A2UI backend agent over the A2A protocol. The agent may also coordinate with the MCP App Server if needed.
State mutation and sync
The agent processes the action, mutates the session state, and pushes a
dataModelUpdate back to the host state manager.Running the sample apps
The A2UI repository includes two sample applications that demonstrate this pattern.Sample 1: MCP App Standalone (Lit + ADK)
Sample 1: MCP App Standalone (Lit + ADK)
Terminal 1 — start the agent:Terminal 2 — start the client:Open
http://localhost:5173. Clicking Call Agent Tool inside the sandboxed iframe triggers an action handled by the ADK agent.Sample 2: Calculator + Pong (Angular + MCP Server + Proxy Agent)
Sample 2: Calculator + Pong (Angular + MCP Server + Proxy Agent)
This sample requires three concurrent processes.Terminal 1 — MCP server:Terminal 2 — proxy agent:Terminal 3 — Angular client:Navigate to
http://localhost:4200/?disable_security_self_test=true. Use the smart chips to load the Calculator or Pong app in their sandboxed iframes.Troubleshooting
| Problem | Solution |
|---|---|
GEMINI_API_KEY not set | Export the key or create a .env file in the agent directory |
yarn build:renderer fails | Run yarn install first in samples/client/lit/ |
| Angular client shows a blank page | Ensure you ran yarn build:all at the repo root before starting |
| MCP app iframe does not load | Confirm both the MCP server (port 8000) and proxy agent (port 10006) are running |
| Security self-test fails in dev | Append ?disable_security_self_test=true to the URL |
ng serve not found | Run yarn install to install dev dependencies including @angular/cli |
Next Steps
Agent Development Guide
Build a full restaurant-finder agent that generates A2UI JSON using ADK and the Agent SDK.
Agent SDK Architecture
Understand the SDK’s streaming parser, validator, and catalog system in depth.