Introduction
Agents rarely work alone. A supervisor hands work to a researcher; a coder calls a reviewer. The A2A protocol standardizes those exchanges, and the agent gateway carries them — so calls between agents get the same routing, security, and observability as the rest of your traffic.
This tutorial puts a sample A2A agent behind the gateway, fetches its agent card, and sends it a task.
Step 1 — Deploy a sample A2A agent
This Echo Agent returns whatever message it receives. The Service marks itself as A2A with appProtocol: kgateway.dev/a2a, which tells the gateway how to handle the backend:
kubectl apply -f- <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: a2a-agent
labels: { app: a2a-agent }
spec:
selector:
matchLabels: { app: a2a-agent }
template:
metadata:
labels: { app: a2a-agent }
spec:
containers:
- name: a2a-agent
image: gcr.io/solo-public/docs/test-a2a-agent:latest
ports:
- containerPort: 9090
---
apiVersion: v1
kind: Service
metadata:
name: a2a-agent
spec:
selector: { app: a2a-agent }
type: ClusterIP
ports:
- protocol: TCP
port: 9090
targetPort: 9090
appProtocol: kgateway.dev/a2a
EOF
Step 2 — Route to the agent
Because the Service is tagged as A2A, you route to it directly:
kubectl apply -f- <<'EOF'
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: a2a
spec:
parentRefs:
- name: agentgateway-proxy
namespace: agentgateway-system
rules:
- backendRefs:
- name: a2a-agent
port: 9090
EOF
Step 3 — Discover the agent
Port-forward the proxy:
kubectl port-forward deployment/agentgateway-proxy -n agentgateway-system 8080:80
A2A agents publish an agent card describing who they are and what they can do. Fetch it through the gateway:
curl -s http://localhost:8080/.well-known/agent.json
{
"name": "Echo Agent",
"description": "This agent echos the input given",
"version": "0.1.0",
"capabilities": { "streaming": true },
"defaultInputModes": ["text"],
"defaultOutputModes": ["text"]
}
Step 4 — Send the agent a task
Send an A2A tasks/send request, the same call one agent would make to another:
curl -s -X POST http://localhost:8080/ -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": "1",
"method": "tasks/send",
"params": {
"id": "1",
"message": { "role": "user", "parts": [ { "type": "text", "text": "hello gateway!" } ] }
}
}'
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"status": {
"state": "completed",
"message": { "role": "agent", "parts": [ { "type": "text", "text": "on_send_task received: hello gateway!" } ] }
}
}
}
The task ran on the agent and came back completed, routed through agentgateway. A calling agent reaches every agent through this one endpoint, so discovery and security live at the gateway and apply to all of them.
Clean up
kubectl delete httproute a2a
kubectl delete deployment,service a2a-agent
What’s next
You have tools, models, and agents all flowing through the gateway. The final tutorial secures that traffic: API-key and JWT authentication, CEL-based access rules, and OpenTelemetry traces.
Next in this series: Securing Agent Traffic with Policy and Observability.
Summary
- An A2A backend is an ordinary Service tagged with
appProtocol: kgateway.dev/a2a; anHTTPRouteattaches it to the Gateway. - Agents publish an agent card at
/.well-known/agent.json, served through the gateway. - A
tasks/sendcall runs work on the agent and returns its result, carried by agentgateway. - One endpoint fronts every agent, so discovery, auth, and observability attach once.
