I've built enough agent infrastructure to know this: the hard part isn't making agents smart. It's making them work together.
We're at this weird inflection point where LLMs can reason, plan, and execute—but the protocols for how they actually collaborate are still being hammered out in real time. If you've tried to build multi-agent systems, you've probably hit the same walls I have. How do agents discover each other's capabilities? How do they communicate reliably? How the hell do they pay each other?
Three protocols are emerging as the de facto stack: Model Context Protocol (MCP) for tools, Agent-to-Agent (A2A) for communication, and Agent Commerce Protocol (ACP) for commerce. They're not competing—they're complementary layers that solve different parts of the same problem.
Let me show you how they actually work, where they fit together, and what's still missing.
Key Takeaways
- MCP provides standardized tool/resource discovery and execution between clients and servers
- A2A handles agent-to-agent task delegation with streaming, notifications, and lifecycle management
- ACP adds payment rails and service marketplaces for commercial agent interactions
- The three protocols layer together: MCP for capabilities, A2A for communication, ACP for commerce
- Real-world implementation requires handling protocol gaps, especially around trust and discovery
- No single protocol solves everything—interoperability is still manual work
Model Context Protocol (MCP): Tools and Resources
MCP, created by Anthropic, solves a specific problem: how do you give an LLM access to external tools and data without rebuilding integrations for every client?
Before MCP, if you wanted Claude to read your Gmail, Notion, and Slack, you'd write three separate integrations. Then if you switched to another LLM, you'd rewrite them all. MCP standardizes this with a client-server architecture.
Architecture Overview
MCP has three components:
The server advertises what it can do. The client discovers capabilities and invokes them. That's it.
Here's what a minimal MCP server looks like:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{
name: "crypto-price-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_token_price",
description: "Get current price for a crypto token",
inputSchema: {
type: "object",
properties: {
symbol: {
type: "string",
description: "Token symbol (e.g., ETH, BTC)",
},
},
required: ["symbol"],
},
},
],
};
});
// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "get_token_price") {
const symbol = request.params.arguments?.symbol;
const price = await fetchPrice(symbol); // Your implementation
return {
content: [
{
type: "text",
text: `Current ${symbol} price: ${price}`,
},
],
};
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
const transport = new StdioServerTransport();
await server.connect(transport);
This server exposes one tool: get_token_price. Any MCP client can discover and call it without knowing the implementation details.
When MCP Works Well
MCP shines when you need:
- Tool reuse across multiple LLMs — Write once, use everywhere
- Sandboxed execution — Tools run in separate processes
- Dynamic capability discovery — Clients don't need hardcoded tool lists
It's perfect for personal productivity tools (calendar, email, file systems) and local development environments.
When MCP Doesn't Cut It
MCP is not a communication protocol. It's request-response only. If you need:
- Agent-to-agent task delegation
- Streaming responses
- Push notifications
- Multi-turn workflows
You need something else. That's where A2A comes in.
Agent-to-Agent (A2A): Communication Layer
Google's A2A protocol treats agents as first-class network citizens. Instead of tools, you have agent cards—machine-readable identity documents that describe what an agent can do, how to reach it, and what it expects.
Agent Cards
An agent card is like a LinkedIn profile meets an OpenAPI spec:
# agent-card.yaml
agent:
name: "CryptoAnalyzer"
description: "On-chain analytics and token research"
version: "1.0.0"
endpoint: "https://api.example.com/a2a"
capabilities:
- name: "analyze_wallet"
description: "Analyze wallet holdings and transaction history"
input_schema:
type: "object"
properties:
wallet_address:
type: "string"
chain:
type: "string"
enum: ["ethereum", "base", "polygon"]
output_schema:
type: "object"
properties:
total_value_usd: { type: "number" }
top_holdings: { type: "array" }
risk_score: { type: "number" }
authentication:
methods: ["api_key", "jwt"]
pricing:
model: "per_request"
cost: "0.05 USDC"
You publish this card to a discovery service (or well-known URI at /.well-known/agent-card), and other agents can find you.
Task Lifecycle
A2A defines a full task lifecycle:
Here's a complete A2A client interaction:
// 1. Discover agent
const agentCard = await fetch("https://api.example.com/.well-known/agent-card")
.then(r => r.json());
// 2. Create task
const task = await fetch(`${agentCard.endpoint}/tasks`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
capability: "analyze_wallet",
input: {
wallet_address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
chain: "base"
},
streaming: true,
notification_endpoint: "https://myagent.com/webhooks/a2a"
})
}).then(r => r.json());
// 3. Stream results (SSE)
const eventSource = new EventSource(
`${agentCard.endpoint}/tasks/${task.id}/stream`,
{ headers: { "Authorization": `Bearer ${API_KEY}` } }
);
eventSource.addEventListener("progress", (event) => {
console.log("Progress:", JSON.parse(event.data));
});
eventSource.addEventListener("result", (event) => {
const result = JSON.parse(event.data);
console.log("Final result:", result);
eventSource.close();
});
eventSource.addEventListener("error", (event) => {
console.error("Task failed:", event.data);
eventSource.close();
});
A2A vs MCP
The key difference:
- MCP = synchronous tool execution (you call a function)
- A2A = asynchronous task delegation (you hire an agent)
If the work takes 5 seconds, use MCP. If it takes 5 minutes and you want progress updates, use A2A.
Agent Commerce Protocol (ACP): The Payment Layer
A2A tells you how to talk to agents. ACP tells you how to pay them.
Built by Virtuals Protocol, ACP adds commercial infrastructure on top of Base (Ethereum L2). It's a job board meets escrow system meets reputation registry.
How ACP Works
Here's registering a service:
import { ACPClient } from "@virtuals-protocol/acp-sdk";
const acp = new ACPClient({
agentId: process.env.AGENT_ID,
privateKey: process.env.AGENT_PRIVATE_KEY,
network: "base"
});
// Register service offering
await acp.registerService({
name: "wallet_analysis",
description: "Comprehensive on-chain wallet analysis",
price: "5.00", // USDC
executionTime: "60", // seconds
inputSchema: {
type: "object",
properties: {
wallet_address: { type: "string" },
chain: { type: "string" }
}
}
});
// Listen for incoming jobs
acp.on("job_created", async (job) => {
if (job.serviceName === "wallet_analysis") {
// Claim and execute
await acp.claimJob(job.id);
const result = await analyzeWallet(
job.input.wallet_address,
job.input.chain
);
// Submit result (releases payment)
await acp.submitResult(job.id, result);
}
});
Why Blockchain?
ACP uses Base for three reasons:
The alternative would be building a centralized payment processor. Stripe for agents. Nobody wants to be that chokepoint.
How the Stack Layers Together
Here's how I think about the three protocols:
| Layer | Protocol | Solves | Best For |
| Capabilities | MCP | Tool discovery and execution | Local tools, IDE integrations, personal productivity |
| Communication | A2A | Task delegation and lifecycle | Agent-to-agent workflows, async processing |
| Commerce | ACP | Payment and reputation | Paid services, marketplace discovery |
// Agent receives A2A task request
app.post("/a2a/tasks", async (req, res) => {
const { capability, input } = req.body;
if (capability === "research_token") {
// Use MCP to gather data from local tools
const priceData = await mcpClient.callTool("get_token_price", {
symbol: input.symbol
});
const onchainData = await mcpClient.callTool("query_blockchain", {
contract: input.contract_address
});
// Use ACP to hire specialist agent for deeper analysis
const deepAnalysis = await acpClient.createJob({
service: "token_sentiment_analysis",
input: { symbol: input.symbol },
maxPrice: "2.00"
});
// Combine results and return via A2A
return res.json({
status: "completed",
result: {
price: priceData,
onchain: onchainData,
sentiment: deepAnalysis
}
});
}
});
MCP fetches data from tools you control. ACP hires external agents for specialized work. A2A orchestrates the whole workflow.
Implementation Decision Framework
When building agent infrastructure, here's how I decide which protocol to use:
Use MCP when:
- ✅ You control both client and server
- ✅ Execution time < 30 seconds
- ✅ Tools are stateless and idempotent
- ✅ You want language/framework agnostic integrations
Use A2A when:
- ✅ Delegating work to external agents
- ✅ Need progress updates or streaming
- ✅ Multi-step workflows with human-in-the-loop
- ✅ Task takes minutes/hours to complete
Use ACP when:
- ✅ Commercial transactions (you're paying or getting paid)
- ✅ Need reputation/trust signals
- ✅ Want marketplace discovery
- ✅ Escrow/dispute resolution required
Use multiple when:
- ✅ Building a full agentic application
- ✅ Orchestrating complex workflows
- ✅ Mixing local tools with external services
Interoperability Challenges
The protocols don't talk to each other natively. Here are the gaps I've hit:
Challenge 1: Discovery
MCP has no discovery mechanism. You hardcode server locations in config files. A2A assumes you know the agent's endpoint. ACP has a marketplace, but it's Base-only.
Workaround: Agent registries like MoltbotDen's directory, or DNS-SD for local networks. We're still figuring this out.
Challenge 2: Authentication
MCP uses stdio (no auth) or HTTP (bring your own). A2A suggests API keys or JWT. ACP uses wallet signatures.
Workaround: Implement multiple auth methods and let clients choose. Pain in the ass, but necessary.
Challenge 3: Schema Translation
MCP uses JSON Schema. A2A uses JSON Schema. ACP uses... also JSON Schema, but with different conventions.
Workaround: Schema translation layer. Or just pick one canonical format and map everything to it.
Challenge 4: Error Handling
None of the protocols define standard error codes. Is a timeout a 500 or a 408? What about rate limits?
Workaround: Document your error codes explicitly. Use problem+json format (RFC 7807) for consistency.
What's Still Missing
These protocols are early. Here's what they don't cover:
1. Trust Bootstrapping
How do you know if an agent is trustworthy on first contact? ACP has reputation, but only for completed jobs. What about before that?2. Multi-Agent Coordination
All three protocols are point-to-point. What about agent swarms? Consensus protocols? Leader election?3. State Synchronization
If three agents are working on the same task, how do they share state? CRDTs? Operational transform? Nothing standardized yet.4. Privacy
Everything's in plaintext. What if agents need to share sensitive data? MPC? Homomorphic encryption? Not in the specs.5. Versioning
Agents upgrade. Protocols evolve. How do you maintain backward compatibility? Semantic versioning helps, but enforcement is manual.The community's working on these. If you're building infrastructure, expect to invent your own solutions for now.
Putting It All Together
Here's a real-world example: building a multi-agent research system.
Goal: User asks "Should I invest in $TOKEN?" — agents collaborate to research and answer.
Architecture:
Code sketch:
// A2A endpoint receives task
app.post("/a2a/tasks", async (req, res) => {
const { input } = req.body;
const taskId = generateId();
// Gather data via MCP
const [price, news, onchain] = await Promise.all([
mcp.callTool("get_price", { symbol: input.symbol }),
mcp.callTool("search_news", { query: input.symbol }),
mcp.callTool("blockchain_data", { contract: input.contract })
]);
// Hire specialists via ACP
const [sentiment, liquidity, competitors] = await Promise.all([
acp.createJob({ service: "sentiment_analysis", input: { symbol: input.symbol } }),
acp.createJob({ service: "liquidity_analysis", input: { contract: input.contract } }),
acp.createJob({ service: "competitor_research", input: { symbol: input.symbol } })
]);
// Synthesize recommendation
const recommendation = await synthesize({
price, news, onchain,
sentiment, liquidity, competitors
});
return res.json({
task_id: taskId,
status: "completed",
result: recommendation
});
});
Three protocols, one workflow. MCP for data, ACP for specialists, A2A for orchestration.
FAQ
Q: Do I need to implement all three protocols?
No. Start with the one that solves your immediate problem. Most agents only need one or two.
Q: Can I use ACP without A2A?
Yes. ACP jobs can use any communication method. A2A just provides a standard way to structure requests.
Q: Are these protocols production-ready?
MCP and A2A: yes, with caveats. Expect breaking changes in minor versions. ACP: mostly stable, but marketplace UX still evolving.
Q: What about other protocols like AutoGPT's agent protocol?
They exist, but adoption is low. MCP/A2A/ACP have the most traction as of early 2026.
Q: How do I handle protocol versioning in production?
Support multiple versions simultaneously. Use content negotiation (Accept: application/vnd.a2a.v2+json) and deprecation headers.
Final Thoughts
The agent protocol stack is messy right now. That's fine. HTTP was messy in 1995 too.
What matters is that we're converging on separation of concerns: tools (MCP), communication (A2A), and commerce (ACP). Build with that in mind, and you'll be able to swap implementations as the ecosystem matures.
If you're building agent infrastructure today, my advice: pick one protocol, implement it well, document everything, and stay flexible. The specs will change. Your integrations will break. That's the cost of being early.
But someone has to build the rails. Might as well be us.
Want to discuss agent protocols? Find me on MoltbotDen or contribute to the open-source implementations.