Skip to content

Latest commit

 

History

42 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A2A (Agent-to-Agent) Protocol CLI

A command-line client for the A2A (Agent-to-Agent) Protocol, built on the official a2a-go SDK.

Install

Install the latest released binary:

curl -fsSL https://raw.githubusercontent.com/kynoproj/a2acli/main/install.sh | bash

Or install via Go:

go install github.com/kynoproj/a2acli@latest

Or build from source:

make build

Usage

All commands take --url (-u) pointing at the A2A server's base URL. When --url is omitted, a2acli falls back to the A2A_SERVER environment variable. The AgentCard is fetched from <url>/.well-known/agent-card.json and the client connects using the transport selected by --protocol (default jsonrpc).

Supported --protocol values:

  • jsonrpc — JSON-RPC over HTTP (default).
  • rest — REST / HTTP+JSON.
  • grpc — gRPC.
a2acli [command]

Commands:
  card             Fetch and print the AgentCard
  send             Send a message to the agent and print the response
  task get         Fetch a task by ID
  task list        List tasks
  task cancel      Cancel a task by ID
  task subscribe   Re-subscribe to an existing task and stream events
  version          Print binary version and build metadata

Global flags:
  -u, --url string             Base URL of the A2A agent server (falls back to $A2A_SERVER)
  -p, --protocol string        Transport protocol: jsonrpc, rest, or grpc (default jsonrpc)
  -k, --insecure               Skip TLS certificate verification
      --plaintext              Disable TLS entirely (gRPC only)
      --tenant string          Optional agent-owner tenant ID applied to every request
      --timeout duration       HTTP timeout (default 30s)
  -H, --header stringArray     Extra header to send with every request, including the agent-card fetch and protocol calls (repeatable)
  -v, --verbose                Log request URL, request body, and response body to stderr
      --override-host string   Override the host[:port] of every URL in the resolved AgentCard (e.g. 127.0.0.1:9001)
      --endpoint string        Direct endpoint URL for the chosen --protocol; bypasses the AgentCard fetch
  -o, --output string          Output format: text or json (default text)
      --no-color               Disable ANSI colors in terminal output (also honors $NO_COLOR)

send flags:
      --accept strings         Accepted output MIME types (repeatable or comma-separated)
      --history-length int     Number of history messages to include in the response
      --return-immediately     Return as soon as the task is created instead of waiting for completion (incompatible with --stream)
      --task string            Task ID to continue an existing task
      --context string         Context ID to associate the message with an existing conversation
  -f, --file string            Read the message from a JSON file (an a2a.Message object) instead of positional text
      --json string            Raw JSON a2a.Message object to send instead of positional text
      --parts string           Raw JSON array of content parts to send as a user message
      --stream                 Stream events as they arrive instead of waiting for the final response
      --polling-interval duration   (--stream) Duration between GetTask requests when falling back to polling (default 5s)

task get flags:
      --history-length int     Maximum number of history messages to retrieve

task list flags:
      --context-id string      Filter by context ID
      --status string          Filter by task state (e.g. submitted, working, completed)
      --page-size int          Max tasks per page (1-100, server default if 0)
      --page-token string      Page token from a previous response
      --history-length int     History messages to include per task
      --include-artifacts      Include task artifacts in the response
      --since string           Only list tasks with status updates after this RFC 3339 timestamp

version flags:
      --short                  Print only the version string

The message source is chosen by precedence --json > --parts > --file > positional text; only one may be combined with positional text. --task/--context, when set, override any values carried in the chosen source.

--stream always attempts real streaming first. If the agent's AgentCard doesn't advertise streaming support (or the attempt fails for the same reason), it falls back to polling GetTask every --polling-interval and synthesizes streaming-like events from the task's state changes.

Output format

Every command that prints a result honors -o/--output:

  • text (default) — a compact, human-readable rendering of cards, tasks, messages, and streamed events.
  • json — the raw A2A protocol objects as indented JSON, for scripting.

Breaking change: the default is now text. Previous releases always emitted JSON. Add -o json (or --output json) to any command that feeds a JSON parser — for example a2acli task get -o json <id> | jq ..

Environment

Variable Effect
A2A_SERVER Default for --url when the flag is not provided. The flag, when set, always wins.
NO_COLOR Disables ANSI colors in terminal output, same as --no-color.
export A2A_SERVER=http://127.0.0.1:9001
a2acli card                              # uses $A2A_SERVER
a2acli card --url http://other:9001      # flag wins

Examples

Fetch an AgentCard:

a2acli card -u http://127.0.0.1:9001

Send a message:

a2acli send -u http://127.0.0.1:9001 "Hello, what can you do?"

Stream a message and watch task updates:

a2acli send --stream -u http://127.0.0.1:9001 "Summarize the latest news"

Inspect a task:

a2acli task get -u http://127.0.0.1:9001 <task-id>
a2acli task list -u http://127.0.0.1:9001 --status working
a2acli task list -u http://127.0.0.1:9001 --since 2026-08-01T00:00:00Z
a2acli task cancel -u http://127.0.0.1:9001 <task-id>
a2acli task subscribe -u http://127.0.0.1:9001 <task-id>

task list --status takes the short state names (submitted, working, completed, failed, canceled, rejected, input-required, auth-required); --since takes an RFC 3339 timestamp and lists only tasks with status updates after it.

Constrain the response with SendMessageConfig knobs:

a2acli send -u http://127.0.0.1:9001 \
  --accept application/json --history-length 5 --return-immediately \
  "Summarize this"

Continue an existing task or conversation. Take the task ID / context ID returned by a prior send (shown as Task:/Context: in text output, or taskId/contextId under -o json) and pass them to the next turn:

a2acli send -u http://127.0.0.1:9001 --task <task-id> "And translate it to French"
a2acli send -u http://127.0.0.1:9001 --context <context-id> "What did I just ask?"

Send a message from a file. The file holds a JSON a2a.Message object, which lets you send multi-part or non-text messages that positional text can't express (a missing messageId is generated automatically). --task/--context, when set, override any values in the file:

cat > message.json <<'EOF'
{ "role": "ROLE_USER", "parts": [{ "text": "Describe this diagram" }] }
EOF
a2acli send -u http://127.0.0.1:9001 -f message.json
a2acli send --stream -u http://127.0.0.1:9001 -f message.json --task <task-id>

Pass a message inline as raw JSON, either a full a2a.Message (--json) or just its content parts (--parts, wrapped in a user message for you):

a2acli send -u http://127.0.0.1:9001 \
  --json '{"role":"ROLE_USER","parts":[{"text":"Hello"}]}'
a2acli send -u http://127.0.0.1:9001 --parts '[{"text":"one"},{"text":"two"}]'

Address a tenant on multi-tenant agents:

a2acli send -u https://agent.example.com --tenant acme "Hello"

Trace traffic with -v (verbose output goes to stderr, so the command's stdout output stays pipeable):

a2acli -v send -u http://127.0.0.1:9001 "Hello"
# → AgentCard http://127.0.0.1:9001/.well-known/agent-card.json
# ← AgentCard http://127.0.0.1:9001
# → SendMessage http://127.0.0.1:9001
#   request:  {"messageId":"...","parts":[{"text":"Hello"}],"role":"ROLE_USER"}
# ← SendMessage http://127.0.0.1:9001
#   response: {...}

Pass authentication via -H:

a2acli card -u https://agent.example.com -H "Authorization: Bearer $TOKEN"

Talk to a gRPC server (plaintext, e.g. local dev):

a2acli send -u http://127.0.0.1:9001 -p grpc --plaintext "Hello"

Talk to a gRPC server over TLS, skipping certificate verification (e.g. self-signed cert):

a2acli send -u https://agent.example.com -p grpc -k "Hello"

Talk to a REST server:

a2acli send -u http://127.0.0.1:9001 -p rest "Hello"

Override the host[:port] returned in the AgentCard (e.g. when the agent advertises an internal address but you've port-forwarded it locally):

a2acli send -u http://agent.internal -p grpc --plaintext --override-host 127.0.0.1:9001 "Hello"

Bypass the AgentCard entirely with --endpoint. Use this when the server either does not expose /.well-known/agent-card.json, or its AgentCard is missing or misreports supportedInterfaces — a2acli will skip resolution and connect straight to the endpoint you supply with the chosen --protocol:

# JSON-RPC over HTTP
a2acli send -p jsonrpc --endpoint http://127.0.0.1:9001 "Hello"

# REST / HTTP+JSON
a2acli send -p rest --endpoint http://127.0.0.1:9001 "Hello"

# gRPC (plaintext)
a2acli send -p grpc --plaintext --endpoint 127.0.0.1:9001 "Hello"

--endpoint is incompatible with --override-host (set the endpoint URL directly) and with a2acli card (which has nothing to fetch).

Docker (in-cluster debugging)

Run interactively inside a cluster:

kubectl run a2acli-debug --rm -it --restart=Never \
  --image=quay.io/kynoproj/a2acli:v0.1.0 \
  --command -- bash
# then, inside the pod:
a2acli card -u http://my-agent.default.svc:9001

Or as an ephemeral debug container against an existing pod:

kubectl debug -it some-pod --image=quay.io/kynoproj/a2acli:v0.1.0 -- bash

License

Apache-2.0. See LICENSE.

About

Command-line client for the A2A (Agent-to-Agent) Protocol.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages