[ Web Proxy ]
URL:
Viewing: https://adk.dev/integrations/../../runtime/../../tutorials/../../a2a/quickstart-consuming-kotlin/ [Back]  [Original]

Kotlin - Agent Development Kit (ADK) Agent Development Kit (ADK)
Skip to content
ADK Go 2.0 GA is LIVE with graph workflows and collaborative agents! Get started.
logo [logo]
Kotlin
Python [Python] Python TypeScript [TypeScript] JS Go [Go] Go Java [Java] Java Kotlin [Kotlin] Kotlin
[Go]
  1. Home
  2. Components
  3. A2A Protocol
  4. A2A Quickstart (Consuming)

Quickstart: Consuming a remote agent via A2A

Supported in ADKKotlinExperimental

This quickstart covers the most common starting point for any developer: "There is a remote agent, how do I let my ADK agent use it via A2A?". This is crucial for building complex multi-agent systems where different agents need to collaborate and interact.

Overview

This sample demonstrates the Agent2Agent (A2A) architecture in the Agent Development Kit (ADK) for Kotlin, showing how a local agent delegates part of a task to an agent running elsewhere.

         
   Root Agent       Remote Prime Agent   
   (Local)          (localhost:8001)     
         
  • Root Agent (root_agent): The local orchestrator that delegates to sub-agents
  • Prime Agent (prime_agent): A remote A2A agent that checks whether a number is prime, running on a separate A2A server

Add the A2A dependency

A2A support ships in a separate artifact. The A2A SDK client is needed on the compile classpath as well, because A2AAgent's httpClient parameter defaults to JdkA2AHttpClient():

build.gradle.kts
implementation("com.google.adk:google-adk-kotlin-a2a:0.8.0")
implementation("org.a2aproject.sdk:a2a-java-sdk-client:1.0.0.Final")

Start a remote agent server

To consume a remote agent you first need one running. adk-kotlin cannot expose an agent over A2A yet, so the server has to come from elsewhere A2A is a wire protocol, so any language will do.

The a2a_basic sample in adk-python serves the prime agent this page delegates to. From an adk-python checkout:

adk api_server --a2a --port 8001 contributing/samples/a2a/a2a_basic/remote_a2a

The A2A protocol requires each agent to publish an agent card describing what it does, served at the well-known path under that agent's own prefix:

http://localhost:8001/a2a/check_prime_agent/.well-known/agent-card.json

Check the card is reachable before you continue:

curl http://localhost:8001/a2a/check_prime_agent/.well-known/agent-card.json

Which servers this client can talk to

The Kotlin client reads A2A 1.0 cards, so the card must carry a supportedInterfaces array whose entries each have a protocolBinding. Cards written for A2A 0.3 declare a top-level url and preferredTransport instead, and A2AAgent rejects them with AgentCardResolutionError: Failed to parse agent card.

The sample's checked-in agent.json is a 0.3-style card, but adk-python does not serve that file verbatim: it parses the card on startup, and under a2a-sdk 1.x that parse promotes url and preferredTransport into supportedInterfaces. adk-python requires a2a-sdk>=0.3.4,<2, so a fresh install resolves to 1.x and the card on the wire is A2A 1.0.

The a2a_server sample in adk-java is pinned to the 0.3.x A2A SDK and serves a 0.3 card, so it does not work as the server for this page.

Serving your own card instead

Any server publishing an A2A 1.0 card will do. A minimal card the client accepts, served from <your-base-url>/.well-known/agent-card.json:

.well-known/agent-card.json
{
  "name": "check_prime_agent",
  "description": "Checks whether numbers are prime.",
  "version": "1.0.0",
  "url": "http://localhost:9090",
  "preferredTransport": "JSONRPC",
  "capabilities": { "streaming": true },
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["application/json"],
  "skills": [],
  "supportedInterfaces": [
    { "protocolBinding": "JSONRPC", "url": "http://localhost:9090" }
  ]
}

Pass that base URL http://localhost:9090 as agentCardUrl below.

Connect to the remote agent

A2AAgent fetches that card and reads the remote agent's description from it, along with whether the remote supports streaming. The name you pass is this agent's identifier in your own agent tree, independent of the name the card advertises. It is a suspending function, so call it from a coroutine:

A2AConsumer.kt
// A2AAgent is a suspending factory: it fetches the remote agent's card from
// <url>/.well-known/agent-card.json and takes the description and streaming
// capability from it. The name is yours -- it identifies this agent in your
// tree, independent of the name the card advertises. The constructor of the
// returned agent is internal, so this factory is the only way to build one.
val primeAgent =
    A2AAgent(
        name = "prime_agent",
        agentCardUrl = "http://localhost:8001/a2a/check_prime_agent",
    )

If you already hold an AgentCard for example one you resolved yourself, or a static card checked into your configuration there is a non-suspending overload that takes it directly, A2AAgent(name = ..., agentCard = ...).

Use it as a sub-agent

The returned agent is a BaseAgent, so it goes into subAgents exactly like a local one. ADK handles the A2A protocol over the wire:

A2AConsumer.kt
// The remote agent is a BaseAgent, so it goes in subAgents like any local one.
// ADK handles the A2A wire protocol from here.
val rootAgent =
    LlmAgent(
        name = "root_agent",
        model = Gemini(name = "gemini-flash-latest"),
        instruction =
            Instruction(
                "You are a helpful assistant that can check prime numbers " +
                    "by delegating to prime_agent.",
            ),
        subAgents = listOf(primeAgent),
    )

Next Steps

Exposing a Kotlin agent over A2A is not yet supported; adk-kotlin currently provides the consuming side only. To expose an agent, see the quickstarts for the other languages:

Back to top

Web Proxy Viewer  |  New URL  |  Original Page