---
description: Use the A2A Inspector to validate agent cards and debug A2A servers, then test with curl, SDK clients and the TCK, and trace production tasks in Bifrost.
title: "A2A Inspector: How to Test and Debug A2A Agents"
image: https://storage.ghost.io/c/84/03/8403f2f6-141c-411a-8f55-a32d4291533e/content/images/size/w1200/2026/10/a2a-inspector-how-to-test-and-debug-a2a-agents-bifrost-1920x1080.png
---

Try Bifrost Enterprise free for 14 days. [Request access](https://www.getmaxim.ai/#enterprise-trial)

**TL;DR**

- The A2A Inspector is the A2A project's open-source web tool that fetches an agent card, runs basic spec checks on it, and shows the raw JSON-RPC 2.0 messages exchanged with an A2A server.
- A2A v1 uses PascalCase JSON-RPC methods such as `SendMessage`, `GetTask`, and `CancelTask`; a server that answers only `message/send` is speaking v0.3.
- curl, the official A2A SDK clients, and the A2A Technology Compatibility Kit (TCK) cover the scripted, integration, and conformance testing the A2A Inspector does not.
- An HTTP 200 JSON-RPC response can carry a task in the failed state, so the task state, not the HTTP status, says whether the agent's work succeeded.
- Bifrost Agent Logs groups A2A operations into sessions by context ID and links them to LLM and MCP calls that carry the `x-bf-session-id` and `x-bf-agent-correlation-id` headers.

The A2A Inspector is the A2A project's open-source web tool for connecting to an Agent2Agent (A2A) server, validating its agent card, and reading the raw JSON-RPC messages it exchanges. It shows whether an agent speaks the protocol correctly, but not who called it in production or why a task failed behind an HTTP 200. [Bifrost](https://www.getmaxim.ai/), the [open-source AI gateway for model, tool, and agent traffic](https://github.com/maximhq/bifrost) built by Maxim AI, covers that second half by recording A2A operations alongside the LLM and MCP calls behind them. This guide covers the A2A Inspector, its alternatives, and production debugging behind a gateway.

## What Is the A2A Inspector?

The A2A Inspector is a FastAPI and TypeScript web application from the A2A project. It connects to an A2A server by URL, validates its agent card, and opens a chat session with a debug console. It checks structure and shows wire traffic during development; it is not a full conformance suite.

The [A2A Inspector repository](https://github.com/a2aproject/a2a-inspector) and its backend source show four functions:

- **Agent card retrieval** from a base URL or the full card path.
- **Spec compliance checks** that flag a missing `name`, `description`, `version`, or `skills` field, a card with neither a v0.3 `url` nor v1.0 `supportedInterfaces`, interfaces without `url` or `protocolBinding`, and an empty skills list.
- **Live chat** through the official A2A Python SDK client, with each task, message, or update checked for fields such as `status.state` and a non-empty `parts` array.
- **A debug console** showing the raw JSON-RPC 2.0 requests and responses.

An **Authentication & Headers** panel supports Basic, Bearer, and API key authentication plus custom headers, and the backend handles both v0.3 and v1.0 cards. The Inspector tests one agent in isolation; shared infrastructure raises routing and access questions, covered in [running A2A traffic through a gateway](https://www.getmaxim.ai/articles/a2a-protocol-gateway/).

## How to Run the A2A Inspector Locally

The tool runs either as two development processes (a frontend build watcher and a Uvicorn backend on port 5001) or as one Docker container serving the UI on port 8080. Both start from a clone of the repository; the local path also needs Python, uv, Node.js, and npm.

```bash
git clone <https://github.com/a2aproject/a2a-inspector.git>
cd a2a-inspector

# Option 1: local processes, then open <http://127.0.0.1:5001>
uv sync
(cd frontend && npm install)
bash scripts/run.sh

# Option 2: Docker, then open <http://127.0.0.1:5002>
docker build -t a2a-inspector .
docker run -d -p 5002:8080 --add-host=host.docker.internal:host-gateway a2a-inspector
```

Upstream maps the container to host port 8080, which collides with a [Bifrost gateway](https://docs.getbifrost.ai/overview) on `localhost:8080`, so the example uses 5002. The backend fetches cards from inside the container, so an agent on your machine is `http://host.docker.internal:<port>`, not `localhost`. To inspect an agent registered in Bifrost, enter its gateway card URL, such as `http://host.docker.internal:8080/agents/a2a/library-research/.well-known/agent-card.json`, and add your virtual key as a custom `x-bf-vk` header. Chat uses the card's endpoints, built from Bifrost's External Client URL, which must also resolve inside the container.

## A2A Inspector Alternatives for Testing A2A Agents

The main A2A Inspector alternatives are curl against the JSON-RPC and REST bindings, the official SDK clients, the A2A samples CLI, and the A2A TCK. Each fits a different testing stage, from smoke tests to production.

| Tool | What it tests | Best stage | Transports |
| --- | --- | --- | --- |
| A2A Inspector | Card structure, interactive chat, raw JSON-RPC | Local development | Through the Python SDK client |
| curl | Exact request bodies, error codes, headers | Smoke tests, CI scripts | JSON-RPC, HTTP+JSON |
| [A2A Python SDK](https://github.com/a2aproject/a2a-python) and A2A JS SDK clients | Multi-turn flows, streaming, cancellation | Integration tests | JSON-RPC, HTTP+JSON, gRPC |
| A2A samples CLI | Card read and text chat in a terminal | Manual checks | Streams when supported |
| [A2A TCK](https://github.com/a2aproject/a2a-tck) | MUST, SHOULD, and MAY spec requirements | Pre-release conformance | gRPC, JSON-RPC, HTTP+JSON |
| [Bifrost Agent Logs](https://docs.getbifrost.ai/features/agent-gateway/observability) | Sessions, task state, events, correlated calls | Staging and production | JSON-RPC, REST, gRPC |

The TCK is the automated counterpart to the Inspector: `./run_tck.py --sut-host http://localhost:9999` runs the suite, `--transport` and `--level` narrow it, and reports land in `reports/`. See also [open-source agent gateways for MCP and A2A](https://www.getmaxim.ai/articles/best-open-source-agent-gateways-for-mcp-and-a2a-in-2026/).

## How to Test an A2A Server with curl

Testing an A2A server with curl means fetching its agent card, reading the interface URL it advertises, and posting JSON-RPC 2.0 bodies with the v1 method names: `SendMessage`, `SendStreamingMessage`, `GetTask`, `ListTasks`, `CancelTask`, and `SubscribeToTask`. Send `A2A-Version: 1.0` on every request.

```bash
AGENT=http://localhost:9999
CARD=$(curl -s "$AGENT/.well-known/agent-card.json")
echo "$CARD" | jq '{name, version, interfaces: .supportedInterfaces}'
RPC_URL=$(echo "$CARD" | jq -r '[.supportedInterfaces[] | select(.protocolBinding == "JSONRPC")][0].url')

curl -s "$RPC_URL" \
  -H "Content-Type: application/json" \
  -H "A2A-Version: 1.0" \
  -d '{
    "jsonrpc": "2.0",
    "id": "req-1",
    "method": "SendMessage",
    "params": {
      "message": {
        "messageId": "msg-1",
        "role": "ROLE_USER",
        "parts": [{"text": "Summarize the open incidents for the payments service."}]
      }
    }
  }' | jq '.result'
```

The result holds a `message` (direct reply) or a `task`. Save `task.id` and `task.contextId`, then poll, stream, or cancel, replacing `TASK_ID`:

```bash
curl -s "$RPC_URL" -H "Content-Type: application/json" -H "A2A-Version: 1.0" \
  -d '{"jsonrpc": "2.0", "id": "req-2", "method": "GetTask", "params": {"id": "TASK_ID", "historyLength": 5}}'

curl -N "$RPC_URL" -H "Content-Type: application/json" -H "Accept: text/event-stream" -H "A2A-Version: 1.0" \
  -d '{"jsonrpc": "2.0", "id": "req-3", "method": "SendStreamingMessage", "params": {"message": {"messageId": "msg-2", "role": "ROLE_USER", "parts": [{"text": "Write a status report for the payments service."}]}}}'

curl -s "$RPC_URL" -H "Content-Type: application/json" -H "A2A-Version: 1.0" \
  -d '{"jsonrpc": "2.0", "id": "req-4", "method": "CancelTask", "params": {"id": "TASK_ID"}}'
```

The HTTP+JSON binding appends resource paths to its interface URL instead: `POST $REST_URL/message:send` with `Content-Type: application/a2a+json` a body whose top-level `message` field holds the same message object, and `GET $REST_URL/tasks/TASK_ID`. The [A2A specification](https://a2a-protocol.org/latest/specification/) serializes enums by ProtoJSON name (`ROLE_USER`, `TASK_STATE_COMPLETED`). Read the error object as closely as the result:

| JSON-RPC code | Meaning | Common cause when testing |
| --- | --- | --- |
| `-32601` | Method not found | v0.3 name such as `message/send` sent to a v1-only server |
| `-32602` | Invalid parameters | Missing `messageId`, or a v0.3 role such as `user` |
| `-32002` | Task not cancelable | `CancelTask` on a completed task |
| `-32001` | Task not found | Wrong task ID, or an endpoint without a shared task store |
| `-32004` | Unsupported operation | `SubscribeToTask` on a task in a terminal state |
| `-32009` | Version not supported | `A2A-Version` names a version the interface does not serve |
| `-31403` | Agent access denied (Bifrost) | The virtual key or project has no grant for this agent |

Through Bifrost, the same body goes to the agent's gateway route, such as `http://localhost:8080/agents/a2a/library-research/json-rpc`, with an `x-bf-vk` header carrying a [virtual key](https://docs.getbifrost.ai/features/governance/virtual-keys).

## Validating the A2A Agent Card

Validating an A2A agent card means confirming the required fields exist and that every advertised interface is reachable from where the client runs. The Inspector catches missing fields; it cannot tell you a `supportedInterfaces` URL resolves on your laptop but not inside a cluster.

Check these for every A2A server you publish:

- **Location:** `/.well-known/agent-card.json` unless your registry or gateway uses another path.
- **Required fields:** `name`, `description`, `version`, and a non-empty `skills` array.
- **Interfaces:** each entry has a `url`, a `protocolBinding` of `JSONRPC`, `HTTP+JSON`, or `GRPC`, and a `protocolVersion`; gRPC addresses are `host:port`.
- **Order:** Bifrost uses card order as the [initial transport preference](https://docs.getbifrost.ai/features/agent-gateway/transports-and-recovery), so list the preferred interface first.
- **Shared state:** interfaces on one card need one task store, because a task created over JSON-RPC and read over gRPC must exist on both.

A card that passes the Inspector can still fail registration. Bifrost returns HTTP 400 with `upstream runtime origin is not permitted by credential_origins` when a card at port 19181 advertises a runtime on port 19182 that has not been [approved as an agent endpoint](https://docs.getbifrost.ai/features/agent-gateway/troubleshooting).

## AI Agent Testing for A2A: Unit, Integration, and Production

AI agent testing for A2A runs in three layers. Unit tests check executor logic with the model stubbed out. Integration tests drive a running A2A server through an SDK client across multi-turn, streaming, and cancellation paths. Production debugging reads real traffic, with caller identity and model calls attached, at the gateway.

![Five A2A testing layers flow left to right: unit tests, agent card validation with the A2A Inspector, TCK conformance, integration calls, and production debugging in Bifrost Agent Logs](https://articles-images-cdn.t3.tigrisfiles.io/diagrams/a2a-inspector/a2a-inspector-testing-layers.png)

*Figure 1: Run the cheap layers first; the gateway layer is where access, latency, and failed-task problems become visible.*

As Figure 1 shows, each layer catches a different class of bug:

- **Unit tests** cover state transitions, artifact construction, and the `input-required` branch.
- **Card validation and conformance** run the Inspector during development and the TCK in CI.
- **Integration tests** continue an `input-required` task with the same task ID, drop a stream before completion, and call `CancelTask` on running and finished work.
- **Production debugging** answers which caller started a task, whether it was allowed to, and what the agent's model and tool calls returned.

The last layer is where the [differences between an agent gateway and an LLM gateway](https://www.getmaxim.ai/articles/agent-gateway-vs-llm-gateway/) become practical, because the failure is often in a call the agent made rather than in the A2A exchange.

## Debugging A2A Agents in Production with Bifrost Agent Logs

[The Bifrost gateway](https://www.getmaxim.ai/) records each A2A operation it routes in **Observability → Agent Logs**, groups operations into sessions by A2A context ID, and opens each one into tabs for the conversation, payload, stream events, correlated LLM and MCP calls, and raw capture. This is the production view a local inspector cannot provide.

![Debugging path in Bifrost Agent Logs: open the agent session by context ID, open the SendMessage operation, read the failed task in Conversation, then inspect correlated MCP and LLM logs](https://articles-images-cdn.t3.tigrisfiles.io/diagrams/a2a-inspector/a2a-inspector-failed-task-path.png)

*Figure 2: A Success status describes the protocol exchange; the task state in the Conversation tab says whether the agent's work succeeded.*

Filter by agent, status, task state, or caller; search matches metadata such as IDs and errors, not message contents. The [Agent Gateway in Bifrost](https://www.getmaxim.ai/bifrost/blog/introducing-agent-gateway-in-bifrost-one-gateway-for-models-tools-and-agents) launch post walks the same flow on a research agent.

- **Task state over status.** An agent that cannot finish still returns an HTTP 200 JSON-RPC response with the task in `result`, so the operation shows **Success** while the task reports `failed`. Figure 2 traces the path from there.
- **Stream events in order.** The **Events** tab on `SendStreamingMessage` and `SubscribeToTask` lists status and artifact updates in sequence; a stream ending does not mean the task completed.
- **Agent time versus gateway time.** **Upstream latency** measures the agent-facing call and **Overhead** the rest, split into protocol library, middleware, plugins, serialization, processing, and client delivery.
- **Raw capture when needed.** Raw capture is off by default; enable **Capture Raw Request and Response** in **Agents → Agent Settings** and send a fresh request. It is limited to 1 MiB per direction, unavailable for gRPC, and not guaranteed to be secret-redacted.

The same operations export to [OpenTelemetry, Prometheus, Datadog, and other connectors](https://docs.getbifrost.ai/features/agent-gateway/connectors), keeping agent telemetry in the [same gateway-layer observability stack](https://www.getmaxim.ai/ai-observability) as model traffic.

## Agent Tracing: Linking A2A Tasks to LLM and MCP Calls

Agent tracing across A2A works when the agent sends its model and tool calls through Bifrost with two headers: `x-bf-session-id` set to the A2A context ID and `x-bf-agent-correlation-id` set to the A2A task ID. Bifrost cannot infer those IDs from a separate model request, so the agent must attach them.

![A client calls an A2A agent through Bifrost; the agent sends LLM and MCP calls with correlation headers, and Agent Logs joins them by ID](https://articles-images-cdn.t3.tigrisfiles.io/diagrams/a2a-inspector/a2a-inspector-correlation-headers.png)

*Figure 3: Without the two correlation headers, Agent Logs shows the A2A exchange but cannot connect the model and tool calls behind it.*

Read both IDs from the A2A server's execution context and attach them to every outgoing call, as shown in [connecting model and tool calls](https://docs.getbifrost.ai/features/agent-gateway/integrating-your-agent):

```bash
curl <http://localhost:8080/v1/chat/completions> \
  -H "Content-Type: application/json" \
  -H "x-bf-vk: $CALLER_BIFROST_VK" \
  -H "x-bf-session-id: $A2A_CONTEXT_ID" \
  -H "x-bf-agent-correlation-id: $A2A_TASK_ID" \
  -d '{"model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Explain how to reuse one HTTP client across requests."}]}'
```

Do not substitute the JSON-RPC request ID or message ID, and keep IDs and credentials in per-task state so concurrent tasks are not cross-attributed. The same headers apply to tool calls through the [MCP gateway](https://www.getmaxim.ai/mcp-gateway).

Bifrost strips the caller's credential before forwarding to an agent by default; enabling [Forward Bifrost authentication](https://docs.getbifrost.ai/features/agent-gateway/authentication) lets the agent reuse it so its calls follow the caller's [budgets and access rules](https://www.getmaxim.ai/resources/governance). Agent access is a separate grant from model and tool access, as with [virtual keys for LLM and MCP traffic](https://www.getmaxim.ai/articles/ai-governance-with-virtual-keys-for-llm-and-mcp-traffic/).

## Troubleshooting Common A2A Errors Behind a Gateway

Most A2A failures behind a gateway fall into four groups: protocol traffic is not enabled, the agent's destination is blocked or unapproved, the caller lacks an agent grant, or the upstream transport failed. Each returns a distinct status or error message, so read the response body before changing configuration.

![Decision flow for a failed unary A2A call in Bifrost: unreachable endpoints try the next interface, ambiguous failures return without replay, auth errors return directly](https://articles-images-cdn.t3.tigrisfiles.io/diagrams/a2a-inspector/a2a-inspector-transport-failures.png)

*Figure 4: Bifrost retries only when the agent never received the work, so an ambiguous failure never creates a duplicate task.*

- **503 or gRPC `UNAVAILABLE`:** **External Client URL** in **Agents → Agent Settings** is empty; the message reads `agent gateway disabled: configure a2a_external_client_url`.
- **502 on the card:** the private network policy blocks the destination; add its host, IP, or CIDR to the Private Network Allowlist.
- **`31403`:** the caller has no grant for the agent or project; [agent access](https://docs.getbifrost.ai/features/agent-gateway/access-control) is set per virtual key, or through access profiles and projects in [Bifrost Enterprise](https://www.getmaxim.ai/enterprise).
- **gRPC cannot find the agent:** the dialed authority must start with the registration name, such as `library-research.a2a.example.com:443`.
- **Failed upstream call:** per Figure 4, dial failures and HTTP 404, 405, 410, or 426 try the next interface once; HTTP 5xx and broken responses return without replay.
- **Dropped stream:** disconnecting does not cancel the task; call `GetTask`, reconnect with `SubscribeToTask`, or send `CancelTask`.

An agent can pass its own access check and still have a tool call denied, which the [governance model behind agent grants](https://www.getmaxim.ai/ai-governance) and [MCP server authentication patterns](https://www.getmaxim.ai/articles/mcp-server-authentication-how-to-secure-agent-tool-access/) explain. Teams comparing deployments can use [criteria for choosing an agent gateway](https://www.getmaxim.ai/articles/how-to-choose-an-agent-gateway/).

## Frequently Asked Questions

### What does the A2A Inspector check?

The Inspector checks that an agent card has `name`, `description`, `version`, and a non-empty `skills` array, plus a v0.3 `url` or v1.0 `supportedInterfaces` entries with `url` and `protocolBinding`. During chat it checks responses for required fields such as task `id`, `status.state`, and message `parts`. It is basic validation; the A2A TCK covers full spec conformance.

### Does the A2A Inspector support A2A v1.0?

Yes. Its current backend depends on `a2a-sdk` 1.1.2 or later and accepts v0.3 and v1.0 formats, including v1.0 `supportedInterfaces` cards and task states such as `TASK_STATE_COMPLETED`. Check the README before upgrading, since setup steps change between releases.

### How do I test an A2A server without the A2A Inspector?

Fetch `/.well-known/agent-card.json` with curl, then post JSON-RPC bodies with `SendMessage`, `GetTask`, and `CancelTask` to the advertised interface URL with an `A2A-Version: 1.0` header. For scripted tests, drive the server with the official A2A SDK clients for Python or JavaScript. For conformance, run the A2A TCK with `./run_tck.py --sut-host` against the server.

### Why does my A2A request succeed when the task failed?

A2A separates the protocol response from the outcome of the work. An agent can return an HTTP 200 JSON-RPC result containing a task whose state is `failed` or `rejected`. In [Bifrost Agent Logs](https://docs.getbifrost.ai/features/agent-gateway/messages-and-tasks) that operation shows **Success**, so open the **Conversation** tab, read the task's status message, then inspect the correlated MCP and LLM logs.

### Why are LLM and MCP logs missing from an A2A session?

The agent is either calling providers or MCP servers directly, or it is not sending the correlation headers. Every model and tool call made for a task must go through Bifrost with `x-bf-session-id` set to the context ID and `x-bf-agent-correlation-id` set to the task ID. Also confirm the time window, allow log ingestion to settle, and check your log permissions.

### Does Bifrost retry failed A2A requests?

Bifrost retries a unary A2A operation on the next advertised interface only when the endpoint was not reached or cannot serve it, such as a dial failure, HTTP 404, or method not found. It never replays an ambiguous failure like HTTP 5xx, or any streaming operation, because the agent may already have created a task. Retrieve the known task before resubmitting work.

## Start Debugging A2A Agents with Bifrost

The A2A Inspector is the fastest way to confirm that one agent's card and responses follow the protocol, and curl plus the TCK make those checks repeatable. Production debugging needs caller identity, task state, stream events, and the model and tool calls behind each task. The open-source [Bifrost AI gateway](https://www.getmaxim.ai/) records all of them in Agent Logs, on the same gateway that governs model and tool traffic. To see how it fits alongside the A2A Inspector in your testing workflow, [book a demo](https://www.getmaxim.ai/book-a-demo) with the Bifrost team.

## More in the blog

[![AI Agent Registry: How Teams Discover and Govern Internal Agents](https://storage.ghost.io/c/84/03/8403f2f6-141c-411a-8f55-a32d4291533e/content/images/size/w720/2026/10/ai-agent-registry-how-teams-discover-and-govern-internal-age-bifrost-1920x1080.png) An AI agent registry is the system of record for the agents a company runs, from identity and skills to endpoints, auth and who may call them. This guide covers discovery models, a field checklist, how it differs from an MCP registry, and how Bifrost governs registered A2A agents.](https://www.getmaxim.ai/articles/ai-agent-registry/)

[![OpenAI API Pricing in 2026: Model Costs and Spend Controls](https://storage.ghost.io/c/84/03/8403f2f6-141c-411a-8f55-a32d4291533e/content/images/size/w720/2026/10/openai-api-pricing-in-2026-model-costs-and-spend-controls-bifrost-1920x1080@2x.png) OpenAI API pricing charges per million tokens, with separate rates for input, cached input, cache writes, and output that change by processing tier and context length. This guide lists current GPT-6 rates, prices a real workload, and shows how Bifrost enforces OpenAI budgets per team and key.](https://www.getmaxim.ai/articles/openai-api-pricing/)

```json
{
    "@context": "https://schema.org",
    "@type": "Article",
    "publisher": {
        "@type": "Organization",
        "name": "Maxim Articles",
        "url": "https://www.getmaxim.ai/articles/",
        "logo": {
            "@type": "ImageObject",
            "url": "https://storage.ghost.io/c/84/03/8403f2f6-141c-411a-8f55-a32d4291533e/content/images/size/w256h256/2025/08/thumbnail.png",
            "width": 60,
            "height": 60
        }
    },
    "author": {
        "@type": "Person",
        "name": "Kuldeep Paul",
        "image": {
            "@type": "ImageObject",
            "url": "https://storage.ghost.io/c/84/03/8403f2f6-141c-411a-8f55-a32d4291533e/content/images/2025/08/1727978381919.jpeg",
            "width": 800,
            "height": 800
        },
        "url": "https://www.getmaxim.ai/articles/author/kuldeep/",
        "sameAs": []
    },
    "headline": "A2A Inspector: How to Test and Debug A2A Agents",
    "url": "https://www.getmaxim.ai/articles/a2a-inspector/",
    "datePublished": "2026-10-29T19:14:43.000Z",
    "dateModified": "2026-10-29T19:14:43.000Z",
    "image": {
        "@type": "ImageObject",
        "url": "https://storage.ghost.io/c/84/03/8403f2f6-141c-411a-8f55-a32d4291533e/content/images/size/w1200/2026/10/a2a-inspector-how-to-test-and-debug-a2a-agents-bifrost-1920x1080.png",
        "width": 1200,
        "height": 675
    },
    "description": "The A2A Inspector is the A2A project's web tool for validating an agent card and reading raw JSON-RPC traffic. This guide shows how to run it, test A2A servers with curl and the TCK, and debug production tasks with correlated logs.\n",
    "mainEntityOfPage": "https://www.getmaxim.ai/articles/a2a-inspector/"
}
```
