/a2a/{assistant_id}.
Protocol version
Agent Server speaks the A2A v1.0 JSON-RPC binding and also accepts the v0.3 method names, so existing v0.3 clients keep working. The agent card declares one interface:Supported methods
Exactly four v0.3 names are accepted:
message/send, message/stream, tasks/get and
tasks/cancel. Anything else — including agent/getAuthenticatedExtendedCard and
tasks/resubscribe — returns -32601 Method not found.
Only the JSON-RPC binding is available. gRPC and HTTP+JSON are not implemented.
Return before the run finishes
By default,SendMessage holds the request open until the run finishes. To get the task back as
soon as the run is created, set returnImmediately to true in configuration:
TASK_STATE_SUBMITTED or TASK_STATE_WORKING, with no artifacts. Poll
GetTask with the returned id until the state is terminal or TASK_STATE_INPUT_REQUIRED. A
completed task carries the agent’s reply in artifacts, the same parts a blocking SendMessage
returns.
returnImmediately: The v1.0 flag. Takes precedence when both flags are sent.blocking: The v0.3 flag."blocking": falsebehaves like"returnImmediately": true.
null, and null counts as unset. Any other value returns -32602
before a run is created.
Task history in responses
A context holds many tasks. By defaultSendMessage, GetTask and ListTasks return the history
of the whole context, not just the task you asked about. The second task in a context replays
the first task’s messages, so a client that renders every history entry shows earlier turns again —
including earlier tool results and A2UI payloads.
Set historyScope to task to get back only the messages that belong to the task you asked about.
The default stays context, so existing integrations are unaffected.
Where the option goes depends on the method. SendMessage reads it from configuration:
GetTask and ListTasks read it directly from params:
capabilities.extensions, so you can detect support rather
than assume it:
- Streaming ignores both history options.
SendStreamingMessagereads neitherhistoryScopenorhistoryLength, and returns no error if you send them — so do not rely on either over SSE. historyLengthcaps at 10. A larger value returns-32602withhistoryLength cannot exceed 10.- Scope is applied before
historyLength, so you get the last N messages of that task.
-32602 with historyScope must be 'context' or 'task'. A mis-cased
key such as historyscope is not an error — it is ignored, and you silently get full-context
history, so check the spelling if filtering appears not to work.
Interrupts
When the graph callsinterrupt(), the task moves to TASK_STATE_INPUT_REQUIRED and carries an
artifact named Interrupt. The artifact holds one DataPart per pending interrupt:
response_schema appears only when the graph passes one to interrupt().
To resume, send a message with the interrupted task’s taskId and contextId. Put the resume
value in a DataPart under a resume key, such as {"data": {"resume": true}}, or send a text
part, which is used as the resume value as is. Send at most one resume DataPart. More than one
returns -32602.
If the task is not waiting on input, a resume DataPart returns -32602, but a text part is
treated as an ordinary message rather than a resume value.
Agent card discovery
Each assistant automatically exposes an A2A Agent Card that describes its capabilities and provides the information needed for other agents to connect. You can retrieve the agent card for any assistant using:Optional capabilities
These are configured per assistant throughmetadata.a2a on the Assistants API. langgraph.json
cannot set assistant metadata, so patch the assistant after deploy.
Declare input and output modes
defaultInputModes/defaultOutputModes and the generated skill’s
modes. They are advertisement only — an undeclared mode is still accepted. Replacement is per
field, so send both if you want both overridden, and note that an empty list is rejected.
File parts
FilePart works in both directions. Inbound file, image, audio and video parts become LangChain
content blocks. Outbound content blocks map back to FilePart, in task history and in the final
streamed artifact. MIME types, URIs and filenames pass through unchanged; inline data is
re-encoded as standard base64.
A2UI v0.9
A2UI is off by default. Turn it on for every assistant in a deployment with an environment variable:a2ui value wins over A2A_A2UI_ENABLED, so you can also turn A2UI off for one
assistant in an enabled deployment. Each run records the setting it started with, so GetTask and
ListTasks render an existing task the same way after you change it.
When A2UI is enabled, the card advertises the extension and appends the canonical MIME type to both mode lists:
A2A-Extensions header.
The legacy X-A2A-Extensions header also works:
params.message.metadata
(a2uiClientCapabilities and a2uiClientDataModel), the location the A2UI v0.9 schema defines.
Capabilities use the tagged shape, such as {"v0.9": {"supportedCatalogIds": [...]}}. A flat
capabilities object is rejected.
An A2UI DataPart holds either one A2UI message object or an array of messages, with
metadata.mimeType set to an A2UI MIME type:
application/json+a2ui: The canonical type. The card advertises it, and responses use it by default.application/a2ui+json: Accepted on input. When a request uses it, responses for that task echo it back, including laterGetTaskreads.
-32602. An invalid payload in the agent’s reply fails the request with -32603.
A2UI parts are preserved in SendMessage, GetTask, and the final SendStreamingMessage artifact.
The server publishes A2UI output only when the assistant has A2UI enabled and the client sent the
extension header. Otherwise, it drops A2UI blocks from the agent’s output and returns the rest of
the reply, rather than failing the request.
Client input is stricter. An A2UI DataPart sent to an assistant without A2UI enabled, or sent
without the extension header, returns -32602.
To publish a tool’s result as A2UI, list the tool names on the deployment. The tool’s result must
be A2UI JSON:
DataParts only when A2UI is active for the request. Error
results and results that fail validation are dropped.
Filter tool results
By default every correlated tool result is published as aDataPart. To publish only some, set an
allowlist of tool names on the deployment:
Requirements
messages key to accept A2A text and file parts. An assistant
whose input schema has no messages field is rejected with an explanatory error.
Creating an A2A-compatible agent
This example creates an A2A-compatible agent that processes incoming messages using OpenAI’s API and maintains conversational state. The agent defines a message-based state structure and handles the A2A protocol’s message format. To be compatible with the A2A “text” parts, the agent must have amessages key in state.
The A2A protocol uses two identifiers to maintain conversational continuity:
contextId: Groups messages into a conversation thread (like a session ID)taskId: Identifies each individual request within that conversation
contextId from the prior response and omit taskId, so each turn opens a new task inside the same conversation. Send a taskId only to add to a task that is still running, such as one waiting on input.
LangSmith Tracing: The Langsmith Deployment A2A endpoint automatically converts the A2A contextId to thread_id for LangSmith tracing, grouping all messages in the conversation under a single thread.
For example:
Agent-to-agent communication
Once your agents are running locally vialanggraph dev or deployed to production, you can facilitate communication between them using the A2A protocol.
This example demonstrates how two agents can communicate by sending JSON-RPC messages to each other’s A2A endpoints. The script simulates a multi-turn conversation where each agent processes the other’s response and continues the dialogue.
- Two LangGraph agents communicating - Example of two LangGraph agents using the A2A protocol
- Google ADK agent with LangChain agent - Example of a Google ADK agent interacting with a LangChain agent using the A2A protocol
Distributed tracing
When multiple agents communicate over A2A, LangSmith can group all their traces into a single thread, which gives you a unified view of the entire multi-agent conversation.How contextId maps to thread_id
The Agent Server A2A endpoint automatically converts the A2AcontextId to thread_id for LangSmith tracing. This means every message in a conversation, across all participating agents, is grouped under the same thread in LangSmith without any extra configuration on your part.
The flow works as follows:
- On the first message, the client omits
contextId. The server generates one and returns it in the response. - The client passes the
contextIdin all subsequent messages to maintain conversation continuity. - Agent Server maps the
contextIdtothread_idin LangSmith metadata, so all turns appear in the same thread.
Tracing across multiple agents
When agents from different frameworks communicate over A2A,contextId is what unifies their traces. Reuse the contextId returned by the first agent on every later request, to that agent and to the others.
The following code snippet demonstrates the key concepts. For a complete runnable implementation with two agents, refer to the Google ADK + LangChain example.
contextId inside the message object on follow-up turns so the server can associate them with the ongoing conversation. Omit it on the first message, because the server generates a contextId and returns it in the response. Do not resend taskId from a finished turn.
2. Send it: The contextId travels inside params.message. Agent Server uses it as the LangGraph thread_id, so there is no separate tracing field to set.
3. Share the context across agents: Let the first agent mint the contextId, then pass that same value to every agent for the rest of the conversation. That is what groups their traces into one thread.
Receive thread_id in non-LangGraph agents
The previous section covers the client side — propagatingcontextId when sending messages. If one of your agents is not built on LangGraph, it also needs to read that contextId on the receiving end and attach it as the thread identifier, so its traces land in the same LangSmith thread. Use langsmith.integrations.otel.configure() to set up automatic tracing, and read params.message.contextId from the incoming A2A request.
app after this middleware.
Set
LANGSMITH_API_KEY and optionally LANGSMITH_PROJECT in your environment to enable tracing. All agents in the conversation should use the same project so their traces are visible together.View traces in LangSmith
After running a multi-agent conversation, open the LangSmith UI and navigate to Threads. All turns from all participating agents will appear under a single thread, identified by the sharedthread_id.
Test your integration
Against your own deployment
Fetch the card, then send a message:result.task.id and result.task.contextId. Reuse the contextId on the
next message to continue the conversation.
For streaming, send Accept: text/event-stream and use SendStreamingMessage. The first event is
the Task; status and artifact updates follow.
Against the official conformance suite
A2A publishes a Technology Compatibility Kit at a2aproject/a2a-tck. It grades an implementation by RFC 2119 level and works against any A2A endpoint, including yours.The TCK drives some scenarios through
messageId prefixes such as tck-input-required, described
in its docs/SUT_REQUIREMENTS.md. A graph that does not implement those prefixes will report those
requirements as skipped rather than failed.What Agent Server currently fails
Agent Server runs the TCK on every CI build as a required check, gated against a checked-in list of known failures. CI fails if a new failure appears, and also if a listed requirement starts passing, so the list cannot drift from what the server actually does. Read this before you build against a capability:Disable A2A
To disable the A2A endpoint, setdisable_a2a to true in your langgraph.json configuration file:
Connect these docs to your agent of choice via MCP for real-time answers.

