Marcus had three agents running in production. The first called Salesforce to pull account data. The second delegated booking tasks to a scheduling specialist. The third needed to route through the enterprise message bus so security could audit every action.
He'd built all three with MCP. The tool calls worked. The agent-to-agent delegation sort of worked, until it didn't: when the scheduling agent started asking follow-up questions, the MCP model broke down because MCP tools are supposed to be stateless, and the scheduling agent was very much not. The enterprise security team rejected the whole setup because they couldn't inspect inter-agent traffic the way the bus would let them.
One protocol. Three different needs. Three mismatches.
Here's what he needed to know at the start.
MCP connects your agent to tools
MCP (Model Context Protocol) is the protocol your agent uses to call external tools: APIs, databases, search indexes, CRMs, ticketing systems. It defines how tools advertise their capabilities, how agents discover and invoke them, and how inputs and outputs move between them.
Think of MCP as the standard connector for AI tools. Before MCP, every tool integration was bespoke. You wrote custom code for the Salesforce call, different custom code for the SQL query, more for the web search. MCP gives every tool a standardized interface so an agent can call a Salesforce tool, a SQL query tool, and a web search tool through the same mechanism.
The model is client-server. Tool providers run MCP servers that expose named functions. Your agent is the MCP client. When the agent needs data or needs to take an action, it discovers the available tools, picks the right one, sends a structured call, and gets the result back.
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["./crm-mcp-server.js"],
});
const client = new Client(
{ name: "cx-agent", version: "1.0.0" },
{ capabilities: {} }
);
await client.connect(transport);
// List available tools from this MCP server
const tools = await client.listTools();
console.log("Available tools:", tools.tools.map((t) => t.name));
// ["get_account", "update_ticket", "list_orders", "create_case"]
// Call a specific tool
const result = await client.callTool({
name: "get_account",
arguments: { account_id: "acc_8829" },
});
console.log(result.content[0].text);
// {"id": "acc_8829", "name": "Acme Corp", "tier": "enterprise", ...}The key property of MCP is that it's vertical: one agent calls one tool. There's no peer relationship between agents here, no delegation, no ongoing task state. The tool executes and returns. If the agent needs more data, it calls again. Each call is independent.
This is what broke Marcus's scheduling agent. The scheduling agent wasn't a tool. It had its own goals, could ask clarifying questions, needed to run multiple steps over several seconds, and maintained task state between turns. Wrapping that in an MCP tool interface is technically possible but architecturally wrong. It forces an agent into a stateless tool shape when the agent needs to be a peer.
The right protocol for agent-to-agent communication is A2A. Not a misuse of MCP.
Chanl's MCP runtime handles the connection layer for CX agents, including tool discovery and authorization, so you're not building transport infrastructure from scratch. Each tool shows up as a callable function in the agent's context, with its input schema surfaced automatically.
A2A handles agent delegation
A2A (Agent-to-Agent Protocol), developed by Google and donated to the Linux Foundation with 50-plus partners in 2025, handles the case that MCP can't: one agent delegating a task to another agent that has its own identity, memory, and decision-making capacity.
The distinction matters more than it might seem. A tool is stateless. It receives inputs, runs a function, and returns outputs. An agent has goals, can take multiple steps, can ask follow-up questions, and can fail in ways that require reasoning rather than just error handling. When your orchestrating agent delegates "schedule a follow-up meeting" to a scheduling agent, the scheduling agent needs to check availability, handle conflicts, send confirmations, and update its own task state. That's not a tool call; it's a delegation to a peer.
A2A gives receiving agents an identity (published as an Agent Card), a structured task format, and three response modes. Synchronous: return the result immediately. Streaming: send progress updates as you go. Async: run the task in the background and notify when done. The async mode is what makes A2A appropriate for long-running CX tasks where the answer doesn't come back in 200 milliseconds.
import { A2AClient } from "@google-labs/a2a-client";
const schedulingAgent = new A2AClient({
baseUrl: "https://agents.internal/scheduling",
});
// Read the agent's capabilities from its Agent Card
const agentCard = await schedulingAgent.getAgentCard();
console.log("Agent:", agentCard.name);
// "Scheduling Agent v2"
console.log("Capabilities:", agentCard.capabilities);
// { streaming: true, async: true, pushNotifications: false }
// Delegate a booking task with streaming updates
const task = await schedulingAgent.createTask({
id: crypto.randomUUID(),
message: {
role: "user",
parts: [
{
type: "text",
text: "Schedule a 30-min follow-up with account acc_8829 for next week, preferably Tuesday or Wednesday morning",
},
],
},
});
// Stream updates as the scheduling agent works
for await (const update of schedulingAgent.streamTaskUpdates(task.id)) {
if (update.status.state === "working") {
console.log("Progress:", update.status.message?.parts[0].text);
// "Checking availability for Tuesday June 30..."
// "Found open slot at 10:00 AM Tuesday"
// "Sending calendar invite..."
}
if (update.status.state === "completed") {
console.log("Meeting booked:", update.artifacts[0].parts[0].text);
break;
}
}The Agent Card is one of A2A's most useful pieces. It's a JSON document the receiving agent publishes at a well-known URL, describing what tasks it accepts, what content types it handles, and how to send it work. The orchestrating agent reads the Agent Card at runtime to understand what it's delegating to, without any out-of-band documentation. This makes A2A self-describing in a way that scales to large agent fleets where you can't keep mental models of every agent's interface.
For most CX agent architectures, MCP and A2A together handle the majority of integration needs. A detailed comparison of when each fits, with real protocol traces, is in MCP vs A2A: protocols, tools, and agents in 2026.
ACP routes across enterprise agent fleets
ACP (Agent Communication Protocol), developed by IBM's BeeAI team and now governed by the Linux Foundation, solves a problem that A2A wasn't designed for: routing agent messages across agents built on different frameworks, inside an enterprise where IT governance controls the traffic.
In large organizations, one team builds agents on LangChain. Another uses CrewAI. A third has a custom Python setup. The IT security team wants all inter-agent communication to flow through a managed bus that can be audited, rate-limited, and controlled by policy. A2A works well when you own both agents. ACP works when you don't, or when governance requires a neutral routing layer between them.
ACP is REST-native. Any agent that can make an HTTP call can participate, regardless of what framework it's built on. It uses a MIME multipart message format that handles text, images, audio, and arbitrary structured data in the same envelope. For CX agents that work across voice (audio buffers), chat (text), and document (PDFs, images) channels, that unified format matters. You don't need separate integration paths for each content type.
import httpx
# Send a task through the enterprise ACP router
# The router decides which registered agent handles it
# based on the task_type and capability registry
response = httpx.post(
"https://agent-bus.internal/acp/v1/tasks",
headers={
"Authorization": f"Bearer {enterprise_token}",
"Content-Type": "application/json",
},
json={
"task_type": "customer.refund.process",
"customer_id": "cust_4421",
"payload": {
"order_id": "ord_9983",
"refund_amount": 89.99,
"reason": "item_not_as_described",
},
},
timeout=30.0,
)
result = response.json()
print(f"Assigned to: {result['assigned_agent']}")
# "refund-processing-agent-v3"
print(f"Task status: {result['status']}")
# "accepted"
print(f"Correlation ID: {result['correlation_id']}")
# "acp-task-7f3a9b21" -- for audit log lookupThe governance angle is ACP's main value proposition. Every message flows through a central point that can apply enterprise policy: "agents in the customer service namespace can initiate refunds up to $500," "any task involving customer PII must stay within the EU data region," "all financial task completions require two-agent confirmation before execution." A2A doesn't provide that central policy layer. ACP does.
You don't need ACP if you're a small team with full control over your own agent stack. A2A handles inter-agent communication without the added routing infrastructure. ACP earns its complexity when IT governance is a real requirement, when you're operating across heterogeneous frameworks, or when you need policy enforcement at the routing layer rather than inside each agent.
ANP connects agents across organizations
ANP (Agent Network Protocol) addresses the one boundary that MCP, A2A, and ACP all assume away: two agents from different organizations, running on different infrastructure, with no shared trust relationship.
With the other three protocols, you're always inside a shared trust boundary. The MCP tool server trusts the agent client. The A2A receiving agent trusts the orchestrator. The ACP router trusts the agents registered with it. That trust is established through shared infrastructure or configuration, which presupposes a shared organization.
ANP takes a different approach. Each agent gets a cryptographic identity using W3C Decentralized Identifiers (DIDs). When your agent wants to work with a partner organization's agent, it doesn't need to exchange API keys or register in a shared system. It verifies the partner agent's DID, and the partner verifies yours. Identity and trust are established cryptographically, not administratively.
This enables scenarios the other protocols can't: your fulfillment partner's inventory agent accepting tasks from your order management agent, where each organization keeps independent control over their own agent identities and permissions. Or a healthcare network where patient consent governs which agents can access which data, enforced at the protocol level rather than through policy documents that someone might not follow.
import { ANPClient } from "@agent-network/anp-sdk";
// Both agents have DID-based identities
const ourAgent = ANPClient.fromPrivateKey({
did: "did:web:agents.yourcompany.com:order-management",
privateKeyPath: "./keys/order-agent-private.pem",
});
// Discover the fulfillment partner's inventory agent via their DID
const partnerAgentDid = "did:web:agents.fulfillmentco.com:inventory";
const partnerAgent = await ourAgent.connect(partnerAgentDid);
// The DID resolution verifies the partner agent's identity cryptographically
// No shared secret, no API key exchange required
const inventoryCheck = await partnerAgent.sendMessage({
type: "inventory.check",
payload: {
sku: "SKU-44821",
quantity: 5,
warehouse_region: "us-east",
},
});
console.log("Inventory available:", inventoryCheck.available); // true
console.log("Verified from:", inventoryCheck.source_agent_did);
// "did:web:agents.fulfillmentco.com:inventory" -- cryptographically confirmedANP is technically well-designed but the DID infrastructure isn't production-ready for most deployments in mid-2026. Key management, DID rotation, and agent identity lifecycle tooling are still developing. Most teams should build with MCP and A2A now, evaluate ANP when a specific cross-organizational use case demands it, and watch the ecosystem for maturity signals toward late 2026.
One property worth noting: ANP's decentralized design means no single vendor controls the protocol. For cross-organization agent communication, that's meaningful. A centralized registry that one company controls is a governance and trust problem waiting to happen. ANP avoids it by putting identity in the cryptographic layer.
How the four protocols compose in a real CX agent
A production CX agent uses multiple protocols simultaneously, at different layers of its architecture.
The most common pattern: an orchestrating agent uses MCP to call tools for data lookup, uses A2A to delegate complex tasks to specialized sub-agents, and those sub-agents also use MCP for their own tool calls. For enterprise deployments, ACP wraps the inter-agent layer as a routing and governance tier. ANP connects to agents outside the organization when that use case arises.
Here's what that looks like for a returns agent handling a damaged item:
-
The orchestrating agent receives the conversation turn. It uses MCP to call
get_order_history, retrieving the order details and return policy eligibility. -
The order qualifies for return. The orchestrating agent uses A2A to delegate
process_refundto a specialized refund agent, which has logic for fraud screening, warehouse routing, and refund initiation that would clutter the orchestrator. -
Inside the enterprise, inter-agent messages flow through ACP so the IT security team can audit them. Every refund action above $200 triggers a two-agent confirmation policy enforced at the ACP routing layer.
-
The refund requires notifying the logistics partner's warehouse system. That system is run by a separate company. ANP handles the cross-organizational handoff, with both agents verifying each other's DID before exchanging task data.
Not every CX agent needs all four. Most teams start with MCP and add complexity only when a specific need forces it.
We covered how to wire up the MCP and A2A layers from scratch in building the agent protocol stack from scratch. If you're starting a new multi-agent build, that piece is a good companion to this one.
What to implement first
MCP is non-negotiable. Every agent that calls external tools should use it. The spec is stable, the client libraries are mature across TypeScript, Python, and Go, and standardizing on MCP now means you don't rewrite tool integrations when you add a second agent to the system.
A2A comes in as soon as you're splitting work across specialized agents. Don't build for it before you need it: start with a single orchestrating agent that handles everything, then extract sub-agents as tasks grow complex enough to warrant separate context and state. That transition usually happens earlier than you'd expect, but not before the first production version.
ACP is an enterprise decision. If your IT organization manages agent infrastructure and requires a governance layer, ACP is the right choice. If you're a small team with full control over your own stack, the added routing infrastructure isn't worth it yet.
ANP is for later. The value is real but build when the ecosystem is ready, not now.
Protocol selection checklist:
MCP Always. Your agent needs to call tools.
A2A When you have specialized sub-agents that own distinct tasks.
ACP When enterprise IT requires governed, auditable inter-agent routing.
ANP When you need cryptographic trust with agents at other organizations.Chanl's MCP integration and tools layer handle the tool connection side for CX agents. As your agent architecture grows to include A2A delegation, Chanl's monitoring traces spans across the full call graph. You see which agent called which tool, which delegation went to which sub-agent, and where things broke, rather than trying to reconstruct that chain from scattered logs.
See your entire agent protocol stack in one trace
Chanl monitors MCP tool calls, A2A delegations, and every step in between. When something breaks in a multi-agent workflow, you see exactly which agent, which protocol, and which step failed.
Explore Chanl monitoringCo-founder
Building the platform for AI agents at Chanl — tools, testing, and observability for customer experience.
El briefing de Signal
Un email por semana. Cómo los equipos líderes de CS, ingresos e IA están convirtiendo conversaciones en decisiones. Benchmarks, playbooks y lo que funciona en producción.


