This release is a pre-release and may not be stable for production use.
Azure AI Agent Server A2A client library for Python
The azure-ai-agentserver-a2a package hosts a native A2A v1.0
a2a-sdk handler in an Azure AI Hosted
Agent container. It adds Foundry's hosting contract while leaving the agent
card, executor, request handler, and protocol semantics in the native A2A SDK.
It can also persist native Tasks using Core's existing Foundry state store.
The package is optional: customers can implement the documented Foundry container contract themselves. It is the recommended convenience layer because it reduces the required route, lifecycle, telemetry, and request-context glue to a small host declaration. The container contract itself remains mandatory.
Getting started
Install the package
python -m pip install "azure-ai-agentserver-a2a==1.0.0b1"
Build and install an alpha
Alpha packages use the same internal dev-feed workflow as the Activity host. They are not published to PyPI.
- Commit and push the A2A and core changes to a branch available to the
internal
python - agentserverpipeline. A fork-only branch must first be made available to that pipeline's source repository by a maintainer. - Select Run pipeline, choose that branch, and enable
Publish A2A and core alpha packages to the dev feed (
PublishA2AAlpha). - Keep Build and Integration selected. The opt-in applies only to
internal manual runs; it sets
SetDevVersion=trueandSkip.Release=true. Leave theBuildTargetingStringvariable unset so neither package is filtered out. Normal CI, scheduled builds, and PR validation are unchanged. - Check the Integration job's publish steps for both
azure-ai-agentserver-a2aandazure-ai-agentserver-core. Normal validation still covers the service packages, but this mode publishes only these two alpha packages, not the other Agent Server hosts.
The pipeline generates versions from its build number without changing the
checked-in versions. For example, build 20261030.1 produces
1.0.0a20261030001 (A2A) and 2.3.1a20261030001 (core).
Replace the example versions below with those from the successful run:
python -m pip install --pre `
--index-url "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" `
"azure-ai-agentserver-a2a==1.0.0a20261030001" `
"azure-ai-agentserver-core==2.3.1a20261030001"
Install both packages from the same run to include the core tracing enrichment changes. The dev-build tooling rewrites A2A's core dependency to an alpha range; pinning both versions also prevents accidentally testing a different core build. Regular preview installations require core 2.3.1b1 or later, which contains the Agent Card metadata-preservation fix.
Prerequisites
- Python 3.10 or later
a2a-sdk>=1.2.3,<2.0.0, which includes owner authorization on active-task cache hits used by subscription and cancellation- A native A2A v1.0
AgentCardand either anAgentExecutororRequestHandler
Requests select protocol version 1.0 with the A2A-Version header or the
a2a-version query parameter. Selector names are case-insensitive. Matching
selectors are accepted; conflicting selectors return an invalid-parameters
error. Omitted or empty selectors use the protocol's 0.3 default,
which this v1-only host rejects. Unsupported versions also return a
version-not-supported error. Trace protocol-version attributes describe an
accepted selection, not an unsupported requested version.
Key concepts
A2AAgentServerHost
A2AAgentServerHost is an AgentServerHost subclass that:
-
registers the native JSON-RPC handler at
POST /a2a; -
accepts
POST /invocations/a2aandGET /invocations/a2a/.well-known/agent-card.jsonas non-advertised aliases; -
registers the native public agent card at
GET /a2a/.well-known/agent-card.json; -
captures
x-agent-foundry-call-idandx-agent-user-idin the request-scoped Foundry context; -
provides
/readiness, port configuration, telemetry, and graceful shutdown throughazure-ai-agentserver-core. -
builds a native default request handler when given an executor, selecting Foundry-backed task storage when hosted and native in-memory storage locally.
Both POST routes execute the same native handler and semantic tracing wrapper. Both card routes use the same native card handler and
card_modifier; the alias does not rewrite the card or advertise an extra interface.
The Foundry passthrough advertises only the JSON-RPC binding. Push notifications, the authenticated extended card, HTTP+JSON/REST, and gRPC are not exposed in the initial release.
Distributed tracing
In Foundry-hosted environments, SendMessage also emits one invoke_agent
parent span using the deployed Foundry agent name,
version, and identity. This keeps hosted-agent trace discovery independent of
LLM calls or native SDK implementation spans. The child A2A operation span
retains Agent Card metadata, which can differ from the deployment name/version.
Both spans cover the complete response and record a returned Task ID for
correlation. Task lookup/list/cancel operations
do not emit an invoke_agent span because they do not execute the agent.
The host emits one SERVER span for each valid A2A JSON-RPC operation using
the Azure.AI.AgentServer.A2A instrumentation scope. Span names are the A2A
method names (SendMessage, GetTask, and so on).
Attributes include Agent Card metadata and protocol, message, task, and contextId
identifiers supplied in the request. The host reuses Core's trace propagation,
exception recording, span completion, and non-blocking flush helpers. HTTP errors
and buffered unary JSON-RPC errors mark the span as failed, including JSON-RPC
errors transported with HTTP 200.
When the request has no Task ID, tracing also records the first Task ID returned
by a single-task operation. This lets a Task-ID search find its original
creation span.
ListTasks is not tagged with an arbitrary result Task ID.
Response-only context IDs and task states are not recorded. Application metadata, prompts, and artifacts are not added to these spans.
These attributes follow the development-stage proposal in OpenTelemetry GenAI semantic conventions PR 195 and may evolve before that convention becomes stable.
The native a2a-sdk currently emits generic implementation-level spans in
addition to these semantic operation spans. To avoid duplicate server spans,
set this environment variable before importing a2a. The hosted invocation
span remains enabled:
OTEL_INSTRUMENTATION_A2A_SDK_ENABLED=false
Examples
Host a native A2A application
from azure.ai.agentserver.a2a import A2AAgentServerHost
host = A2AAgentServerHost(agent_card=card, request_handler=handler)
host.run()
To let the host construct the native handler and select default storage:
host = A2AAgentServerHost(agent_card=card, agent_executor=executor)
host.run()
The package intentionally does not replace the native A2A SDK. Continue using native A2A types for the agent card, executor, handler, task store, messages, artifacts, and tasks.
Task persistence
Executor-based construction follows the Activity host's storage-selection pattern:
| Configuration | Task storage |
|---|---|
Explicit task_store |
The supplied native store, unchanged |
| Foundry-hosted, no explicit store | FoundryTaskStore backed by Core's generic state store |
| Local, no explicit store | Native InMemoryTaskStore |
Existing request_handler |
The handler and its storage are preserved; no replacement |
Supply exactly one of agent_executor and request_handler. When supplying
an existing handler, configure its storage directly instead of passing
task_store to the host.
FoundryTaskStore implements the native save, get, list, and delete
operations. It stores complete protobuf Task snapshots, including history and
artifacts. Lightweight listing metadata is saved atomically with each snapshot;
native filtering and pagination select the page before full snapshots are read.
Listing still scans key metadata to preserve native ordering and total counts,
but full history/artifact reads are limited to the requested page when listing
metadata is present.
Listing metadata is also omitted when its encoded value exceeds Foundry's
256-character tag limit; the complete Task is still saved and uses the same
full-read listing path. Task-list timestamp cutoffs are inclusive. Equal
timestamps are ordered by descending Task ID, following the native SDK.
The response pageSize is the page limit used, not the returned Task count.
Task IDs that would exceed the 128-character storage item-key limit use an owner-scoped
hash key; their original IDs remain unchanged in the saved Task.
Foundry enforces its configured caller-isolation scope on hosted item
operations using validated brokered context. Available platform-user, native
user, and tenant scopes are layered into storage keys. A raw user-ID header is not required when the request
has a brokered call ID; the opaque call ID is forwarded unchanged through Core,
never parsed or used as a durable owner key. Hosted requests without usable
identity or brokered context are rejected.
Every operation verifies that the actual backing-store descriptor enables
user_isolation, including reads of an existing store. A non-isolated or
unverifiable store is rejected; creation arguments are not treated as proof of
an existing store's configuration. Storage authorization failures are surfaced
rather than selecting an anonymous/shared partition.
The hosted default namespace uses the stable agent GUID (or agent name when a GUID is unavailable), not the process or hosted-session ID. The host drains its default native handler before shutdown callbacks and closes its default store afterward. Explicit stores and existing handlers remain caller-owned.
To opt into persistence locally or choose a different named store:
from azure.ai.agentserver.a2a import A2AAgentServerHost, FoundryTaskStore
store = FoundryTaskStore("my-agent/a2a-tasks")
host = A2AAgentServerHost(agent_card=card, agent_executor=executor, task_store=store)
@host.shutdown_handler
async def close_storage():
await store.aclose()
Locally this uses Core's existing file-backed state store under
AGENTSERVER_STATE_ROOT (default ~/.agentserver). Hosted operation uses the
Foundry storage service and its identity/permission requirements. Storage is
created lazily on the first save; reads do not create an empty store.
Storage failures are surfaced rather than falling back to hosted in-memory
storage. Store retention defaults to Core's 30 days and can be configured with
item_ttl_seconds. Large outputs should use artifact references where needed
to respect the state service's item-size limits.
Persistence is not execution recovery: saving a Task marked WORKING does
not restart its executor. This feature does not create Core resilient tasks
or checkpoint workflows. Those remain separate application choices.
Hosted persistence also requires the A2A gateway to deliver the platform identity/brokered-context headers. A preview gateway may route native A2A requests successfully while omitting this handoff. In that case the SDK rejects storage access with a caller-context error; enabling the endpoint alone is not proof that managed persistence is available. Do not disable isolation or supply fabricated platform identity headers to work around a missing service handoff.
See the persistence example for a restart test.
Call a Foundry service from an A2A handler
The host binds the inbound platform identity to a ContextVar. Forward the
call ID, in addition to normal authorization, when custom code calls a service
under FOUNDRY_PROJECT_ENDPOINT:
from azure.ai.agentserver.core import get_request_context
headers = {
"Authorization": bearer,
**get_request_context().platform_headers(),
}
await client.post(foundry_service_url, headers=headers, json=payload)
platform_headers() forwards only x-agent-foundry-call-id. The inbound user
ID remains available as get_request_context().user_id for container-side
state partitioning and is not forwarded to Foundry services.
An inbound A2A contextId is recorded as gen_ai.conversation.id and added to
the active baggage context so child model, tool, and framework spans can use the
same conversation correlation.
Host A2A and Invocations together
Protocol hosts use cooperative inheritance, so both protocols can share one process and port:
pip install azure-ai-agentserver-a2a azure-ai-agentserver-invocations
from azure.ai.agentserver.a2a import A2AAgentServerHost
from azure.ai.agentserver.invocations import InvocationAgentServerHost
class MultiProtocolHost(A2AAgentServerHost, InvocationAgentServerHost):
pass
host = MultiProtocolHost(agent_card=card, request_handler=handler)
@host.invoke_handler
async def handle_invocation(request):
...
host.run()
See the sample setup and walkthroughs for standalone and multi-protocol examples, a native local client, and guidance on TaskStore durability and context reuse.
Scope
This package hosts incoming A2A traffic. It does not provide an outbound A2A client or intercept calls from the hosted agent to another agent.
The Foundry service rewrites the externally returned agent card. Container security schemes, signatures, provider/branding fields, internal URLs, and unsupported capabilities are not exposed to callers.
Troubleshooting
- Agent Card discovery returns 404: check the server port and use
/a2a/.well-known/agent-card.jsonfor a local container. The public Foundry Agent Card route is different; local sample clients do not authenticate to that public endpoint. - A request returns
VERSION_NOT_SUPPORTED: use the native sample client, or explicitly sendA2A-Version: 1.0with JSON-RPC requests. - Task lookup fails after restarting a sample: the examples use
InMemoryTaskStore. Its records do not survive a process restart. Reusing a context ID does not restore a lost Task or application history.
Core provides console logging for request failures and supports distributed tracing through its configured exporters. See distributed tracing for the A2A span behavior. Do not include authorization headers or sensitive message contents when sharing diagnostic logs.
Next steps
- Follow the sample setup and walkthroughs to discover an Agent Card, send a message, and retrieve a Task locally.
- Implement your agent with the native A2A Python SDK executor, request-handler, and TaskStore interfaces.
- Review the samples' state guidance before replacing in-memory storage, and use multi-protocol composition when another Agent Server protocol must share the same process.
Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
This project has adopted the Microsoft Open Source Code of Conduct.
Metadata
Release files for azure-ai-agentserver-a2a 1.0.0b1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| azure_ai_agentserver_a2a-1.0.0b1.tar.gz | 53.3 kB | Without provenance | Details for azure_ai_agentserver_a2a-1.0.0b1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| azure_ai_agentserver_a2a-1.0.0b1-py3-none-any.whl | Python 3 | none | any | Details for azure_ai_agentserver_a2a-1.0.0b1-py3-none-any.whl |
Total release size: 74.5 kB
Release files / azure_ai_agentserver_a2a-1.0.0b1.tar.gz
| Download URL | azure_ai_agentserver_a2a-1.0.0b1.tar.gz |
|---|---|
| Size | 53.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6a110fe6c8f5c7290cf7562c9aeb6966c0f517d349f7e484c1a529a320ad7cbe
|
|
BLAKE2b-256 checksum How to use checksums |
310f90f54ab7794f953591a5c5314a5cb0b281137897164f2b41b5c3dd6bd25e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
RestSharp/106.13.0.0
|
Release files / azure_ai_agentserver_a2a-1.0.0b1-py3-none-any.whl
| Download URL | azure_ai_agentserver_a2a-1.0.0b1-py3-none-any.whl |
|---|---|
| Size | 21.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e54dc54b88747023c42da6b3d3737b9568ef3b2823079ae594562392f292ebc2
|
|
BLAKE2b-256 checksum How to use checksums |
a96f315b94869499ec83e312d2f6f1345ef788bcb8808d3b40ef7dc939d72b29
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
RestSharp/106.13.0.0
|
Security for azure-ai-agentserver-a2a 1.0.0b1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.