a2a-rs-server. Aura also serves a v0.3 JSON-RPC binding at the root for pre-1.0 clients (see A2A v0.3 Root Binding).
Enabling A2A
A2A is disabled by default. Enable it with the--enable-a2a flag or AURA_ENABLE_A2A environment variable:
/.well-known/agent-card.json, /a2a/v1/*, and POST /) are not mounted and return 404.
Endpoints
message:send — immediate return
AuraRequestHandler forces return_immediately = true on every message:send request. The HTTP response returns as soon as the task is queued in Working state, without waiting for the agent to finish. Poll GET /a2a/v1/tasks/{id} or subscribe via message:stream / tasks/{id}:subscribe to track completion.
A2A v0.3 Root Binding
POST / (the bare service root) serves an A2A v0.3 JSON-RPC 2.0 binding. It runs alongside the existing v1.0 JSON-RPC at /a2a/v1/rpc and the v1.0 REST mounts under /a2a/v1/*.
A2A v0.x clients, such as kagent’s bring-your-own (BYO) agent feature, read the pre-1.0 top-level url field of the agent card (see v0.x Client Compatibility). Finding none, they fall back to POSTing JSON-RPC at the bare service root. Before this binding, Aura advertised its endpoints only through supportedInterfaces[] and mounted JSON-RPC only at /a2a/v1/rpc. Those clients hit the root, got a 404, and appeared to hang silently because they never received a usable response.
The root binding is active automatically whenever A2A is enabled with the existing --enable-a2a flag or AURA_ENABLE_A2A environment variable. There is no new flag or environment variable. See Enabling A2A.
The root binding accepts the v0.3 slash-style method names: message/send, message/stream, tasks/get, tasks/cancel, and tasks/resubscribe.
The root binding shares the same request handler, agent executor, and in-memory task store as the v1.0 bindings, so behavior matches. A root message/send returns immediately with a task in the Working state, the same as the v1.0 message:send (see message:send — immediate return). The resulting task is stored in the same task store, so you can poll it with a v0.3 tasks/get call to POST / or with the REST endpoint GET /a2a/v1/tasks/{id}. The x-aura-model header works the same way at the root as on the other endpoints: it selects the agent configuration when multiple configs are loaded, and is forwarded to the agent’s MCP connections (see Model selection).
The root binding accepts only the v0.3 method names above. Any other method returns -32601 Method not found. This includes the v1.0 method names (SendMessage, GetTask, CancelTask), which belong to /a2a/v1/rpc, and the push-notification and extended-card methods, which are unsupported and match the card’s pushNotifications: false capability.
A malformed JSON body returns a JSON-RPC parse error -32700 rather than a bare HTTP 422. All protocol failures are returned inside the JSON-RPC envelope at HTTP 200, as the A2A spec requires.
These slash-style method names belong only to the root binding. They are distinct from the v1.0 method names (
SendMessage, GetTask, CancelTask) used at /a2a/v1/rpc.The root binding is served on the same host and port as the rest of the server; it opens no new port. Enabling A2A does not add any flag or environment variable to the Aura process. However, because
POST / was previously always a 404, a reverse proxy, load balancer, or Kubernetes Ingress in front of Aura may need a routing rule to forward bare POST / to the Aura backend. Watch for collisions with health-check paths or other services that share the same origin. Only POST / is mounted at the root; GET / continues to return 404, so health-check probes on GET / are unaffected. Disabling A2A unmounts this route along with the other A2A surfaces, and POST / then returns 404 again.Agent card URL (AURA_SERVER_URL)
The agent card’s supportedInterfaces[].url fields must be absolute (per the A2A spec). A2A clients read these URLs from the card and pass them straight to their HTTP layer, which rejects relative paths — so a client that fetches the card successfully will still fail on message:send if the advertised URLs are relative.
Aura builds the interface URLs from a single canonical origin, configured via:
When
AURA_SERVER_URL is unset, the origin is derived from the bind host/port, with a wildcard bind (0.0.0.0 / ::) mapped to 127.0.0.1. That default is fine for local development but wrong whenever the server is reached at a different address than it binds — behind a reverse proxy, load balancer, Kubernetes Service/Ingress, or when the container port is remapped. In those cases set AURA_SERVER_URL to the externally-reachable origin clients actually use (scheme + host + optional port, no path):
AURA_SERVER_URL is trimmed before the paths are appended.
v0.x Client Compatibility
The top-levelurl and preferredTransport fields let pre-1.0 A2A clients discover the endpoint. The third supportedInterfaces entry advertises the same root binding to v1.0-aware clients. Both use the same AURA_SERVER_URL origin already documented in the AURA_SERVER_URL table above, so there is no new configuration. See A2A v0.3 Root Binding for how the root endpoint handles these clients.
Model selection (x-aura-model)
When the server is started with multiple agent configs (e.g. --config agent-a.toml --config agent-b.toml), A2A clients can target a specific agent by sending the x-aura-model request header. This mirrors the model field in the OpenAI-compatible /v1/chat/completions endpoint.
The error message when no config matches:
- Header provided:
"no agent configuration found for model '<name>'"(A2Ainvalid_params) - No header and no default:
"no agent configuration available"(A2Ainvalid_params)
x-aura-model is not part of the A2A spec — it is an Aura extension. Like all request headers, it is also forwarded to the agent’s MCP connections via the headers_from_request mechanism.
Multi-turn conversations
UsecontextId to group message:send requests into a single conversation. It is optional. To start a new conversation, omit contextId. The server generates one and returns it on the task object as task.contextId, which you read back from the first message:send response. The same value is present on the GET /a2a/v1/tasks/{id} response. The first message:send call is shown under Testing with curl below.
To continue the conversation, send another message:send with message.contextId set to that value, placed inside the message object alongside the other message fields. You group requests into one conversation only by contextId. When you send a follow-up on the same contextId, the agent includes its own prior answers as context, along with prior user prompts, so it can reference what it said earlier.
contextId across instances, subject to a configured TTL. To configure the durable or multi-pod backend, see Session Store.
There is no wire-contract change.
task.history still contains only the user prompt. The agent’s answer is still delivered as artifacts (the “Response” stream and “Final Info”). This section covers request-side contextId linkage and improved recall, not a new response field.Testing with curl
Assumes the server is running onlocalhost:8080.
Agent card
Health check
REST — send a message
Working state. Grab the id field for follow-up calls.
REST — get a task by ID
REST — list tasks
REST — cancel a task
JSON-RPC — send a message
JSON-RPC — get a task
JSON-RPC — cancel a task
JSON-RPC (v0.3) — send a message
This is the endpoint that pre-1.0 clients like kagent use automatically. The v0.3 binding uses the v0.3 wire format, which differs from the v1.0 examples above:role is lowercase (user), each part carries a kind discriminator ({ "kind": "text", ... }), and responses come back with v0.3 spellings (for example, kebab-case task states).
JSON-RPC (v0.3) — get a task
This polls a task created by the v0.3message/send call above. The same task is also reachable through the REST endpoint GET /a2a/v1/tasks/{id}.
Notes
A2A-Versionis optional — when present on/a2a/v1/rpcrequests, the version is validated. An unsupported value returns-32009 Version not supported. REST endpoints do not enforce the header.messageIdandroleare required on theMessageobject — malformed bodies return-32602 Invalid params.- Text-only parts — the executor only accepts
textparts;fileanddataparts return an error. - By default, tasks are stored in the
a2a-rs-serverin-memoryTaskStorefor the lifetime of the process. A Redis or Valkey Session Store persists tasks for durable or multi-pod deployments. UseGET /a2a/v1/tasks/{id}orGetTaskto poll aftermessage:sendreturns. - Request headers passed to
/a2a/v1/message:sendare forwarded to the agent’s MCP connections (sameheaders_from_requestmechanism as the OpenAI-compatible endpoint). This includesx-aura-model. x-aura-modelis an Aura extension, not part of the A2A spec. It selects the agent configuration when multiple configs are loaded — see Model selection.

