agentscope-extensions-a2a implements version 1.0 of the A2A protocol, with the A2A Java SDK, and ships two sub-modules:
agentscope-extensions-a2a-client: wraps a remote A2A Agent as a localAgentyou cancall(...)directly.agentscope-extensions-a2a-server: exposes a localReActAgentas an A2A Server.
A2A-Version header, with a version error. The server does not support ListTasks yet, since it does not authenticate callers.
Client: call a remote A2A Agent
Add the dependency
Pass an AgentCard directly
Stream the reply
streamEvents streams the events of a call: the text and thinking the remote agent streams arrive as TextBlockDeltaEvent and ThinkingBlockDeltaEvent, then AgentResultEvent carries the same message call() returns. Tool calls and tool results are only in the result message.
Sessions
Each session, set by the user and session id of theRuntimeContext, keeps its own history in its AgentState, and its calls run one at a time; calls without a session id share the session named after the agent. interrupt(RuntimeContext) cancels the remote task of the call in progress in that session.
Middleware
A2aAgent runs MiddlewareBase at two points: onAgent wraps the whole call, and onReasoning wraps the exchange with the remote agent. The input messages of onReasoning are the messages sent to the remote agent, and its events are the text and thinking the remote agent streams. The other extension points do not apply to a remote agent.
Auto-discover via well-known
A2aAgent is a subclass of AgentBase, so it composes naturally with Pipeline, MsgHub, Subagent, etc.
Server: expose a ReActAgent as an A2A Server
Add the dependency
Build the server
AgentScopeA2aServer does not bind a port or expose endpoints itself; it only assembles components and the request-handling chain. You wire transport into Spring Boot, Quarkus, Vert.x, etc. as you prefer.
Request session identifiers
The server fillsAgentRequestOptions.sessionId for the AgentRunner from the SDK-resolved A2A contextId. Clients can use the standard protocol field without adding a custom metadata key. If the client omits contextId, the SDK generates one.
For compatibility, a non-null, non-blank message.metadata["sessionId"] overrides this mapping, even when it differs from contextId. This preserves existing session keys when the SDK generates a new context ID. Null, empty, or whitespace-only metadata values fall back to contextId. The protocol message’s contextId is not changed.
This mapping supplies the runner’s request options; it does not automatically enable session persistence. A custom runner can use the identifier when setting up its runtime context or state store.
Optional components
TaskStore/QueueManager: task and event queue stores; in-memory by default, swap for persistent versions in production.PushNotificationConfigStore/PushNotificationSender: outbound notifications. Push notifications are not supported yet: the agent card declares none, and push configs sent with a message are ignored.AgentRegistry: registerAgentCardto an external registry such as Nacos (see Nacos).
Spring Boot Starter
If you’re on Spring Boot, preferagentscope-spring-boot-starter-a2a-server — it auto-configures the server and controller. See Quickstart.
Configure the agent card under agentscope.a2a.server.card, with the field names of the A2A agent card. For example, to declare how clients authenticate:
authorization-code (with pkce-required), client-credentials and device-code flows. A2A 1.0 has no implicit or password flow; configuring one fails the startup.
When a map key contains special characters, such as the OAuth scope name read:user or a URL, write it quoted in brackets, for example "[read:user]": Read the user. Without brackets, characters such as : and / are dropped, and a security-schemes name containing . is read as a nested path, so that scheme is not applied.
The starter writes A2A JSON with the A2A SDK, so the application’s own Jackson settings (such as spring.jackson.property-naming-strategy) do not affect it.