Complexity: 🟨 Intermediate
This example demonstrates an end-to-end A2A workflow with NVIDIA NeMo Agent Toolkit functioning as both A2A client and server. The workflow performs mathematical calculations integrated with time queries and logical reasoning, combining remote calculator operations with local time services and conditional evaluation tools.
- Per-User A2A Client: Each user gets isolated A2A client connections with separate authentication and session state
- A2A Protocol Integration: Connects to a remote calculator workflow using A2A protocol
- Hybrid Tool Architecture: Combines remote A2A tools with local MCP and custom functions
- Multi-User Support: Demonstrates user isolation with different session cookies
flowchart LR
subgraph "Math Assistant A2A"
CC[Math Assistant A2A]
CC --> CTA[Calculator A2A Client]
CC --> CTM[Time MCP Client]
CC --> CLE[Logic Evaluator Tools]
end
CTA --> AP[A2A Protocol<br/>localhost:10000]
AP --> CS[Calculator A2A Server]
subgraph "Calculator A2A Server"
CS --> CA[calculator__add]
CS --> CSUB[calculator__subtract]
CS --> CDIV[calculator__divide]
CS --> CMUL[calculator__multiply]
CS --> CCMP[calculator__compare]
CS --> CDT[current_datetime]
end
style CC fill:#e1f5fe,color:#000
style CS fill:#f3e5f5,color:#000
style AP fill:#fff3e0,color:#000
Follow the instructions in the Install Guide to create the development environment and install NeMo Agent Toolkit.
From the root directory of the NeMo Agent Toolkit library, install this example:
uv pip install -e examples/A2A/math_assistant_a2aSet your NVIDIA API key as an environment variable:
export NVIDIA_API_KEY=<YOUR_API_KEY>First, start the calculator server that this client will connect to:
# Terminal 1: Start the A2A calculator server
nat a2a serve --config_file examples/getting_started/simple_calculator/configs/config.yml --port 10000Verify the server is running:
# Terminal 2: Check discover card
nat a2a client discover --url http://localhost:10000In a separate terminal, run the client workflow:
# Terminal 2: Run the calculator client
nat run --config_file examples/A2A/math_assistant_a2a/configs/config.yml \
--input "Is the product of 2 and 4 greater than the current hour of the day?"For more query examples, see data/sample_queries.json.
Run a specific query by its ID:
# Run query by ID (e.g., ID 4)
QUERY_ID=4
QUESTION=$(jq -r --arg id "$QUERY_ID" '.[] | select(.id == ($id | tonumber)) | .question' examples/A2A/math_assistant_a2a/data/sample_queries.json)
echo "Question: $QUESTION"
nat run --config_file examples/A2A/math_assistant_a2a/configs/config.yml --input "$QUESTION"This example uses a per-user workflow pattern because A2A clients are per-user function groups:
- Each user gets isolated A2A client connections
- Separate authentication credentials per user (important for OAuth2)
- Independent session state and task tracking
- No interference between users
The example uses per_user_react_agent, which is the per-user version of the ReAct agent:
- Each user gets their own isolated ReAct agent instance
- Gets per-user A2A client tools via the builder
- Provides the same interface as the shared
react_agentbut with per-user isolation - Built-in support for per-user function groups like A2A clients
When using nat serve, different users are identified by the nat-session cookie:
Before testing multi-user support, ensure the Calculator A2A server is running:
# Terminal 1: Start the A2A calculator server (if not already running)
nat a2a serve --config_file examples/getting_started/simple_calculator/configs/config.yml --port 10000Verify the server is running:
# Terminal 2: Check discover card
nat a2a client discover --url http://localhost:10000# Start the math assistant as a FastAPI server on terminal 2
nat serve --config_file examples/A2A/math_assistant_a2a/configs/config.yml# User "Alice" makes a request on terminal 3
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-H "Cookie: nat-session=Alice" \
-d '{"messages": [{"role": "user", "content": "Is the sum of 5 and 3 greater than the current hour of the day?"}]}' | jq
# User "Hatter" makes a request on terminal 3 (isolated from Alice)
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-H "Cookie: nat-session=Hatter" \
-d '{"messages": [{"role": "user", "content": "Is the product of 3 and 2 greater than the current hour of the day?"}]}' | jq-
Start the UI by following the instructions in the Launching the UI documentation.
-
Connect to the UI at
http://localhost:3000 -
Enable WebSocket mode in the UI by toggling the WebSocket button on the top right corner of the UI.
:::important Per-user workflows are not supported in HTTP mode. You must use WebSocket mode to test multi-user support. :::
- Send a message to the agent by typing in the chat input:
Is the sum of 5 and 3 greater than the current hour of the day?
- The workflow will be instantiated for the user on the first message and agent will respond with the result.
Yes, the sum of 5 and 3 is greater than the current hour of the day.
The workflow is configured to use the core per-user ReAct agent:
workflow:
_type: per_user_react_agent # Per-user ReAct agent
tool_names:
- calculator_a2a # Per-user A2A client
- mcp_time.get_current_time_mcp
- logic_evaluator.if_then_else
- logic_evaluator.evaluate_condition
llm_name: nim_llmThe configuration demonstrates three types of tool integration:
-
A2A Client Tools (
calculator_a2a) - Per-User:- Connects to remote calculator server
- Each user gets isolated connection and authentication
- Provides:
add,subtract,multiply,divide,comparefunctions
-
MCP Client Tools (
mcp_time) - Shared:- Local MCP server for time operations
- Provides:
get_current_time_mcpfunction
-
Logic Evaluator (
logic_evaluator) - Shared:- Simple local utility for logical operations
- Provides:
if_then_elseandevaluate_conditionfunctions
Server Not Running:
# Check if the calculator server is running
curl http://localhost:10000/.well-known/agent-card.json | jqPort Conflicts:
- Ensure port 10000 is available for the calculator server
- Check for other services using the port
- Modify the port in both the server startup and config.yml if needed
Timeouts:
- Increase
task_timeoutin config if calculations take longer - Check network connectivity to remote services
For production scenarios requiring authentication, see the OAuth2 Protected Math Assistant A2A example, which demonstrates:
- End-to-end OAuth2 authorization code flow
- Protected A2A server with JWT token validation
- Keycloak integration for testing secure A2A communication
- OAuth2 Protected Math Assistant A2A - OAuth2-protected A2A example
- Currency Agent A2A - External A2A service integration example