ChanlChanl
Agent Architecture

A2A and MCP: the agent protocol stack explained

MCP connects agents to tools. A2A connects agents to other agents. Together they form the full protocol stack for multi-agent CX systems. Here's how they work and why you need both.

DGDean GroverCo-founderFollow
June 28, 2026
14 min read
Protocol diagram showing how MCP and A2A complement each other in a multi-agent architecture

A2A and MCP: the agent protocol stack explained

The billing dispute was simple. The customer wanted to know why their last invoice was $40 higher than expected, and the voice agent resolved it in 90 seconds. But then they asked: "Can you also schedule a callback with a billing specialist for next week?"

The voice agent knew the dispute. The scheduling agent, a separate service managing the specialist calendar, knew availability. The problem was getting them to talk to each other.

You could handle it inline by passing context from the voice agent to the scheduling agent, waiting for confirmation, and returning to the customer. But what does "passing context" mean when the two agents are separate services from different vendors on different infrastructure? What format? What authentication? What if the scheduling agent takes ten seconds? Does the voice agent hold the call open?

Two protocols exist to answer these questions. MCP handles one half. A2A handles the other. Most teams learn this lesson the hard way, after building a system that conflates them.

Why one protocol is not enough

MCP and A2A each solve a different problem, and using one where you need the other creates a category of bugs that are difficult to diagnose.

MCP (Model Context Protocol) connects your agent to passive capabilities: APIs, databases, file systems, external services. The agent calls a tool, the tool executes a function, the tool returns a result. The tool doesn't plan or reason. It just executes. This is the agent-to-tool layer.

A2A connects your agent to other agents, peers that have their own reasoning, their own memory, their own domain expertise. When you delegate over A2A, you're not calling a function. You're handing work to another autonomous system and trusting it to determine how to complete that work. This is the agent-to-agent layer.

The failure modes are completely different. A tool call fails fast with a deterministic error you can catch and handle immediately. An agent delegation fails slowly, ambiguously, with partial progress and shared state you need to reconcile. Designing your orchestration as if you're making tool calls when you're actually delegating to agents is where most multi-agent bugs originate.

For CX systems, the split is usually clean. Your agents use MCP to access tools they own directly (CRM lookup, call controls, payment processing), and they use A2A to delegate work to specialized peer agents (a scheduling service, a billing escalation agent, a fraud detection system). Once you see the system through that lens, the architecture becomes intuitive.

MCP: your agent's connection to tools

MCP gives your agent a standard interface for discovering, describing, and calling tools. The protocol handles the schema (how the tool's inputs are described to the model), the transport (how calls are made and results returned), and the lifecycle (streaming results, cancellation, error handling).

An MCP server for a CRM lookup looks roughly like this:

crm-mcp-server.ts·typescript
import { MCPServer } from "@modelcontextprotocol/server";
 
const server = new MCPServer({ name: "crm-service", version: "1.0.0" });
 
server.addTool({
  name: "get_customer",
  description: "Look up a customer record by phone number or email",
  inputSchema: {
    type: "object",
    properties: {
      identifier: {
        type: "string",
        description: "Phone number (E.164) or email address",
      },
      fields: {
        type: "array",
        items: { type: "string" },
        description: "Fields to return. Defaults: name, tier, open_issues, recent_orders.",
        default: ["name", "tier", "open_issues", "recent_orders"],
      },
    },
    required: ["identifier"],
  },
  execute: async ({ identifier, fields }) => {
    const customer = await db.customers.findByIdentifier(identifier);
    return pick(customer, fields);
  },
});

Your agent treats this as a function call. It sees the schema, decides when to invoke it, provides arguments, and gets back structured data. The agent doesn't know whether the CRM is a Postgres query, a REST call, or a GraphQL fetch. MCP abstracts the transport.

This works well when the tool is genuinely passive. The CRM returns data and stops. But scheduling is different. Booking an appointment requires reasoning about availability windows, applying business rules, handling conflicts, confirming with the customer, and sending confirmations. You could wrap all of that in a single MCP tool, but you'd be writing a planning loop inside a tool handler. At that point you've built an agent and called it a tool, which means you've lost the state management, streaming, and error recovery that A2A provides natively.

A2A: agent-to-agent task delegation

A2A lets your agent hand a complete task to another agent rather than calling a single function and waiting for a synchronous result. The receiving agent handles the task in its own execution context, using its own tools and memory, and returns a structured result when it's done.

The protocol has three core building blocks.

Agent Cards let agents advertise their capabilities. Tasks carry work and track its progress through a state machine. Streaming via Server-Sent Events handles long-running interactions where you need incremental updates.

Agent Cards: the discovery layer

Before your orchestrator can delegate to a peer agent, it needs to know what that peer can do. Agent Cards solve this. Every A2A-capable agent publishes a JSON document at /.well-known/agent.json describing its identity, supported skills, accepted input types, and authentication requirements.

/.well-known/agent.json·json
{
  "name": "Scheduling Agent",
  "version": "2.1.0",
  "description": "Books and manages specialist callbacks for billing, support, and account reviews",
  "url": "https://scheduling.internal/a2a",
  "defaultInputModes": ["text"],
  "defaultOutputModes": ["text"],
  "skills": [
    {
      "id": "book_callback",
      "name": "Book callback appointment",
      "description": "Schedule a callback with a specialist. Handles availability lookup, conflict resolution, and confirmation messaging.",
      "tags": ["scheduling", "appointments", "callbacks"],
      "examples": [
        "Schedule a billing specialist callback for next Tuesday afternoon",
        "Book a 30-minute account review with the enterprise team"
      ]
    },
    {
      "id": "reschedule_appointment",
      "name": "Reschedule existing appointment",
      "description": "Modify a previously booked appointment. Requires the original booking ID.",
      "tags": ["scheduling", "modification"]
    }
  ],
  "authentication": {
    "schemes": ["Bearer"]
  }
}

Your orchestrator fetches this card once and caches it. When the voice agent decides it needs to delegate scheduling, it checks the card, confirms the skill exists, and sends a delegation request. No hardcoded routing tables. No shared configuration files. The agent advertises what it can do and peers discover it.

Task delegation in practice

Once your agent has the card, sending a task is a JSON-RPC call. The response includes a task ID and initial state. From there you can poll or stream.

a2a-task-delegation.ts·typescript
import { A2AClient } from "@a2a/client";
 
const schedulingAgent = new A2AClient({
  agentUrl: "https://scheduling.internal/a2a",
  auth: { type: "bearer", token: process.env.SCHEDULING_TOKEN },
});
 
// Delegate the scheduling task with customer context
const task = await schedulingAgent.sendMessage({
  message: {
    role: "user",
    parts: [
      {
        type: "text",
        text: `Book a billing specialist callback for customer ${customerId}.
               Preference: next week, morning.
               Subject: invoice dispute, reference #${disputeId}.`,
      },
    ],
  },
});
 
// Stream updates so you can relay questions to the customer in real time
for await (const update of schedulingAgent.subscribeToTask(task.id)) {
  if (update.status.state === "input-required") {
    // Scheduling agent needs clarification -- relay to customer
    const question = update.status.message?.parts[0]?.text;
    const answer = await voiceAgent.askCustomer(question);
    await schedulingAgent.replyToTask(task.id, answer);
  }
 
  if (update.status.state === "completed") {
    const booking = update.artifact?.parts[0]?.data;
    await voiceAgent.confirmBooking(booking);
    break;
  }
 
  if (update.status.state === "failed") {
    await voiceAgent.handleSchedulingFailure(update.status.message);
    break;
  }
}

The voice agent doesn't know how the scheduling agent books the appointment. It might be calling a calendar API directly, negotiating across multiple specialists' calendars, sending internal notifications. A2A abstracts all of that. The voice agent delegates and reacts to state changes.

The input-required state is worth paying attention to. This is what happens when the scheduling agent needs more information before it can proceed. In a voice context, you relay the question to the customer, collect the answer, and send it back. The task then continues. Without built-in support for multi-turn delegation, you'd build this interaction pattern yourself with custom polling and state management.

How A2A and MCP work together

The two protocols operate at different layers. MCP connects each agent to the tools it uses directly. A2A connects agents to each other. In a production CX system, you need both, and they don't compete.

Reports billing dispute, requests callback get_customer(phone) via MCP Customer record, dispute history Delegate: book_callback task via A2A check_specialist_availability() via MCP Available slots for next week Apply booking rules, select slot Task completed, booking confirmed You're booked for Tuesday at 10am Customer Voice Agent CRM Tool (MCP) Scheduling Agent (A2A) Calendar Tool (MCP)
MCP handles tool calls within an agent; A2A delegates tasks between agents

Each agent owns its own MCP connections. The voice agent's tools cover CRM lookups, call controls, and sentiment detection. The scheduling agent's tools cover calendar access, specialist availability, and confirmation messaging. Neither agent reaches into the other's tool layer.

A2A is what connects these specialized domains without merging them. The voice agent doesn't need calendar access. It delegates to the scheduling agent, which has the context and tools to handle that domain and returns a structured result. The voice agent reacts to that result without needing to understand how it was produced.

This is the architecture that scales. You can replace the scheduling agent with a different vendor's implementation as long as it speaks A2A. You can add new specialists (fraud detection, account management, technical support) without modifying the voice agent or any other peer. The protocol provides the interface; each agent owns its domain.

Building multi-agent CX with this stack

A2A v1.0, released early 2026, is production-grade and supported by more than 150 organizations including Salesforce, ServiceNow, and SAP. That last group matters: A2A can delegate across the enterprise platforms your agents already connect to. You're not building a proprietary integration point. You're joining a standard that CRM vendors, ticketing systems, and workforce management tools are already adopting.

Four things to get right before you ship:

Latency budget. Each A2A delegation adds a network round trip. For a voice interaction where the customer is on the line, 50 to 100ms of added latency is usually acceptable. If you're chaining three A2A delegations, you're adding 150 to 300ms before the first tool call in the final agent fires. Map your critical paths before you route time-sensitive interactions through multi-hop chains.

State durability. A2A tasks are stateful. If your scheduling agent crashes mid-booking, your orchestrator needs to decide whether to retry, fetch current task state, or escalate. Build your orchestration logic around the full state machine, including failed and input-required states, not just the happy path.

Authorization scoping. Each agent card declares its authentication schemes. Your calling agent needs credentials for every peer it delegates to. Use service accounts scoped to specific skills, issued by your identity provider and rotated on a standard schedule. Don't pass end-user tokens downstream to peer agents, the security boundary for each agent should be its own.

Version pinning. Agent Cards include an explicit version field. When a peer agent ships breaking changes, its version bumps. Your orchestrator should compare the version it depended on against the card it fetches and alert on unexpected changes. Build this check early; it's cheap to add and expensive to debug without.

Coming back to the billing scenario that opened this article: with MCP handling the CRM lookup and A2A handling the scheduling delegation, the voice agent stayed on one protocol boundary and the scheduling agent stayed on another. Neither needed to know how the other worked. The customer got a booking confirmation before the call ended.

For the tool-calling side of this architecture, tool-calling fragmentation and the MCP standard covers how different frameworks handle tool definitions and where the specification has settled. For the security layer, zero-trust multi-agent delegation goes deeper on authorization patterns across agent boundaries. Chanl's MCP feature and tools feature surface every MCP call and A2A delegation event in a unified trace view, which becomes essential when you're debugging an issue that spans two agent hops and three tool calls.

mcp-config.json
Live
{
"mcpServers":
{
"chanl":
{
"url": "https://acme.chanl.dev/mcp",
"transport": "sse",
"apiKey": "sk-chanl-...a4f2"
}
}
}
Tools
12 connected
Memory
Active
Knowledge
3 sources

See your full agent protocol stack in one place

Chanl surfaces MCP tool calls, A2A task delegations, and conversation traces in a single view. Connect your first agent in minutes.

Get started free
DG

Co-founder

Building the platform for AI agents at Chanl — tools, testing, and observability for customer experience.

Learn Agentic AI

Weekly. Patterns for shipping agents that work. MCP, scorecards, regression tests, prompts, model comparisons.

500+ builders subscribed

Frequently Asked Questions