MCP vs A2A vs A2UI: A System Design Guide for AI Agent Architectures

Quick answer

Use MCP when an AI host needs tools, resources, or prompts from a capability server; A2A when one independent agent delegates a task to another; and A2UI when an agent must describe a safe, native interface for a user. They solve different boundaries and often belong in one architecture rather than competing.

MCP, A2A, and A2UI are not three substitutes for the same job. MCP connects an AI host to capabilities, A2A connects independent agents to each other, and A2UI connects an agent's output to a trusted UI renderer. Choose the protocol by the boundary and lifecycle you need. If your architecture contains all three relationships, using all three can be correct; if it contains none, an ordinary function call, API, event, or fixed frontend is simpler.

That distinction is the fastest way to answer “MCP vs A2A vs A2UI” in a design review or system design interview. The rest of this guide turns it into an implementation decision.

MCP vs A2A vs A2UI in one table

QuestionMCPA2AA2UI
Primary boundaryAI host or client ↔ capability serverClient agent ↔ independent remote agentAgent or server → client renderer
What crosses it?Tool calls, resources, prompts, elicitationMessages, tasks, status updates, artifactsDeclarative surfaces, components, data, actions
Unit of delegationA named capability with a schemaA goal handled by an opaque agentA UI description rendered from an approved catalog
Who owns orchestration?The MCP hostEach agent owns its side of the task contractThe host owns rendering and component behavior
DiscoveryServer features and capability discoveryAgent Card with skills and supported interfacesCatalog and renderer capabilities through the carrier transport
Long-running workKeep application state outside the core request; use negotiated extensions where neededNative task lifecycle with polling, streaming, or pushProgressive UI updates; transport owns delivery and return channel
Best fitTools, enterprise data, reusable context integrationsCross-team, cross-vendor, or separately deployed specialist agentsDynamic forms, approvals, cards, and workflows that must look native
Usually wrong whenYou need an autonomous peer to own a goalYou only need a function or tool call in one processThe UI is fixed and can be coded normally

The protocols can carry or complement one another. For example, A2UI can travel inside an A2A message part or an MCP result. That does not collapse their roles: the carrier still handles delivery, while A2UI defines what the client renders.

Decision tree for choosing MCP for host-to-capability access, A2A for agent-to-agent goal delegation, A2UI for agent-described native interfaces, or a simpler API when no protocol boundary exists

Start with the relationship that crosses a deployment or trust boundary. A single request can follow multiple branches as it moves through the system.

The mental model: tools, teammates, and interfaces

A useful shorthand is:

User ← A2UI → host agent ← A2A → specialist agent
                    │                       │
                    └──── MCP → tools       └──── MCP → tools
  • MCP is for capabilities. The caller chooses a named tool, resource, or prompt and remains responsible for the larger workflow.
  • A2A is for collaborators. The caller delegates an outcome and the remote agent may plan, ask for more input, call its own tools, and return artifacts.
  • A2UI is for presentation and interaction. The agent describes a surface; the client maps that description onto trusted native components.

This is an architectural model, not a claim that every deployment needs an “agent protocol stack.” Protocols pay for interoperability across a boundary. Inside one service, typed functions and queues are often the better design.

What is MCP, and when should you use it?

The Model Context Protocol (MCP) standardizes how an AI application connects to servers that expose tools, resources, and prompts. The host retains control of model selection, conversation state, approvals, and orchestration; the server provides bounded capabilities with machine-readable contracts.

Use MCP when you want multiple AI hosts to reuse the same integration, or one host to connect to many capability servers without inventing a new tool API for each. Typical examples include reading a code repository, querying a catalog, looking up an incident, or submitting an approved change.

The current MCP 2026-07-28 specification uses stateless, self-contained requests with per-request capability negotiation. Servers can expose tools, resources, and prompts; clients can support elicitation. That core is a good fit for horizontally scaled capability services, while durable workflow state still belongs in your application or a negotiated extension.

MCP is the right choice when

  • the operation has a stable name and input/output schema;
  • the caller, not the server, owns the end-to-end plan;
  • the server should expose data or an action without revealing its internals;
  • multiple hosts should discover and invoke the same integration; or
  • you need a consistent consent and policy boundary around tool execution.

MCP is not enough when

An MCP server can contain sophisticated logic, but the protocol contract is still capability-oriented. If the remote system must accept a broad goal, manage a multi-turn task, publish progress, request clarification, and return one or more artifacts, treating it as one enormous run_agent tool hides the lifecycle you actually need. That is where A2A is the clearer boundary.

For a deeper implementation treatment, including tenant isolation and token exchange, see the secure multi-tenant MCP gateway system design.

What is A2A, and when should you use it?

The Agent2Agent (A2A) Protocol standardizes collaboration between independent, potentially opaque agent systems. A client discovers a remote agent through an Agent Card, selects a supported interface, sends a message, and may receive a short response or a stateful task whose progress is polled, streamed, or pushed.

The current A2A 1.0 specification defines a canonical data model for tasks, messages, artifacts, parts, Agent Cards, and extensions. It maps those semantics to JSON-RPC, gRPC, and HTTP/REST bindings. The opacity is intentional: the remote agent advertises skills and output modes, not its chain of thought, private memory, or internal tools.

A2A is the right choice when

  • the remote party owns how a goal is achieved;
  • the agent is independently deployed, versioned, or operated;
  • work can outlive one HTTP request or require more user input;
  • clients need task status, cancellation, streaming, or artifacts; or
  • different vendors or frameworks must interoperate without sharing internals.

An example is an incident coordinator delegating “diagnose the checkout latency regression” to a database specialist. The coordinator should not need to know which queries, models, or MCP tools the specialist uses. It needs a task contract, progress, a bounded deadline, and a diagnosis artifact.

Do not use A2A merely because there are two agents

Two model calls inside the same codebase do not automatically justify A2A. If one process owns both, a typed function or internal job queue is easier to test, trace, and change atomically. A2A earns its cost when the second agent is a real interoperability boundary: separate ownership, deployment, trust, lifecycle, or technology.

What is A2UI, and when should you use it?

A2UI (Agent to UI) is a declarative, streaming format for agent-generated interfaces. An agent sends JSON messages such as createSurface, updateComponents, and updateDataModel. The client validates them against a known catalog and renders its own React, Angular, Flutter, Lit, or other native components. The agent sends a blueprint, not arbitrary JavaScript.

The A2UI 0.9.1 specification is the current production release as of August 3, 2026. It is transport-agnostic: A2A, MCP, AG-UI, SSE, WebSockets, or another ordered message channel can carry the envelopes. Interactive surfaces also need a return channel for user actions.

A2UI is the right choice when

  • the agent must choose or update the UI structure at runtime;
  • the host must keep its design system, accessibility behavior, and native feel;
  • the same intent should render across web, mobile, or desktop clients;
  • progressive rendering matters; or
  • a remote agent must present forms, approvals, cards, or workflow state without shipping executable UI code.

Declarative does not mean trusted

The renderer must reject unknown components, functions, and catalogs. It must also bound tree size and update frequency, sanitize Markdown and URLs, prevent duplicate IDs, preserve message order, and verify agent attribution. A button named approve_refund is only a user event; the server must still authenticate the user, authorize the exact action, check freshness, and enforce idempotency.

For comparison, MCP Apps let an MCP server provide a pre-built HTML interface that runs in a sandboxed iframe. MCP Apps favor server-owned web experiences. A2UI favors host-rendered, cross-platform components that inherit the client's design system. They can also be composed when a trusted A2UI catalog deliberately includes a sandboxed app component.

Are MCP, A2A, and A2UI competitors?

Mostly no. They overlap at delivery seams, not at their central abstractions.

An A2A agent may expose an A2UI artifact. An MCP tool or resource may return an A2UI payload. An A2A agent may call several MCP servers while completing its task. The design remains understandable if each protocol has one job:

  1. A2A owns remote task semantics.
  2. MCP owns capability discovery and invocation.
  3. A2UI owns the declarative UI contract.

Problems start when one protocol is stretched to hide another lifecycle: a generic MCP tool that secretly runs an unbounded agent, an A2A task used as a low-latency database RPC, or an A2UI action treated as authorization.

A production architecture that uses all three

Consider an incident-response assistant for a multi-tenant commerce platform:

  1. An engineer asks the host agent to investigate checkout latency.
  2. The host calls an inventory MCP tool to read the current deployment and service owner.
  3. It delegates diagnosis over A2A to an independently operated reliability agent. That agent may call its own metrics and tracing MCP servers.
  4. The reliability agent returns a diagnosis artifact with evidence and confidence, not its private reasoning trace.
  5. The host creates an A2UI incident surface showing evidence and a “request rollback approval” button.
  6. A click sends an action back to the host. The host reauthorizes the engineer and creates an approval request; it does not let the UI execute a rollback.

The important separation is ownership. A2A owns the specialist task, MCP owns bounded system access, A2UI owns presentation, and application policy owns the side effect.

TypeScript example: keep protocol adapters outside business policy

The following single-file example is runnable with npx tsx protocol-boundaries.ts. It uses small ports instead of pinning the article to one SDK release. In a real service, implement each port with the current MCP, A2A, or A2UI library and keep the orchestration function unchanged.

type RequestContext = Readonly<{
  traceId: string
  tenantId: string
  userId: string
  deadlineAt: number
}>
 
type Deployment = Readonly<{
  version: string
  deployedAt: string
}>
 
type DiagnosisArtifact = Readonly<{
  taskId: string
  state: "completed" | "input-required" | "failed"
  summary: string
  confidence: number
}>
 
interface McpPort {
  callTool<TArguments, TResult>(request: {
    context: RequestContext
    name: string
    arguments: TArguments
  }): Promise<TResult>
}
 
interface A2aPort {
  delegate(request: {
    context: RequestContext
    agent: string
    skill: string
    message: string
  }): Promise<DiagnosisArtifact>
}
 
type A2uiComponent =
  | { id: string; component: "Column"; children: string[] }
  | { id: string; component: "Text"; text: string | { path: string } }
  | {
      id: string
      component: "Button"
      text: string
      action: { event: { name: string; context: Record<string, string> } }
    }
 
type A2uiEnvelope =
  | {
      version: "v0.9.1"
      createSurface: { surfaceId: string; catalogId: string }
    }
  | {
      version: "v0.9.1"
      updateComponents: {
        surfaceId: string
        components: A2uiComponent[]
      }
    }
  | {
      version: "v0.9.1"
      updateDataModel: {
        surfaceId: string
        value: Record<string, unknown>
      }
    }
 
interface A2uiPort {
  send(messages: readonly A2uiEnvelope[]): Promise<void>
}
 
function assertWithinDeadline(context: RequestContext): void {
  if (Date.now() >= context.deadlineAt) {
    throw new Error(`deadline exceeded for trace ${context.traceId}`)
  }
}
 
function safeDisplayText(value: string, maxLength = 2_000): string {
  // This bounds control characters and payload size. The renderer must still
  // sanitize Markdown, links, and any catalog-specific rich content.
  return value
    .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, "")
    .slice(0, maxLength)
}
 
function incidentSurface(input: {
  service: string
  deployment: Deployment
  diagnosis: DiagnosisArtifact
}): A2uiEnvelope[] {
  const surfaceId = `incident-${input.service}`
  const catalogId =
    "https://a2ui.org/specification/v0_9_1/catalogs/basic/catalog.json"
 
  return [
    {
      version: "v0.9.1",
      createSurface: { surfaceId, catalogId },
    },
    {
      version: "v0.9.1",
      updateComponents: {
        surfaceId,
        components: [
          {
            id: "root",
            component: "Column",
            children: ["title", "deployment", "diagnosis", "approval"],
          },
          { id: "title", component: "Text", text: "Incident review" },
          {
            id: "deployment",
            component: "Text",
            text: { path: "/deploymentLabel" },
          },
          {
            id: "diagnosis",
            component: "Text",
            text: { path: "/diagnosisSummary" },
          },
          {
            id: "approval",
            component: "Button",
            text: "Request rollback approval",
            action: {
              event: {
                name: "request_rollback_approval",
                context: { service: input.service },
              },
            },
          },
        ],
      },
    },
    {
      version: "v0.9.1",
      updateDataModel: {
        surfaceId,
        value: {
          deploymentLabel: `Current deployment: ${input.deployment.version}`,
          diagnosisSummary: safeDisplayText(input.diagnosis.summary),
          confidence: input.diagnosis.confidence,
          taskId: input.diagnosis.taskId,
        },
      },
    },
  ]
}
 
async function buildIncidentReview(
  context: RequestContext,
  service: string,
  ports: { mcp: McpPort; a2a: A2aPort; a2ui: A2uiPort }
): Promise<void> {
  if (!/^[a-z][a-z0-9-]{1,62}$/.test(service)) {
    throw new Error("invalid service identifier")
  }
  assertWithinDeadline(context)
 
  const [deployment, diagnosis] = await Promise.all([
    ports.mcp.callTool<{ service: string }, Deployment>({
      context,
      name: "inventory.get_current_deployment",
      arguments: { service },
    }),
    ports.a2a.delegate({
      context,
      agent: "reliability-specialist",
      skill: "diagnose-service-regression",
      message: `Diagnose the latency regression for ${service}`,
    }),
  ])
 
  assertWithinDeadline(context)
  if (diagnosis.state !== "completed") {
    throw new Error(`specialist task ended in state: ${diagnosis.state}`)
  }
  if (diagnosis.confidence < 0 || diagnosis.confidence > 1) {
    throw new Error("invalid diagnosis confidence")
  }
 
  // The host builds and validates the UI. It does not blindly forward a
  // remote agent's component tree or allow the UI to execute a rollback.
  await ports.a2ui.send(incidentSurface({ service, deployment, diagnosis }))
}
 
const mcp: McpPort = {
  async callTool<TArguments, TResult>(request: {
    context: RequestContext
    name: string
    arguments: TArguments
  }): Promise<TResult> {
    console.log(`[mcp] ${request.name}(${JSON.stringify(request.arguments)})`)
    return {
      version: "checkout-2026.08.03.4",
      deployedAt: "2026-08-03T09:30:00Z",
    } as TResult
  },
}
 
const a2a: A2aPort = {
  async delegate(request) {
    console.log(`[a2a] delegated ${request.skill} to ${request.agent}`)
    return {
      taskId: "task-7f3",
      state: "completed",
      summary: "Latency started after the latest checkout deployment.",
      confidence: 0.91,
    }
  },
}
 
const a2ui: A2uiPort = {
  async send(messages) {
    const kinds = messages.map((message) =>
      "createSurface" in message
        ? "createSurface"
        : "updateComponents" in message
          ? "updateComponents"
          : "updateDataModel"
    )
    console.log(`[a2ui] sent ${kinds.join(" -> ")}`)
  },
}
 
async function main(): Promise<void> {
  await buildIncidentReview(
    {
      traceId: "trace-42",
      tenantId: "acme",
      userId: "engineer-17",
      deadlineAt: Date.now() + 5_000,
    },
    "checkout",
    { mcp, a2a, a2ui }
  )
 
  console.log("surface=incident-checkout state=ready")
}
 
void main().catch((error: unknown) => {
  console.error(error)
  process.exitCode = 1
})

Expected output:

[mcp] inventory.get_current_deployment({"service":"checkout"})
[a2a] delegated diagnose-service-regression to reliability-specialist
[a2ui] sent createSurface -> updateComponents -> updateDataModel
surface=incident-checkout state=ready

The example has three deliberate properties:

  1. The application passes the same tenant, user, trace, and deadline context to both remote boundaries.
  2. The host validates the A2A artifact and constructs an allowlisted A2UI surface instead of forwarding arbitrary remote UI.
  3. The button requests an approval workflow. A separate server handler must authenticate the user, bind the action to the tenant and service, consume an idempotency key, and only then call a write tool.

In production, do not use the generic cast in the in-memory MCP stub. Your MCP adapter should validate tool results at runtime before returning the typed Deployment object. The cast keeps the demo dependency-free; it is not a trust boundary.

Map context explicitly across protocol boundaries

The protocols do not automatically agree on identity or lifecycle. Define a translation contract before implementation.

ConcernMCP boundaryA2A boundaryA2UI boundary
IdentityToken audience and scopes for the capability serverCaller identity and agent-specific authorizationAuthenticated app session; never trust identity inside component data
TenantDerived from verified credentials and repeated in data policyTask storage and listing scoped to the caller's tenantSurface namespace and actions bound server-side to the tenant
DeadlinePer call, with a remaining-time budgetTask deadline plus cancellation policySurface expiry and action freshness
IdempotencyRequired before retrying writesStable task/message identity and deduplicationStable action ID consumed once by the server
TracePropagate through tool metadata or transport headersPropagate without exposing private reasoningCorrelate surface and action, but do not put secrets in UI state
VersionPin protocol and capability expectationsPin A2A major/minor and validate Agent CardPin envelope version and catalog ID

Avoid translating one bearer token unchanged across every hop. Each receiver should get a credential intended for its own audience and least-privilege scope. Otherwise, a compromised downstream service can replay a powerful upstream token and turn the orchestrator into a confused deputy.

Failure modes and edge cases

MCP failure modes

  • Tool descriptions or schemas change after approval. Pin or hash approved definitions and review risk-increasing changes.
  • The model chooses a valid but dangerous tool. Reauthorize every call from trusted identity and policy; tool discovery is not permission.
  • A timeout is retried after the write succeeded. Require idempotency keys or reconciliation before retrying an ambiguous result.
  • Results leak between tenants through a cache. Include tenant, principal scope, tool, arguments, policy version, and data version in the cache key.

A2A failure modes

  • A stale or spoofed Agent Card advertises a privileged skill. Use trusted registries or direct configuration, HTTPS, cache revalidation, and signatures where your trust model requires them.
  • A task outlives the client request. Persist task ownership, deadline, cancellation state, and result retention outside a web replica.
  • Agents recursively delegate until cost or latency explodes. Enforce hop, cost, token, and wall-clock budgets in application policy.
  • Polling, streaming, and push deliver duplicate status. Make updates monotonic and consumers idempotent; terminal state must win.

A2UI failure modes

  • Messages arrive out of order. The carrier must preserve order; do not apply an update to a surface that has not been created.
  • The agent names an unknown component or function. Reject it against the negotiated catalog rather than attempting a best-effort render.
  • A remote agent impersonates a trusted agent in the theme. The orchestrator must overwrite display identity from verified agent metadata.
  • A user replays a destructive action. Reauthorize server-side, bind the action to current state, require a nonce or idempotency key, and expire it.

Cross-protocol failure modes

The hardest bugs occur between layers: an A2A task remains active after the MCP deadline, an A2UI surface offers an action after permissions changed, or trace context disappears at an adapter. Give the overall request one budget and derive shorter downstream budgets. Store the protocol identifiers together: traceId, a2aTaskId, MCP request ID, A2UI surfaceId, tenant, and policy decision ID.

Common architecture mistakes

Treating MCP as remote-agent orchestration

A generic tool named ask_agent(prompt) can work for a narrow internal adapter, but it hides task state, clarification, cancellation, and artifacts. Use A2A when those semantics cross an ownership boundary.

Treating A2A as a faster RPC format

A2A is designed for potentially long-running, asynchronous collaboration. A direct function, service API, or MCP tool is simpler for a deterministic lookup with a tight latency budget.

Treating A2UI as the authorization layer

Disabling a button is user experience, not security. A malicious client can send the event directly. Every action needs the same server-side authorization as an API call.

Blindly forwarding one protocol inside another

If a remote A2A agent returns A2UI, validate the version, catalog, component count, URLs, functions, bindings, attribution, and action names before rendering. If an MCP result becomes an A2A artifact, validate its schema and strip secrets before persistence.

Sharing one context object without audience reduction

Trace and tenant identity should propagate. Credentials, raw prompts, hidden reasoning, and unrestricted tool catalogs should not. Translate the minimum context each receiver needs.

Senior-level trade-offs interviewers will probe

DecisionSimpler optionWhen the protocol earns its costSenior-level concern
MCP vs direct APITyped internal clientMultiple AI hosts need discoverable capabilities and consistent consentSchema governance, tool poisoning, token audience, write idempotency
A2A vs internal queueFunction or durable jobIndependent agents need interoperable task lifecycle and opaque executionTrust registry, task ownership, delegation loops, result retention
A2UI vs fixed frontendCoded React/native UISurface structure changes at runtime or comes from remote agentsCatalog governance, accessibility, action authorization, version skew
One agent vs specialistsOne orchestration loopDomain ownership, isolation, scaling, or vendor boundaries are realLatency amplification, cost budgets, correlated failure, observability
Forward remote UI vs rebuild itPass through the payloadThe remote party is trusted and the catalog is intentionally sharedImpersonation, unsupported components, unsafe URLs, policy drift

A strong design does not maximize protocol adoption. It names the boundary, shows why ordinary code is insufficient there, and keeps the rest of the system boring.

Production checklist

Contract and lifecycle

  • Draw each boundary and label it capability, agent task, UI description, or ordinary application call.
  • Pin supported protocol versions and fail clearly on incompatible features.
  • Define ownership for MCP calls, A2A task state, A2UI surfaces, and cleanup.
  • Give the end-to-end request one deadline, then allocate downstream budgets.
  • Specify cancellation, retry, deduplication, and terminal-state behavior.

Trust and security

  • Authenticate every remote endpoint and verify the credential audience.
  • Derive tenant and principal identity from trusted credentials, not model or UI payloads.
  • Authorize tool calls, task access, and UI actions independently.
  • Validate MCP schemas, A2A cards/artifacts, and A2UI envelopes at runtime.
  • Use least-privilege downstream credentials; do not pass one bearer token through the entire graph.
  • Put destructive actions behind a server-owned approval and idempotency boundary.

Reliability and operations

  • Propagate trace context and store cross-protocol correlation IDs.
  • Bound delegation depth, tool calls, tokens, cost, response bytes, component count, and update rate.
  • Use per-dependency timeouts, bulkheads, and circuit breakers.
  • Test stale discovery, version mismatch, duplicate delivery, partial failure, cancellation, and permission revocation.
  • Redact prompts, artifacts, UI data, tokens, and tool results from logs by policy.
  • Define rollout, fallback, and rollback behavior for each adapter.

For broader practice, use the system design interview case studies to rehearse requirements and capacity reasoning, the Architecture Judgment Index for Staff-level trade-off drills, and the AI Architect track to assess agent-system design gaps. The Production AI Systems course goes deeper on interview framing, reliability, and operating the design.

How to explain MCP vs A2A vs A2UI in an interview

Start with boundaries, not definitions:

“I choose these protocols by who owns the work. MCP lets my host discover and invoke a bounded capability, so the host still owns orchestration. A2A lets my host delegate a goal to an independently operated agent with its own task lifecycle. A2UI lets an agent describe a dynamic interface that our trusted client renders from an approved catalog. In this design, the coordinator uses A2A for specialist diagnosis, both agents use MCP for system access, and the coordinator emits A2UI for the human approval step. Identity, deadlines, trace context, and authorization are translated at every boundary.”

Then state what you deliberately did not use: direct functions within one trust domain, no A2A for deterministic lookups, and no A2UI for fixed product screens. That shows cost awareness rather than protocol memorization.

Realistic follow-up questions

Why not expose the specialist as one MCP tool?

That is reasonable if the work is short, bounded, and owned by the same team. It becomes awkward when the remote party needs task status, multi-turn clarification, streaming, cancellation, independent discovery, or artifacts. Those are native A2A concerns.

Can an A2A agent call MCP tools?

Yes. A2A defines the contract between cooperating agents, not their internal implementation. Each agent can use MCP, direct APIs, databases, or local code to complete its task.

Where should conversation and task state live?

Keep durable A2A task and business state in an application-owned store, not a web replica. Keep MCP core requests stateless and persist only application state that the workflow actually needs. Keep A2UI surface state in the client plus an authoritative server model for security-sensitive actions.

What if the remote agent returns A2UI the client does not support?

Reject or downgrade based on negotiated capabilities. The client should never guess how to render an unknown component. A safe fallback is a text or structured artifact, not arbitrary HTML execution.

How do you prevent one agent from spending the entire budget?

Give each delegation a child budget for time, tokens, cost, tool calls, and hop count. The parent keeps reserve for validation, user interaction, and recovery. Cancellation should propagate, but cleanup and audit must survive the canceled request.

Which protocol should be introduced first?

Start with the boundary that already causes duplicated integration work. MCP is often first because tool and data adapters multiply quickly. Add A2A only when independent agent ownership and task lifecycle are real. Add A2UI when dynamic, host-native interaction is a product requirement—not merely because text feels plain.

The practical default

Use MCP for capabilities, A2A for delegated outcomes, and A2UI for dynamic native interaction. Keep application policy, durable workflow state, and authorization outside the protocols. If a plain function, API, queue, or fixed UI solves the problem inside one ownership boundary, use it. The best agent architecture is the smallest set of contracts that makes ownership, trust, and failure behavior explicit.

Key takeaways

  • Choose by relationship: host-to-capability is MCP, agent-to-agent delegation is A2A, and agent-to-renderer UI description is A2UI.
  • MCP exposes bounded capabilities; A2A delegates goals to an opaque peer; A2UI carries declarative interface state, not executable application code.
  • Do not add A2A for two agents inside one trusted process, or A2UI for a fixed form your frontend can own directly.
  • Authentication, authorization, deadlines, idempotency, and trace context must be translated explicitly at every protocol boundary.
  • A production system can use all three: A2UI at the user edge, A2A between independently owned agents, and MCP behind each agent for tools and data.
  • Pin protocol versions and validate capabilities; current specifications are MCP 2026-07-28, A2A 1.0, and A2UI 0.9.1 as of August 3, 2026.

Frequently asked questions

Is A2A replacing MCP?

No. MCP connects an AI application to capabilities such as tools, resources, and prompts. A2A connects independent agent systems that discover each other, exchange messages, and manage tasks. An A2A agent commonly uses MCP internally to access its own tools.

Can MCP, A2A, and A2UI be used together?

Yes. A client can render an A2UI surface from an orchestrator, the orchestrator can delegate specialist work over A2A, and each participating agent can call tools through MCP. The important design work is preserving identity, deadlines, trace context, and authorization across the boundaries.

Is A2UI secure because it is declarative?

A2UI is safer than executing arbitrary agent-generated JavaScript because the client renders only registered components and functions. It is still untrusted input. Validate every message against the selected catalog, sanitize content and URLs, enforce limits, verify attribution, and authorize every user action on the server.

How is A2UI different from MCP Apps?

A2UI sends declarative component and data messages that the host renders with native components and styling. MCP Apps let a server provide a pre-built HTML interface that runs in a sandboxed iframe. Choose A2UI for host-controlled, cross-platform UI; choose MCP Apps when the integration should own the complete web experience.


Related Posts