Multi-agent coordination using the A2A open protocol
Build interoperable agents with the A2A standard — define agent cards, implement executors, and exchange structured messages across independent services.
Use this file to discover all available pages before exploring further.
When a single agent isn’t enough, you need a way for specialized agents to delegate work to each other — regardless of which framework, language, or vendor built them. The Agent2Agent (A2A) protocol provides that common language. This page demonstrates how to implement A2A agents using the a2a-sdk, wire them into a multi-agent workflow, and understand how A2A differs from and complements MCP.
Standardizes how agents connect to tools, APIs, and data sources. It defines how an agent uses a capability.
A2A (Agent2Agent Protocol)
Standardizes how independent agents communicate and collaborate as peers. It defines how agents partner and delegate work.
The two protocols are complementary. An agent participating in an A2A interaction might use MCP internally to fulfill its part of the collaborative task.
Every A2A agent implements two methods on AgentExecutor: execute handles incoming requests by pushing events onto the EventQueue, and cancel handles cancellation requests.
An AgentCard is the public description of your agent. Other agents and clients discover it at /.well-known/agent.json.
# --- News Agent ---news_skill = AgentSkill( id='get_latest_news', name='Get Latest News', description='Provides the latest news headline.', tags=['news', 'information', 'tldr'], examples=['what is the news?', 'latest headline', 'give me news'])news_agent_card = AgentCard( name='News Information Agent', description='Provides news headlines for the TLDR of the day.', url=NEWS_AGENT_BASE_URL, version='1.0.0', defaultInputModes=['text'], defaultOutputModes=['text'], capabilities=AgentCapabilities(streaming=True), skills=[news_skill], supportsAuthenticatedExtendedCard=False)news_agent_server_app = A2AStarletteApplication( agent_card=news_agent_card, http_handler=DefaultRequestHandler( agent_executor=NewsInfoAgentExecutor(), task_store=InMemoryTaskStore(), ),).build()# --- Events Agent ---events_skill = AgentSkill( id='get_current_events', name='Get Current Events', description='Provides information about current events.', tags=['events', 'information', 'tldr', 'conference'], examples=['what are the current events?', 'any ongoing events?', 'tell me about events'])events_agent_card = AgentCard( name='Current Events Information Agent', description='Provides updates on current events for the TLDR of the day.', url=EVENTS_AGENT_BASE_URL, version='1.0.0', defaultInputModes=['text'], defaultOutputModes=['text'], capabilities=AgentCapabilities(streaming=True), skills=[events_skill], supportsAuthenticatedExtendedCard=False)events_agent_server_app = A2AStarletteApplication( agent_card=events_agent_card, http_handler=DefaultRequestHandler( agent_executor=EventsInfoAgentExecutor(), task_store=InMemoryTaskStore(), ),).build()
Run each agent server in a separate Python script using uvicorn. Do not run uvicorn.run() inside a notebook cell — it blocks the kernel.
Once you have agents built, you may want a simple web UI for interactive testing without writing a full frontend. The agent-with-streamlit-ui tutorial shows exactly this pattern.The core of the Streamlit chatbot is a generate_response function that calls the OpenAI chat API and a st.chat_input widget that drives the conversation loop:
import streamlit as stimport openaiimport osclient = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))def generate_response(user_prompt, file_content=None): messages = [] if file_content: messages.append({ "role": "system", "content": f"The user has uploaded a file:\n\n{file_content}" }) messages.append({"role": "user", "content": user_prompt}) response = client.chat.completions.create( model="gpt-4o", messages=messages ) return response.choices[0].message.content# Conversation loopif user_msg := st.chat_input("Type your message here..."): st.session_state.messages.append({"role": "user", "content": user_msg}) with st.chat_message("user"): st.markdown(user_msg) with st.chat_message("assistant"): with st.spinner("Thinking..."): assistant_msg = generate_response(user_msg) st.markdown(assistant_msg) st.session_state.messages.append({"role": "assistant", "content": assistant_msg})
Use the Streamlit UI pattern to manually test your A2A agents before integrating them into automated workflows. It gives you a fast feedback loop without building a dedicated test harness.