Start with renderer ownership
The practical distinction starts with the renderer. A2UI gives the client a description to render, while an MCP App gives the host a web resource to run. That boundary determines who can change the layout, which components are available, where client state lives, how styling enters the surface, and what must be tested.
| A2UI surface | MCP App | A2UI delivered over MCP | |
|---|---|---|---|
| Interface definition | Declarative data against an agreed catalog | Developer-built HTML, CSS, and JavaScript resource | Declarative A2UI data carried through an MCP route |
| Renderer owner | Client or host application | Embedded web application, within host constraints | Client or host application |
| Visual implementation | Host-native components and theme mapping | Styles and components shipped with the web resource | Host-native components and theme mapping |
| Layout freedom | Bounded by schema and catalog | Broad web layout and interaction freedom | Bounded by schema and catalog |
| Required support | A2UI validation, renderer, catalog, and action routing | MCP App resource, compatible host, bridge, and sandbox policy | MCP transport plus explicit A2UI handling, validation, renderer, catalog, and action support |
| State burden | Application and renderer must define synchronization | Embedded app owns local UI state; server and host still own their respective state | Application must reconcile MCP results, A2UI updates, renderer state, and actions |
| Best default fit | Native summaries, bounded forms, and generated data views | Rich editors, bespoke dashboards, and complex local interaction | MCP-connected tools that need host-native declarative output |
MCP support is not UI support
A client that can call an MCP tool doesn't necessarily support MCP Apps, A2UI payloads, a particular component catalog, or the bridge required for nested patterns. Record each capability separately.
Security labels don't settle the choice. A declarative catalog limits what can be requested, but the application still has to validate messages, authorize actions, and protect data. An embedded iframe provides isolation boundaries, yet the host and application still have to govern permissions, messages, resources, and side effects. These architectures have different trust surfaces, not automatic security outcomes.
Protocol articles age quickly. On October 20, 2026, the first-party A2UI navigation identifies v0.9.1 as current, v1.0 as candidate, and v0.8 as legacy. A community article from December 2025 still describes v0.8 as preview. Both pages describe their own periods, but only the current first-party documentation should govern a current version decision.
| Governing evidence | Review trigger | |
|---|---|---|
| A2UI protocol version | First-party A2UI specification and navigation, captured with a date | Current version changes or the candidate becomes current |
| Combined architecture pattern | Current first-party implementation guide for A2UI and MCP Apps | Pattern, extension, or delivery contract changes |
| Host support | Named host documentation or a recorded test for the exact host version | Host release, policy change, or support-matrix change |
| Renderer and catalog coverage | Versioned renderer and catalog inventory in the consuming application | Renderer, schema, or catalog release |
| Practitioner recommendation | Dated secondary analysis with its assumptions preserved | Architecture, host, or product requirements change |
| Observed behavior | Executed evidence from the named surface and environment | Any dependency, policy, content, or environment change that can invalidate it |
Don't write that A2UI supports a host when the evidence only shows that the protocol can express the surface. Likewise, don't write that MCP supports an app when the client supports only tool calls. Record the protocol fact, host capability, local implementation, and observed result in separate fields.
Stable distinction, changing implementations
Renderer ownership is a durable architectural distinction. Version numbers, catalogs, extension details, and host support can change. A useful record keeps those two classes apart.
Choose per surface, not per product
One product can reasonably use A2UI for a generated summary, ordinary form, or native mobile result, then open an MCP App for a rich editor. Make the decision at the level of the smallest surface with one coherent interaction and consequence model.
| Preferred starting route | Reason and condition | |
|---|---|---|
| Native summary or status card | A2UI | Use when the catalog covers the content and the host should control presentation. |
| Generated table, chart, or bounded data view | A2UI | Use when the renderer has the required components and can reject unknown declarations safely. |
| Fixed data-entry form | Either | Choose A2UI for host-native fields; choose an MCP App when client logic, validation UX, or layout exceeds the catalog. |
| Bespoke dashboard | MCP App | Use when the developer must own layout, filtering, visualization behavior, and local state. |
| Rich editor or canvas | MCP App | A developer-owned web application usually fits complex direct manipulation better than a bounded catalog. |
| Mobile surface across native clients | A2UI | Prefer it only when each named client has a compatible renderer, catalog, and action route. |
| Approval for a consequential action | Either, with application-owned policy | The route can present the decision. It must not invent permission, approval state, or completion. |
| Mixed support workflow | Hybrid | Use a native summary for common work and an embedded editor for the exceptional complex step. |
Ask nine questions about each surface. Who owns the renderer? How variable is the layout? Does the catalog cover every required state? Where does client state live? Which hosts must work? What happens if the preferred route is unavailable? Who authorizes actions? Who controls release timing? What evidence is required before accepting the surface?
A protocol can carry or render an interface without owning the truth that the interface claims to show.
Keep the responsibility boundaries visible
A rendering choice isn't a complete application contract. A2UI doesn't supply your product policy. An MCP App doesn't gain authority because it displays a button. A design kit isn't a renderer or an accessibility result.
| Owner | Required evidence | |
|---|---|---|
| Data and tool result | Application or MCP server | Schema validation, provenance, error behavior, and current result state |
| Declarative interface | Agent or server within the A2UI contract | Valid payload, declared catalog version, and rejected unknowns |
| A2UI renderer and catalog | Client or host application | Component mapping, supported states, version, and representative render checks |
| Embedded web resource | MCP App developer | Resource version, bundle behavior, bridge messages, and failure handling |
| Host placement and lifecycle | Host | Supported display modes, permissions, resource lifecycle, and interruption behavior |
| Authorization and side effects | Application policy and system of record | Permission decision, approval evidence, dispatch result, and authoritative completion |
| Application state | Consuming application | Synchronization, conflict handling, persistence, and recovery evidence |
| Visual source | Design-system owner | Named tokens, typography, spacing, motifs, and precedence rules |
| Accessibility evaluation | Component and product teams within a recorded scope | Keyboard, focus, semantics, zoom, assistive-technology, and composition observations |
| Acceptance and retest | Named release owner | Expected behavior, observation, evidence reference, disposition, and trigger |
Accessibility needs particular care. Native components may provide useful platform behavior, while a web app may reuse mature accessible components. Neither fact proves that the composed surface works with its real labels, focus order, updates, errors, content, viewport, and host container. Evaluate the actual surface.
Give either route a coherent visual source
Once you've assigned renderer and application responsibilities, a design kit can supply the upstream tokens, typography, spacing, and usage rules that each implementation maps into its own components.
Treat hybrid routes as separate architectures
"Use both" is incomplete advice. The combined patterns documented by the Google A2UI Team and MCP Apps co-creators have different prerequisites. Test the exact arrangement instead of assuming the parts will compose automatically.
| Prerequisites | Reject or fall back when | |
|---|---|---|
| A2UI over an MCP server | MCP connectivity; explicit A2UI payload handling; compatible renderer; matching catalog; action routing | The host supports MCP tools but not A2UI rendering, the payload is unrecognized, or the catalog cannot satisfy it |
| MCP App inside an A2UI component | A2UI renderer; catalog component that can host the app; supported web resource; bridge; lifecycle and sizing policy | The catalog lacks the wrapper, the resource is unavailable, the host forbids embedding, or bridge initialization fails |
| A2UI inside an MCP App | Compatible MCP App host; embedded app resource; A2UI renderer inside the app; catalog; synchronized app and host state | The resource cannot load, the embedded renderer rejects the payload, or state and action routing cannot be reconciled |
| Separate surfaces in one workflow | Capability detection; explicit route boundary; shared application-state contract; deterministic handoff | Either surface is unsupported or the handoff would lose state, authority, or completion evidence |
Prefer the shallowest composition that meets the need
If an A2UI surface covers the task on its own, adding an embedded app creates another lifecycle and evidence boundary. If a developer-owned app already covers the task, nesting a renderer inside it needs a concrete benefit, such as reusable generated layouts.
Define fallback before shipping the preferred route
Fallback is product behavior. It isn't an exception message added after integration. It must preserve meaning, action safety, and recovery. The result may be less rich, but it must never imply that an unavailable control executed or an interrupted operation completed.
| Required behavior | Do not do | |
|---|---|---|
| Unsupported host | Use a declared alternate surface, a read-only structured result, or an authorized first-party route if one exists | Render an empty container or assume basic MCP support includes app UI support |
| Missing A2UI renderer | Reject the declarative surface and present the recorded non-A2UI fallback | Display raw payloads to end users as if they were an interface |
| Unknown catalog or component | Reject the affected declaration, preserve diagnostics, and use the bounded fallback | Substitute a visually similar component with different behavior |
| Invalid payload | Fail validation before rendering actions; record the invalid field and source | Partially render consequential controls from an untrusted remainder |
| Unavailable MCP App resource | Show a stable unavailable state with retry or an alternate route according to policy | Loop retries without a bound or report the underlying task as failed when only the view failed |
| Interrupted update | Preserve the last confirmed state, mark freshness, and offer a policy-approved recovery path | Merge partial updates into an apparently final result |
| Denied action | Keep the denial distinct from technical failure and show only permitted next steps | Retry under another identity or imply that approval exists |
| Incomplete outcome | Use runtime evidence to label the action pending, failed, cancelled, or unknown | Treat dispatch, UI closure, or a success-looking message as authoritative completion |
For consequential actions, the safe fallback may be read-only. If the alternate route can't preserve authorization, confirmation, idempotency, or authoritative completion, remove the action and explain which supported route is required. That's a controlled reduction in capability, not a hidden failure.
Copy the route decision record
The following record is a template. It hasn't been executed and makes no claim about host compatibility. Replace every bracketed value, verify the governing sources, and leave observations unresolved until someone runs the named checks.
record_type: agent_ui_route_decision
status: unexecuted
recorded_on: "[YYYY-MM-DD]"
owner: "[team or person]"
surface:
name: "[one named surface]"
user_task: "[task this surface must complete]"
consequence_class: "[informational | reversible | consequential]"
required_hosts:
- name: "[host]"
version: "[exact version]"
version_authority:
a2ui_version: "[version or not-applicable]"
a2ui_governing_source: "[first-party source and capture date]"
mcp_apps_contract: "[extension or host contract and version]"
host_support_source: "[named host source or unresolved]"
selected_route: "[a2ui | mcp-app | a2ui-over-mcp | mcp-app-in-a2ui | a2ui-in-mcp-app]"
renderer_owner: "[client | host | embedded app]"
renderer_version: "[version or unresolved]"
component_catalog: "[name and version or not-applicable]"
web_resource: "[resource identity and version or not-applicable]"
bridge: "[bridge and message contract or not-applicable]"
required_capabilities:
layout: "[requirement]"
client_state: "[requirement]"
actions: "[requirement]"
accessibility_scope: "[conditions to evaluate]"
action_authority:
policy_owner: "[application owner]"
permission_source: "[authoritative source]"
completion_source: "[authoritative runtime evidence]"
visual_source:
authority: "[design-system source and version]"
mapping_owner: "[renderer or app owner]"
fallback:
trigger: "[unsupported or failed capability]"
behavior: "[deterministic alternate behavior]"
prohibited_behavior: "[unsafe substitution or claim]"
rationale: "[why this route fits this surface]"
correction_owner: "[owner]"
review_triggers:
- "protocol or extension version changes"
- "host capability or policy changes"
- "renderer or catalog changes"
- "action policy or system-of-record behavior changes"
disposition: pending_executionA selected route is not an accepted implementation
Architecture approval records intent. Acceptance requires observations from the named host, surface, versions, states, and action paths. Keep those evidence states separate.
Record acceptance without inventing results
Write the expected behavior before testing. Add observations and evidence afterward. This keeps a plausible screenshot or successful tool dispatch from becoming false proof of authorization, completion, recovery, accessibility, or cross-host support.
record_type: agent_ui_surface_acceptance
status: unexecuted
route_decision_id: "[record identifier]"
surface: "[named surface]"
host: "[host and exact version]"
protocol_and_extension_versions: "[versions]"
renderer_and_catalog_versions: "[versions or not-applicable]"
resource_version: "[version or not-applicable]"
test_date: null
tester: null
cases:
- case: renders_required_content
expected: "All required content and controls render from the selected route."
observation: null
evidence_reference: null
- case: rejects_unknown_or_invalid_input
expected: "Unknown catalog entries or invalid resources fail through the declared rejection path."
observation: null
evidence_reference: null
- case: preserves_interaction_state
expected: "Required state survives updates, interruption, and route handoff according to the contract."
observation: null
evidence_reference: null
- case: enforces_permission
expected: "The application checks current authority before dispatching a consequential action."
observation: null
evidence_reference: null
- case: reports_completion_truthfully
expected: "Only authoritative runtime evidence marks an action complete."
observation: null
evidence_reference: null
- case: recovers_deterministically
expected: "Unsupported and failed capabilities use the recorded fallback without losing meaning."
observation: null
evidence_reference: null
- case: evaluates_accessibility_scope
expected: "The named keyboard, focus, semantics, zoom, update, and assistive-technology conditions are evaluated."
observation: null
evidence_reference: null
- case: preserves_visual_mapping
expected: "The rendered surface maps to the declared visual source without unauthorized local substitutions."
observation: null
evidence_reference: null
correction_owner: "[owner]"
retest_trigger: "[dependency, policy, host, renderer, catalog, or resource change]"
disposition: pending_executionBounded example: a support case
Consider a support workflow with two surfaces. One is a case summary showing customer-visible status, recent events, and recommended next steps. The other is a complex evidence editor with filters, attachments, annotations, and draft state.
- 1
Select A2UI for the summary
The host renderer can map a bounded summary, status labels, event rows, and ordinary next-step controls to approved native components. This is still a proposal until the exact host, renderer, catalog, and payload are tested.
- 2
Select an MCP App for the editor
The product team needs direct control over dense layout, attachment handling, local drafts, filtering, and annotation behavior. The host must support the app resource, bridge, lifecycle, and required permissions.
- 3
Keep action policy outside both views
The application decides whether a case may be escalated, who may send a response, and which system event proves completion. Neither the native button nor the embedded editor creates that authority.
- 4
Define the handoff
Opening the editor must carry the case identity and current version without treating the A2UI view as the source of truth. On return, the summary must refresh from authoritative state instead of trusting an optimistic local message.
- 5
Specify fallback
If A2UI is unsupported, show a structured read-only case result and the approved alternate route. If the editor resource is unavailable, preserve the summary and draft status without presenting edit or send controls.
- 6
Leave acceptance unresolved
Expected behavior can be written now. Rendering, bridge behavior, permissions, recovery, accessibility, and completion remain pending until tested in every named host.
Where a design kit fits
A visual system sits upstream of either route. For A2UI, the host can map semantic roles, typography, spacing, and component treatments into its native catalog. An MCP App can consume the same intent through its own CSS, tokens, and components. Shared visual input may reduce drift, but it doesn't erase the two rendering implementations or their separate verification work.
Token specimen · real values
Ambient Sage
Live renderAmbient Sage's actual tokens — the same values its exports use.
Ambient Sage is useful here because its public page exposes a coherent set of colors, typography, spacing, and usage direction. Its availability proves only that the source artifact can be inspected. It doesn't prove that an A2UI catalog maps those decisions, that an MCP App consumes them, that either route is accessible, or that a rendered surface is correct.
Identity Forge stops at the visual-system boundary
Identity Forge can provide DESIGN.md, semantic tokens, typography, spacing, layout direction, and export artifacts. The consuming team still owns protocol support, renderers, component implementations, host compatibility, authorization, application state, accessibility evaluation, and runtime verification.
Make one bounded decision now
Choose one representative surface with a real user task. Name every required host, then complete the route decision record before implementation. Define the fallback and expected evidence at the same time. Expand the architecture only after you've observed that surface in every named host and traced its action outcomes to authoritative runtime evidence.
Sources
- A2UI + MCP Apps: Combining the best of declarative and custom agentic UIs: The Google A2UI Team and MCP Apps co-creators describe three combined patterns, including A2UI delivered over MCP and arrangements that nest one UI mechanism inside the other.
- MCP Apps vs A2UI: Which Agent UI Standard Should You Use? (October 2026): This comparison distinguishes renderer ownership, host UI support, validation, application responsibilities, testing, and fallback for unsupported clients.
- How Does A2UI Compare?: The first-party A2UI documentation distinguishes declarative native rendering from sandboxed MCP App resources, documents their combined use, and lists v0.9.1 as current and v1.0 as candidate.
- MCP Apps and A2UI: The Two Architectures That Will Define Generative UI for Enterprise AI Agents: The Workday engineering analysis highlights approval, permission, audit, governance, and side-effect questions that remain application responsibilities.
- A2UI vs MCP Apps: Choosing the Right Protocol: This December 2025 community comparison labels A2UI v0.8 as preview, providing a historical example of why protocol comparisons need dates and governing sources.
- Ambient Sage Design Kit: The published Ambient Sage kit exposes an inspectable visual system with semantic colors, typography, spacing, and usage direction, but does not establish compatibility with either UI protocol.