Skip to content
Effloow
← Back to Articles
AI INFRASTRUCTURE ARTICLES ·2026-09-24 ·BY EFFLOOW EDITORIAL ·14 MIN READ

Google A2A 1.0 in Production: Our Multi-Vendor Interoperability and Compatibility Audit

We tested Google A2A 1.0 between local Python agents, including discovery, task lifecycle, artifacts, authentication, and migration from pre-1.0 agent cards. Here is what worked, what broke, and where an adapter layer remains necessary.
A2A Agent Infrastructure Interoperability Python Production Engineering
SHARE
Illustration for Google A2A 1.0 in Production: Our Multi-Vendor Interoperability and Compatibility Audit
Illustration: AI-assisted. Editorial policy

Why We Brought This Tool Into Our Lab

We tested Google's Agent-to-Agent protocol, or A2A, to evaluate communication between independently built AI agents rather than produce another demo. We brought it in to evaluate whether a shared protocol could reduce custom translation code when agents use different request and response formats.

A2A 1.0 needs a compatibility layer

A2A 1.0 handled discovery, task lifecycle, authentication failures, and artifacts between local agents, but pre-1.0 agent cards and methods did not work directly, so a versioned translation proxy remained necessary for backward compatibility.

One agent accepts web requests using Hypertext Transfer Protocol, or HTTP. Those requests use custom data fields encoded in JavaScript Object Notation, or JSON, a format for representing data as text. Another expects a continuous stream of updates. A third returns a job identifier that the client must use to check repeatedly for results. Authentication, cancellation, progress updates, and generated files all use different conventions. The first integration looks manageable; by the fifth, the team has substantial integration code to maintain.

A2A addresses that boundary. It gives agents a shared way to find each other, exchange messages, track work, send updates, cancel tasks, and deliver artifacts such as generated files. It does not standardize an agent's internal model, prompt framework, memory system, or tool implementation.

That distinction mattered in our evaluation. We tested whether A2A let agents exchange work reliably, not whether it chose agents or coordinated their work.

We anchored our test plan to three primary references: the original A2A interoperability announcement, the A2A 1.0 backward-compatibility discussion, and n8n's A2A implementation analysis. We then turned the protocol concepts into tests we could run. Successful discovery meant finding an agent and reading its connection details and capabilities, not proving that it could work with another agent.

Our local test setup contained two Python agents:

  • Coordinator agent: accepted a research request and delegated document rendering.
  • Renderer agent: accepted structured data and returned a Markdown artifact.
  • Compatibility proxy: a service that converted selected pre-1.0 agent descriptions and messages into formats the new client accepted.
  • Mock identity service: issued fixed bearer tokens, which grant access to whoever presents them, for tests with valid and invalid credentials.
  • Test client: recorded discovery responses, task states, artifacts, HTTP status codes, and protocol errors.

Agents published an agent card, a document describing how to contact them and which requests they accept. They exchanged structured requests and exposed task records with explicit status information. We inspected requests and responses with the command-line tool curl, the Python HTTP client httpx, and a reverse proxy that forwarded traffic to the agents. We could understand these exchanges without adding monitoring code inside a vendor's agent software.

We also confirmed what A2A did not handle. It did not choose an agent for a task or guarantee that two agents understood a skill the same way. It did not automatically exchange OAuth credentials, which let applications access services with permission, or accept arbitrary older request formats. We still had to decide where requests went, which callers we trusted, and which data formats we accepted. We also needed compatibility tests.

A2A connects agents to each other, while the Model Context Protocol, or MCP, connects an AI application to tools and sources of context. We use MCP primarily between an AI application and tools or context providers. We use A2A between autonomous or semi-autonomous services that expose agent-level capabilities. Combining them is reasonable: an A2A agent can invoke MCP tools internally. Replacing one with the other usually produces an awkward abstraction.

Hands-On Walkthrough: Setup, Execution & Output

We ran the audit in a separate Python environment and limited the software development kit, or SDK, to one major version. The kit supplies code for building software that uses the protocol. We also cloned the sample repository so that our first control run used the published sample structure before we introduced our own coordinator and renderer logic.

Our setup sequence was:

git clone --depth 1 https://github.com/a2aproject/a2a-samples.git
python3 -m venv .venv
. .venv/bin/activate

python -m pip install --upgrade pip
python -m pip install "a2a-sdk>=1.0,<2" httpx uvicorn pytest pytest-asyncio

# We recorded the resolved versions in the audit artifact.
python -m pip freeze > a2a-lab.lock

# We first ran the repository's Python sample following its checked-in README.
# We then started our two-agent fixtures on separate loopback ports.
python lab/renderer_agent.py --host 127.0.0.1 --port 8101 \
  --token renderer-lab-token > logs/renderer.log 2>&1 &

python lab/coordinator_agent.py --host 127.0.0.1 --port 8102 \
  --renderer-url http://127.0.0.1:8101 \
  --renderer-token renderer-lab-token > logs/coordinator.log 2>&1 &

python -m pytest -q tests/test_discovery.py \
  tests/test_task_lifecycle.py \
  tests/test_artifacts.py \
  tests/test_auth.py \
  tests/test_legacy_cards.py

We kept the agents deliberately simple. The coordinator received a text request, converted it into a structured rendering request, and called the renderer through its advertised A2A interface. The renderer emitted a Markdown artifact instead of returning the content only as conversational text.

Our test sequence covered five parts of agent communication:

  1. Discover the renderer's agent card.
  2. Select a communication method the agent supports rather than assuming one in advance.
  3. Submit a message and follow its task state.
  4. Retrieve and validate the resulting artifact.
  5. Repeat the exchange with missing, invalid, and valid credentials.

We separately supplied a fixture, a pre-1.0 agent card used as controlled test data. It listed one service address and did not specify how the client and agent should agree on a protocol version. It also used the older operation names and task fields our legacy client expected. We tested the card directly with the 1.0 client, then repeated the test through our compatibility proxy.

The shortened simulated transcript below comes from our fixture mode, which produces the same output for the same test inputs. We used this output to avoid presenting timings from agents running on the same machine as evidence of production performance.

$ python lab/run_matrix.py --emit-fixture

[discovery] GET http://127.0.0.1:8101/.well-known/agent-card.json
[discovery] HTTP 200
[discovery] name="Effloow Renderer" protocolVersion="1.0"
[discovery] binding="JSONRPC" auth="Bearer"

[auth-negative] send without Authorization header
[auth-negative] HTTP 401 WWW-Authenticate="Bearer"

[auth-negative] send with invalid token
[auth-negative] HTTP 403 error="invalid_token"

[auth-positive] send with renderer-lab-token
[task] id="task-7f31" state="submitted"
[task] id="task-7f31" state="working"
[artifact] name="audit-summary.md" mediaType="text/markdown"
[task] id="task-7f31" state="completed"

[artifact-check] sha256 fixture match: PASS
[context-check] request context preserved: PASS
[terminal-state-check] completed task immutable: PASS

[legacy-direct] old discovery path: HTTP 404
[legacy-direct] top-level url without negotiated interface: REJECTED
[legacy-direct] legacy task method: METHOD_NOT_FOUND
[legacy-direct] sessionId field: SCHEMA_ERROR

[legacy-via-proxy] discovery path fallback: PASS
[legacy-via-proxy] interface normalization: PASS
[legacy-via-proxy] task method translation: PASS
[legacy-via-proxy] sessionId to contextId mapping: PASS

13 passed, 0 failed

The authentication result deserves emphasis. Advertising a bearer or OAuth-compatible security scheme in an agent card did not authenticate anything by itself. We still had to configure who issued tokens, which service could accept them, and when they expired. We also needed request checks that limited each caller's access to tasks.

For the local test, a fixed bearer token was sufficient because we were testing connection setup and failures, not the service that verifies identities. In production, we would use short-lived credentials and check who issued them and which service they were intended for. We would also tie task retrieval and cancellation to a verified caller.

The artifact test also caught more than a normal chat response test. We checked the file type, filename, and associated task. We also compared a checksum—a value calculated from the file's contents; and checked behavior after the task finished. That gave us a concrete contract for generated files rather than relying on text hidden in a message body.

Teams building similar automated tests can use our broader AI tools collection to compare related infrastructure tools. For architecture or migration support, see effloow services.

Compatibility Failures and Implementation Limits

Our 1.0 exchange worked under the expected successful conditions. Compatibility with pre-1.0 assumptions did not work automatically.

The first breakage occurred during discovery. Our legacy fixture requested its known discovery location and expected one top-level service URL. The 1.0 endpoint returned no card at that location, and the newer card required the client to select an interface. The client never reached message submission.

We handled this in the compatibility proxy. It answered requests at both discovery addresses and converted the older service address into the interface format the new client expected. It also kept the original card for troubleshooting. We left both agents' application code unchanged.

The second failure involved method dispatch: how the server selects the operation that handles a request. The legacy client invoked its historical task-oriented method, while our 1.0 endpoint accepted the current message-oriented operation. The server correctly returned a method error. Retrying the identical body under a different method name was not enough because the nested message and task fields also differed.

Our workaround translated the complete request and response pair:

  • older operation names to their 1.0 equivalents;
  • older session identifiers to the identifiers now used to group related exchanges;
  • older message components to the structure the new service accepted;
  • current task states to the status format the older client expected;
  • details about generated files to the older response format wherever it could preserve them.

By default, we rejected translations that would discard information. If a 1.0 response contained multiple artifacts or a capability the old client could not represent, our proxy returned an explicit compatibility error instead of silently dropping data. That policy made compatibility failures explicit instead of reporting success when data was missing.

The third issue was advertised capabilities that did not work in every case. Listing streaming, authentication, or a skill in an agent card did not prove that the agent consistently supported it. After discovery, we added conformance checks: requests that tested whether the agent actually supported its advertised capabilities. Our client used the card to choose what to test, not as proof of compatibility.

The fourth issue was the order of task updates. In an early version, our renderer reported completed before it saved the generated file with the task. A fast client could see a terminal state, meaning the task had ended, yet receive no generated files. We changed the renderer to save files reliably before marking the task as finished.

We also prevented finished tasks from changing state. Otherwise, a worker retrying an operation could mark a completed task as working again. A state machine controls which task states can follow others, and using the protocol's labels did not make ours correct.

Cancellation exposed another ambiguity. We could request cancellation, but we could not assume that an underlying model call or external tool stopped instantly. We therefore distinguished between receiving a cancellation request and confirming a canceled terminal state. Our worker checked for cancellation between processing steps and stopped publishing files once it had marked the task as canceled.

Authentication produced predictable but operationally important failures. A card describing a security scheme did not tell our client where its credentials should come from in every deployment. We had to configure that relationship outside the task message. We also had to ensure that logs redacted authorization headers and that redirected requests did not forward tokens to an untrusted host.

Finally, matching version labels did not establish compatibility. Two services can both mention A2A 1.0 yet differ in communication methods, authentication, file formats, streamed updates, or optional features. We now save a record of supported capabilities for each agent and card version, then stop using that record when the card changes.

Our rule: require data to match the expected format inside the core service. Handle known older formats only in a versioned adapter that translates them. Save data from failed exchanges as reusable compatibility test inputs, with sensitive information removed.

Scale, Latency & Cost vs. Alternatives

We did not publish response-time or processing-rate measurements from this audit. Both agents ran on the same machine and performed fixed work, so those measurements would describe our test setup more than A2A in production. Our three sources also did not measure performance under comparable conditions that would support comparisons across products.

We instead evaluated the network path structurally.

A synchronous A2A request keeps the caller waiting while the agent works, adding request handling, data checks, authentication, and conversion into a format the receiver understands. Streaming sends updates over an open connection and must handle receivers that cannot keep up. Asynchronous tasks let the caller continue while work runs, but require stored task state and repeated checks, streamed updates, or notifications. A compatibility proxy adds another network step unless it runs within the application or alongside it on the same machine.

Those costs are usually small compared with running a model or waiting for an external tool, but they can dominate agents that do simple, fixed work. We would not route a sub-process function call through A2A merely to claim protocol consistency.

Option What we would use it for Interoperability burden Operational trade-off Lock-in profile
A2A 1.0 Agent discovery, delegation, tasks, artifacts, and status Medium initially, lower across conforming peers Requires conformance tests, task storage, auth, and version policy Lower at the agent boundary
MCP Connecting an AI application to tools and context Low to medium Strong fit for tool exposure; not our preferred agent-task lifecycle Lower at the tool boundary
Custom REST or gRPC Stable internal services with tightly controlled callers. Representational State Transfer, or REST, organizes web requests around resources such as tasks. gRPC lets one service call functions in another. Low for the first integration, rising with each peer Maximum control, but we define every convention for tracking work High unless other systems can use the same data formats
Workflow webhooks Webhooks notify another service when an event occurs, allowing teams to trigger automated workflows. Low for simple triggers Easy to operate until tracking long-running work becomes complex Medium and platform-dependent
Queue-specific RPC Remote procedure calls, or RPC, let services request work from other services, here through a queue for high-volume internal processing. Medium Strong internal control; outside services need a gateway to connect High dependence on the queue service and its message formats

For cost, we used an explicit engineering model rather than pretending the protocol itself has a licensing price. A2A itself was not our main expense. Our bill came from adapter work, security review, conformance automation, task persistence, and operations.

Our planning example assumed three days of one engineer's work for each custom connector between two platforms and four days for each vendor-facing A2A adapter. Connecting every pair of four agent platforms requires six custom integrations, totaling 18 engineer-days in this model. Four A2A adapters total 16 engineer-days.

That is only a break-even illustration, not a universal estimate. Under our illustrative assumptions, a custom connector costs less at two platforms, while A2A adapters cost less at four fully interconnected platforms. These crossover points depend on the assumed engineering effort and connection topology; they are not measured adoption thresholds.

Costs fall further when we run the compatibility tests in continuous integration, or CI, which checks every code change automatically. Each new agent implementation runs against the same discovery, auth, lifecycle, and artifact tests. We still write vendor-specific adapters, but we stop rewriting the acceptance criteria.

A2A did not eliminate integration engineering in our lab. It moved that work from ad hoc business code into a reusable protocol and compatibility layer. That is a meaningful improvement, but it is not zero-cost interoperability.

What This Audit Could Not Verify

This local audit did not establish production response times or processing capacity. Our sources also did not provide comparable performance measurements across products.

Our Final Verdict: When to Deploy, When to Skip

Our verdict is positive with conditions. A2A 1.0 is useful when we treat it as a tested network contract. It is risky when we treat the presence of an agent card as proof that two systems will cooperate.

Deploy this if:

  • We operate agents owned by different teams, vendors, or runtime stacks.
  • We need explicit task states rather than a single synchronous chat response.
  • We exchange files or structured artifacts that must remain associated with a task.
  • We need to learn what agents can do and agree with them on how to communicate.
  • We can run conformance checks against every agent release.
  • We are willing to keep authentication, authorization, and identity policy outside the conversational payload.
  • We expect enough integrations for shared A2A adapters to require less work than separate connectors between every pair of services.
  • We can persist task state and enforce valid transitions under retries and cancellation.

Hold off or avoid this if:

  • We have one caller and one stable internal service.
  • A normal function call, queue message, or typed REST endpoint already solves the problem.
  • We need every response to meet a strict deadline, and another HTTP request with validation checks is unacceptable.
  • Our agents cannot provide stable descriptions of their capabilities, accepted inputs, returned outputs, or generated files.
  • We expect A2A to coordinate work, choose agents based on request meaning, issue credentials, or enforce our application's access rules.
  • We cannot test old and new card formats during migration.
  • We need guaranteed compatibility with pre-1.0 clients but cannot operate a translation boundary.

For a system already using pre-1.0 agents, we would not upgrade every agent in place. We would first list how clients find agents, interpret their cards, send requests, group related exchanges, track tasks, handle generated files, and authenticate. We would then place a compatibility proxy in front of one non-critical agent. We would test saved requests through both the direct and proxy connections and reject any translation that loses information.

After that, we would update clients to agree directly with agents on a supported 1.0 interface and track use of the older connection method. We would name an adapter owner and define usage thresholds for retiring it, so temporary compatibility code did not become permanent by default.

The strongest outcome from our lab was not that two Python processes exchanged a message. Custom HTTP could have done that in an afternoon. The stronger result was that we could turn interoperability into a repeatable test matrix covering discovery, authentication failure, state transitions, cancellation, and artifacts.

The weakest point was backward compatibility. Pre-1.0 assumptions did not become safe merely because the current endpoint implemented A2A 1.0. We needed explicit translation, dual discovery support, and negative tests. We would test each legacy client directly before deciding whether it needs a translation layer; our fixture failures do not establish that every pre-1.0 migration requires one.

We would deploy A2A for a multi-vendor agent platform, but only behind a compatibility gateway and only with conformance tests in CI. For two closely connected internal services, we would keep a simpler application programming interface, or API, with defined request and response types. We would add A2A only when we had enough separate agents to justify the extra integration work.

If that boundary is already becoming expensive, contact our infrastructure team before adding another one-off connector. A week spent defining the compatibility contract is usually cheaper than discovering, during a vendor migration, that every agent interpreted the same task differently.

Get the next one
in your inbox.

One short weekly dispatch with new guides, tools, and what we tested. No spam, unsubscribe anytime.

Get weekly AI tool reviews & automation tips

Join our newsletter. No spam, unsubscribe anytime.

More in Articles

Tools you can use