DEV Community

Fernando Paladini
Fernando Paladini

Posted on

Build a Deterministic Multi-Agent Pipeline with A2A in Python

Multi-agent examples often jump straight to models, tools, and production claims. That makes it difficult to see what the protocol is doing. Before adding an LLM, it is useful to watch a small system discover specialists, delegate a task, and return a result that you can inspect.

This tutorial uses A2A Orchestration Lab, an open-source Python project by Fernando Paladini. It starts three local agents: an orchestrator, a researcher, and a writer. The researcher and writer are deterministic stubs, so the example isolates the Agent2Agent (A2A) communication flow from model behavior.

The result is a runnable research-to-write pipeline that helps explain where A2A fits next to the Model Context Protocol (MCP).

TL;DR

Install the lab with uv, run its demo command, and inspect the three local Agent Cards and the delegated result. The project is a learning lab, not a production runtime. That is a feature for this tutorial because every moving part remains visible.

Prerequisites

You need:

  • Python 3.12 or newer.
  • uv for environment and dependency management.
  • A terminal with network access for the initial dependency download.

The repository declares version 0.1.0, requires Python >=3.12, and depends on the A2A Python SDK, httpx, and uvicorn. It is licensed under MIT.

Create and run the lab

Clone the public repository and let uv create the environment from the locked dependencies:

git clone https://github.com/paladini/a2a-orchestration-lab.git
cd a2a-orchestration-lab
uv sync
Enter fullscreen mode Exit fullscreen mode

Run the bundled end-to-end demo:

uv run a2a-lab demo "Explain A2A and how it relates to MCP"
Enter fullscreen mode Exit fullscreen mode

The CLI starts the three agents as subprocesses, waits for their Agent Cards, sends a message to the orchestrator, prints the response, and terminates the child processes. The default prompt is the same explanation used by the repository README, but using your own prompt makes the delegation easier to recognize.

On a successful run, the output contains sections similar to these:

[demo] asking orchestrator: 'Explain A2A and how it relates to MCP'

## Orchestrator result

**User:** Explain A2A and how it relates to MCP

### Step 1 - Researcher (A2A)
# Research notes

### Step 2 - Writer (A2A)
# Brief
Enter fullscreen mode Exit fullscreen mode

The exact wording is generated by the local stubs and can change with repository updates. The important result is the sequence: the orchestrator receives the prompt, delegates research, then gives the research result to the writer.

Inspect the three agents

The lab can also run each service independently. Open three terminals in the repository and start one command in each:

uv run a2a-lab run researcher
uv run a2a-lab run writer
uv run a2a-lab run orchestrator
Enter fullscreen mode Exit fullscreen mode

The services listen on loopback addresses:

  • Orchestrator: http://127.0.0.1:9100
  • Researcher: http://127.0.0.1:9101
  • Writer: http://127.0.0.1:9102

Each exposes an Agent Card at /.well-known/agent-card.json. For example:

http://127.0.0.1:9100/.well-known/agent-card.json
Enter fullscreen mode Exit fullscreen mode

An Agent Card is the discovery surface. It tells a client what an agent is, where it is available, and which skills or interfaces it advertises. In this lab, opening the cards is a practical way to connect the protocol concept to a real HTTP response.

Stop the three processes with Ctrl+C when you are finished. The one-shot demo command handles child-process cleanup in its finally block.

Follow the delegation path in the source

The most useful source-reading path is short:

  1. Start with src/a2a_lab/cli.py. The cmd_demo function starts the agents and waits for their cards. _ask_orchestrator resolves the orchestrator card, creates an A2A client, and sends a text message.
  2. Read the agent server and executor modules to see how a local process becomes an A2A service and how task lifecycle states are handled.
  3. Read the orchestrator agent to see the client-side delegation to the researcher and writer.

The CLI uses the A2A Python SDK types for a SendMessageRequest, then collects the response stream into text. This is a useful separation: the CLI manages the demo lifecycle, while the agent modules implement the roles.

A2A and MCP solve different boundaries

A2A describes itself as a protocol for agent discovery and task-oriented communication. Its core concepts include messages, tasks, artifacts, Agent Cards, and task updates. In the lab, A2A is the horizontal connection between the orchestrator and its specialist agents.

MCP standardizes connections between LLM applications and external data sources or tools. Its server features include resources, prompts, and tools. MCP is therefore a natural boundary when one agent needs a capability such as filesystem access, search, or a code analysis tool.

A simple mental model is:

user -> A2A orchestrator -> A2A researcher
                       -> A2A writer
                              |
                              -> MCP tools, when a specialist needs them
Enter fullscreen mode Exit fullscreen mode

The lab does not implement MCP. Its README explicitly treats MCP as a later addition after the A2A learning path. That makes the project a good place to understand agent-to-agent delegation before introducing another protocol.

What the demo proves, and what it does not

The smoke test proves that the declared Python environment resolves, the three services start, Agent Cards become reachable, a client can send a message to the orchestrator, and the pipeline returns a result. It does not prove model quality, distributed reliability, authentication, or production readiness.

The project intentionally lists several missing production concerns: portable task checkpointing, capability tokens, strong sandboxing, multi-vendor identity and trust, budgets, audit as a primitive, and governed business context. Treat that list as an implementation boundary, not as a roadmap promise.

The lab also uses loopback HTTP services and local knowledge-base stubs. Do not expose the three ports to a network and assume that localhost implies authorization. If you replace the stubs with real tools or models, add authentication, authorization, timeouts, rate limits, structured logs, and explicit data handling rules before handling sensitive input.

Failure modes and troubleshooting

If uv sync fails, verify the Python version with python --version and the tool with uv --version. The project requires Python 3.12 or newer.

If the demo reports that an agent is not ready, check whether ports 9100, 9101, or 9102 are already in use. The CLI waits up to 15 seconds for each Agent Card. Stop stale processes and try again.

If the demo prints a result but the content is unexpectedly short, remember that the researcher and writer are deterministic stubs. Change the local knowledge base or prompt to explore the flow. Adding an LLM is a separate experiment, not a prerequisite for understanding A2A.

FAQ

Does this lab require an API key?

No. The README describes the first-day workflow as local and without API keys. Its current agents use deterministic stubs.

Is A2A a replacement for MCP?

No. A2A connects agents to agents. MCP connects an AI application to tools and data sources. A system can use both, with an A2A specialist invoking MCP tools when that capability belongs inside the specialist boundary.

Does the demo run forever?

No. uv run a2a-lab demo starts the agents, runs one task, prints the result, and shuts them down. Use the separate run commands when you want to inspect services manually.

Is this ready for production?

No. The project explicitly describes itself as a learning lab and names the lifecycle, identity, capability, budget, audit, and governance gaps that remain.

Takeaway

A2A becomes easier to reason about when the first example is deterministic. The Orchestration Lab gives you three inspectable local services, discoverable Agent Cards, a real delegation path, and a clear place to add MCP later.

I used AI assistance to organize and edit this tutorial. The repository README, pyproject.toml, learning notes, CLI source, MIT license, official A2A specification, official MCP specification, and a live uv sync plus demo run were checked separately.

What would you replace first in this lab: the researcher stub, the writer stub, or the orchestrator's routing logic?

Top comments (0)