Deep dive into architecture, implementation details, and code examples for both AI communication protocols
Understanding the architectural differences between MCP and A2A helps developers implement the right solution for their needs.
MCP is designed as a structured format for passing rich context to language models. Its architecture follows a hierarchical structure with clearly defined components:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ MCP Layer │ │ │ │ Application │───▶│ Context Assembly │───▶│ LLM Model │ │ │ │ & Standardization │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ Raw Data │ │ Model Output │ │ Sources │ │ │ └─────────────────┘ └─────────────────┘
MCP approaches the problem from a context quality perspective, focusing on how to structure and enrich the information sent to models in a standardized way. This is fundamentally different from A2A's focus on agent communication channels.
A2A protocol is designed as a communication framework enabling different AI agents to interact, discover capabilities, and collaborate on tasks. Its architecture resembles distributed systems protocols:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ │ │ Agent A │◀──▶│ A2A Protocol │◀──▶│ Agent B │ │ │ │ Message Layer │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ▲ │ ▲ │ ▼ │ │ ┌─────────────────┐ │ │ │Agent Discovery &│ │ └─────────────│ Registry │─────────────┘ └─────────────────┘ │ ▼ ┌─────────────────┐ │ Task Execution │ │ & Coordination │ └─────────────────┘
A2A approaches the problem from a service coordination perspective, focusing on how independent AI services can discover and interact with each other. This resembles microservice architectures more than traditional model input optimization.
How these protocols are implemented in practice, including technical specifications and frameworks.
Implementation Aspect | MCP (Model Context Protocol) | A2A (Agent-to-Agent) |
---|---|---|
Primary Format | JSON-based structure with defined schema | JSON-based messaging with RPC-like conventions |
Transport Layer | Typically HTTP/REST with API providers | HTTP, WebSockets, or message queues |
State Management | Mostly stateless, context embedded in requests | Can maintain conversation state across interactions |
Authentication | Provider API keys, typically simpler | More complex, may involve OAuth, API keys, or custom tokens |
Error Handling | Basic error codes and descriptions | Rich error taxonomy, retry mechanisms, fallback strategies |
Development Tools | Emerging SDKs, minimal current tooling | More comprehensive framework support planned |
Schema Validation | JSON Schema definitions | Both JSON Schema and runtime capability checking |
Both protocols are in early stages of development and face adoption challenges:
Practical examples showing how to implement each protocol in real-world applications.
Here's a simplified example of using MCP to structure context for an LLM call:
// JavaScript/TypeScript Example import { MCPClient } from 'mcp-client'; async function queryWithContext() { const mcpClient = new MCPClient({ apiKey: 'your-llm-api-key' }); // Create an MCP context object const context = { metadata: { version: '1.0', application: 'travel-assistant', session: 'user-123-session-456' }, documents: [ { id: 'doc-1', type: 'flight-info', content: 'Flight AA123 departs at 10:30 AM on June 15th', metadata: { source: 'airline-database', timestamp: '2023-06-10T14:30:00Z', relevance: 0.95 } } ], conversation: { messages: [ { role: 'user', content: 'I need to book a flight to New York next week.', timestamp: '2023-06-10T14:25:00Z' }, { role: 'assistant', content: 'I found several options. When exactly do you want to travel?', timestamp: '2023-06-10T14:26:00Z' }, { role: 'user', content: 'I need to be there by Tuesday afternoon.', timestamp: '2023-06-10T14:27:00Z' } ] }, preferences: { user: { id: 'user-123', travelPreferences: { seatType: 'window', airlinePreference: ['Delta', 'American'], maxConnections: 1 } } } }; // Send query with structured context const response = await mcpClient.query({ model: 'gpt-4', prompt: 'Find the best flight option for this user', context: context }); return response; }
// Example MCP JSON Schema (simplified) { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Model Context Protocol Schema", "type": "object", "required": ["metadata"], "properties": { "metadata": { "type": "object", "required": ["version"], "properties": { "version": { "type": "string" }, "application": { "type": "string" }, "session": { "type": "string" } } }, "documents": { "type": "array", "items": { "type": "object", "required": ["id", "content"], "properties": { "id": { "type": "string" }, "type": { "type": "string" }, "content": { "type": "string" }, "metadata": { "type": "object" } } } }, "conversation": { "type": "object", "properties": { "messages": { "type": "array", "items": { "type": "object", "required": ["role", "content"], "properties": { "role": { "type": "string", "enum": ["user", "assistant", "system"] }, "content": { "type": "string" }, "timestamp": { "type": "string", "format": "date-time" } } } } } }, "preferences": { "type": "object" } } }
Here's a simplified example of implementing A2A protocol for agent communication:
// JavaScript/TypeScript Example import { A2AAgent, CapabilityRegistry } from 'a2a-framework'; // Define an A2A-compliant Travel Planning Agent class TravelPlannerAgent extends A2AAgent { constructor() { super({ agentId: 'travel-planner-agent-001', name: 'Travel Planning Assistant', description: 'Can help plan travel itineraries and book flights/hotels', version: '1.0.0', capabilities: [ { id: 'plan-itinerary', name: 'Plan Travel Itinerary', description: 'Creates a complete travel plan based on user preferences', parameters: { type: 'object', required: ['destination', 'startDate', 'endDate'], properties: { destination: { type: 'string' }, startDate: { type: 'string', format: 'date' }, endDate: { type: 'string', format: 'date' }, budget: { type: 'number' }, preferences: { type: 'object' } } }, returns: { type: 'object', properties: { itinerary: { type: 'array' }, totalCost: { type: 'number' } } } } ] }); // Register capability handlers this.registerCapabilityHandler('plan-itinerary', this.planItinerary.bind(this)); // Register with discovery service CapabilityRegistry.register(this); } // Implementation of capability async planItinerary(params) { // Check if we need help from other specialized agents const flightAgent = await CapabilityRegistry.findAgent('flight-booking'); const hotelAgent = await CapabilityRegistry.findAgent('hotel-booking'); // Send A2A requests to other agents const flightResult = await this.sendA2ARequest(flightAgent.agentId, 'search-flights', { origin: 'user-home-location', // determined from context destination: params.destination, departDate: params.startDate, returnDate: params.endDate, budget: params.budget * 0.4 // allocate 40% of budget to flights }); const hotelResult = await this.sendA2ARequest(hotelAgent.agentId, 'search-hotels', { location: params.destination, checkIn: params.startDate, checkOut: params.endDate, budget: params.budget * 0.4 // allocate 40% of budget to accommodation }); // Combine results and create itinerary const itinerary = this.createItinerary(flightResult, hotelResult, params); return { itinerary: itinerary, totalCost: flightResult.price + hotelResult.price }; } // Helper methods... createItinerary(flights, hotels, params) { // Complex logic to create optimal itinerary return [/* itinerary items */]; } }
// Example A2A Message (Request) { "messageType": "request", "messageId": "msg-12345", "timestamp": "2023-06-15T09:30:00Z", "source": { "agentId": "travel-planner-agent-001", "name": "Travel Planning Assistant" }, "target": { "agentId": "flight-booking-agent-002", "capability": "search-flights" }, "payload": { "origin": "SFO", "destination": "JFK", "departDate": "2023-07-01", "returnDate": "2023-07-08", "budget": 600, "preferences": { "seatClass": "economy", "directOnly": true } }, "metadata": { "priority": "normal", "sessionId": "user-session-789", "timeout": 30000 } } // Example A2A Message (Response) { "messageType": "response", "messageId": "resp-67890", "inResponseTo": "msg-12345", "timestamp": "2023-06-15T09:30:05Z", "source": { "agentId": "flight-booking-agent-002", "name": "Flight Booking Service" }, "target": { "agentId": "travel-planner-agent-001" }, "status": "success", "payload": { "flights": [ { "airline": "Delta", "flightNumber": "DL123", "departureTime": "2023-07-01T08:30:00Z", "arrivalTime": "2023-07-01T11:45:00Z", "price": 450 } ], "price": 450, "currency": "USD" }, "metadata": { "dataSource": "global-flight-database", "resultCount": 1, "filteredFrom": 24 } }
Technical implementation of an adapter pattern to bridge MCP-based services into the A2A ecosystem.
The following code example demonstrates how to create an adapter that wraps an MCP-based service and exposes it as an A2A-compliant agent:
// JavaScript/TypeScript Example of MCP-to-A2A Adapter import { A2AAgent, CapabilityRegistry } from 'a2a-framework'; import { MCPClient } from 'mcp-client'; class MCPtoA2AAdapter extends A2AAgent { constructor(mcpConfig) { super({ agentId: 'mcp-adapter-001', name: 'MCP Service Adapter', description: 'Exposes MCP-based LLM services as A2A capabilities', version: '1.0.0', capabilities: [ { id: 'answer-question', name: 'Answer Questions with LLM', description: 'Answers questions using an LLM with MCP context', parameters: { type: 'object', required: ['question'], properties: { question: { type: 'string' }, contextDocuments: { type: 'array', items: { type: 'object' } }, conversationHistory: { type: 'array', items: { type: 'object' } } } }, returns: { type: 'object', properties: { answer: { type: 'string' }, confidence: { type: 'number' } } } } ] }); // Initialize MCP client this.mcpClient = new MCPClient(mcpConfig); // Register capability handlers this.registerCapabilityHandler('answer-question', this.answerQuestionWithMCP.bind(this)); // Register with A2A discovery service CapabilityRegistry.register(this); } // Adapter method that translates between A2A and MCP async answerQuestionWithMCP(params) { // Convert A2A parameters to MCP context format const mcpContext = { metadata: { version: '1.0', application: 'a2a-mcp-adapter', session: params.metadata?.sessionId || 'unknown-session' }, // Convert A2A context documents to MCP format documents: params.contextDocuments?.map(doc => ({ id: doc.id || `doc-${Math.random().toString(36).substring(2, 9)}`, type: doc.type || 'text', content: doc.content, metadata: doc.metadata || {} })) || [], // Convert A2A conversation history to MCP format conversation: { messages: params.conversationHistory?.map(msg => ({ role: msg.role, content: msg.content, timestamp: msg.timestamp })) || [] } }; // Call MCP service with converted context const mcpResponse = await this.mcpClient.query({ model: 'gpt-4', // Can be configurable prompt: params.question, context: mcpContext }); // Convert MCP response back to A2A format return { answer: mcpResponse.text, confidence: mcpResponse.metadata?.confidence || 0.8, sourceDocuments: mcpResponse.metadata?.sourceDocuments || [] }; } } // Usage example const adapter = new MCPtoA2AAdapter({ apiKey: process.env.MCP_API_KEY, endpoint: 'https://api.mcp-service.com/v1' }); // The adapter now appears as an A2A agent in the ecosystem // that other A2A agents can discover and communicate with