6. Interacting with the Server¶
With the Helloworld A2A server running, let's send some requests to it. The SDK includes a client (A2AClient) that simplifies these interactions.
The Helloworld Test Client¶
The test_client.py script demonstrates how to:
- Fetch the Agent Card from the server.
 - Create an 
A2AClientinstance. - Send both non-streaming (
message/send) and streaming (message/stream) requests. 
Open a new terminal window, activate your virtual environment, and navigate to the a2a-samples directory.
Activate virtual environment (Be sure to do this in the same directory where you created the virtual environment):
Run the test client:
Understanding the Client Code¶
Let's look at key parts of test_client.py:
- 
Fetching the Agent Card & Initializing the Client:
base_url = 'http://localhost:9999' async with httpx.AsyncClient() as httpx_client: # Initialize A2ACardResolver resolver = A2ACardResolver( httpx_client=httpx_client, base_url=base_url, # agent_card_path uses default, extended_agent_card_path also uses default )The
A2ACardResolverclass is a convenience. It first fetches theAgentCardfrom the server's/.well-known/agent.jsonendpoint (based on the provided base URL) and then initializes the client with it. - 
Sending a Non-Streaming Message (
send_message):client = A2AClient( httpx_client=httpx_client, agent_card=final_agent_card_to_use ) logger.info('A2AClient initialized.') send_message_payload: dict[str, Any] = { 'message': { 'role': 'user', 'parts': [ {'kind': 'text', 'text': 'how much is 10 USD in INR?'} ], 'messageId': uuid4().hex, }, } request = SendMessageRequest( id=str(uuid4()), params=MessageSendParams(**send_message_payload) ) response = await client.send_message(request) print(response.model_dump(mode='json', exclude_none=True))- The 
send_message_payloadconstructs the data forMessageSendParams. - This is wrapped in a 
SendMessageRequest. - It includes a 
messageobject with theroleset to "user" and the content inparts. - The Helloworld agent's 
executemethod will enqueue a single "Hello World" message. TheDefaultRequestHandlerwill retrieve this and send it as the response. - The 
responsewill be aSendMessageResponseobject, which contains either aSendMessageSuccessResponse(with the agent'sMessageas the result) or aJSONRPCErrorResponse. 
 - The 
 - 
Handling Task IDs (Illustrative Note for Helloworld):
The Helloworld client (
test_client.py) doesn't attemptget_taskorcancel_taskdirectly because the simple Helloworld agent'sexecutemethod, when called viamessage/send, results in theDefaultRequestHandlerreturning a directMessageresponse rather than aTaskobject. More complex agents that explicitly manage tasks (like the LangGraph example) would return aTaskobject frommessage/send, and itsidcould then be used forget_taskorcancel_task. - 
Sending a Streaming Message (
send_message_streaming):streaming_request = SendStreamingMessageRequest( id=str(uuid4()), params=MessageSendParams(**send_message_payload) ) stream_response = client.send_message_streaming(streaming_request) async for chunk in stream_response: print(chunk.model_dump(mode='json', exclude_none=True))- This method calls the agent's 
message/streamendpoint. TheDefaultRequestHandlerwill invoke theHelloWorldAgentExecutor.executemethod. - The 
executemethod enqueues one "Hello World" message, and then the event queue is closed. - The client will receive this single message as one 
SendStreamingMessageResponseevent, and then the stream will terminate. - The 
stream_responseis anAsyncGenerator. 
 - This method calls the agent's 
 
Expected Output¶
When you run test_client.py, you'll see JSON outputs for:
- The non-streaming response (a single "Hello World" message).
 - The streaming response (a single "Hello World" message as one chunk, after which the stream ends).
 
The id fields in the output will vary with each run.
// Non-streaming response
{"jsonrpc":"2.0","id":"xxxxxxxx","result":{"type":"message","role":"agent","parts":[{"type":"text","text":"Hello World"}],"messageId":"yyyyyyyy"}}
// Streaming response (one chunk)
{"jsonrpc":"2.0","id":"zzzzzzzz","result":{"type":"message","role":"agent","parts":[{"type":"text","text":"Hello World"}],"messageId":"wwwwwwww","final":true}}
(Actual IDs like xxxxxxxx, yyyyyyyy, zzzzzzzz, wwwwwwww will be different UUIDs/request IDs)
This confirms your server is correctly handling basic A2A interactions with the updated SDK structure!
Now you can shut down the server by typing Ctrl+C in the terminal window where __main__.py is running.