Documentation

Exposing agents through A2A protocol

Every AI agent created with kagent implements the A2A protocol and can be invoked by an A2A client.

Let's look at how this works in kagent!

Create an AI agent that supports A2A

We'll create a simple agent (k8s-a2a-agent) that can retrieve resources from a Kubernetes cluster. Note the definition of the agent follows the Agent CRD with the a2aConfig section added that describes the skills the agent can perform. You can follow the quick start to install kagent and then apply the following definition to your cluster:

apiVersion: kagent.dev/v1alpha1
kind: Agent
metadata:
name: k8s-a2a-agent
namespace: kagent
spec:
description: An example A2A agent that knows how to use Kubernetes tools.
modelConfig: openai-model-config
systemMessage: |-
You are an expert Kubernetes agent that uses tools to help users.
tools:
- builtin:
name: kagent.tools.k8s.GetResources
type: Builtin
a2aConfig:
skills:
- id: get-resources-skill
name: Get Resources
description: Get resources in the Kubernetes cluster
inputModes:
- text
outputModes:
- text
examples:
- "Get all resources in the Kubernetes cluster"
- "Get the pods in the default namespace"
- "Get the services in the istio-system namespace"
- "Get the deployments in the istio-system namespace"
- "Get the jobs in the istio-system namespace"
- "Get the cronjobs in the istio-system namespace"
- "Get the statefulsets in the istio-system namespace"

Testing the A2A endpoint

The A2A endpoint is exposed on the port 8083 of the kagent service. So let's do a port-forward to make the endpoint accessible:

kubectl port-forward svc/kagent 8083:8083 -n kagent

Note that you could also expose the A2A endpoint publicly by using a gateway.

To test that the agent is available and has an agent card, we can send a request to the .well-known/agent.json endpoint. Note the API endpoint follows the pattern /api/a2a/{namespace}/{agent-name}/.well-known/agent.json.

Let's send a request to the endpoint:

curl localhost:8083/api/a2a/kagent/k8s-a2a-agent/.well-known/agent.json

The output will be a JSON object that describes the agent as per the A2A protocol.

{
"name": "k8s-a2a-agent",
"description": "An example A2A agent that knows how to use Kubernetes tools.",
"url": "http://127.0.0.1:8083/api/a2a/kagent/k8s-a2a-agent",
"version": "1",
"capabilities": {
"streaming": false,
"pushNotifications": false,
"stateTransitionHistory": false
},
"defaultInputModes": [
"text"
],
"defaultOutputModes": [
"text"
],
"skills": [
{
"id": "get-resources-skill",
"name": "Get Resources",
"description": "Get resources in the Kubernetes cluster",
"examples": [
"Get all resources in the Kubernetes cluster",
"Get the pods in the default namespace",
"Get the services in the istio-system namespace",
"Get the deployments in the istio-system namespace",
"Get the jobs in the istio-system namespace",
"Get the cronjobs in the istio-system namespace",
"Get the statefulsets in the istio-system namespace"
],
"inputModes": [
"text"
],
"outputModes": [
"text"
]
}
]
}

Use the A2A host CLI to invoke the agent

We'll use the A2A host CLI to call the agent. This CLI part of the A2A repository. Start by cloning the repository:

git clone https://github.com/google/A2A.git

Then from the A2A/samples/python/hosts/cli directory, run the CLI and point it to the kagent endpoint:

cd A2A/samples/python/hosts/cli
uv run . --agent http://127.0.0.1:8083/api/a2a/kagent/k8s-a2a-agent

The CLI will connect to the kagent, display the agent card and prompt you for input:

======= Agent Card ========
{"name":"my-a2a-agent","description":"An example A2A agent that knows how to use Kubernetes tools.","url":"http://127.0.0.1:8083/api/a2a/kagent/my-a2a-agent","version":"1","capabilities":{"streaming":false,"pushNotifications":false,"stateTransitionHistory":false},"defaultInputModes":["text"],"defaultOutputModes":["text"],"skills":[{"id":"kagent-k8s-agent","name":"Get Resources","description":"Get resources in the Kubernetes cluster","examples":["Get all resources in the Kubernetes cluster","Get the pods in the default namespace","Get the services in the istio-system namespace","Get the deployments in the istio-system namespace","Get the jobs in the istio-system namespace","Get the cronjobs in the istio-system namespace","Get the statefulsets in the istio-system namespace"],"inputModes":["text"],"outputModes":["text"]}]}
========= starting a new task ========
What do you want to send to the agent? (:q or quit to exit):

Let's send the task "Get the pods in the kagent namespace" to the agent. You'll be also prompted to optionally attach a file to the request, but just hit enter to skip this step. The request will be sent to the agent and the response will be displayed in the CLI. Her'es the formated version of the response:

{
"jsonrpc": "2.0",
"id": "0df6761ed3394b43a2dee2bd6572bc94",
"result": {
"id": "89bae00376e44ed094a2174e163da9f6",
"sessionId": "d966626d06ab42b19bd3999e65333311",
"status": {
"state": "completed",
"message": {
"role": "agent",
"parts": [
{
"type": "text",
"text": "Processed result: There is one pod running in the \"kagent\" namespace:\n\n- Pod Name: kagent-748fb675c6-9ddsz\n- Status: Running\n- Ready Containers: 3 out of 3\n- Restarts: 0\n- Age: 31 minutes\n- Pod IP: 10.244.0.11\n- Node: kagent-control-plane\n\nLet me know if you need more details or want to perform any actions on this pod."
}
]
},
"timestamp": "2025-05-06T22:27:31+00:00"
},
"artifacts": [
{
"name": "Task Result",
"description": "The result of the task processing",
"parts": [
{
"type": "text",
"text": "There is one pod running in the \"kagent\" namespace:\n\n- Pod Name: kagent-748fb675c6-9ddsz\n- Status: Running\n- Ready Containers: 3 out of 3\n- Restarts: 0\n- Age: 31 minutes\n- Pod IP: 10.244.0.11\n- Node: kagent-control-plane\n\nLet me know if you need more details or want to perform any actions on this pod."
}
],
"index": 0,
"lastChunk": true
}
]
}
}

The result section contains the result of the task and the artifacts section contains the output of the task and it shows the pods running inside the kagent namespace.

The agent has processed the request and returned the result.