Files
google__adk-docs/docs/a2a/quickstart-consuming-kotlin.md
Daria Wieliczko eb989519a7 Upgrade Kotlin docs to adk-kotlin 0.9.0 and move off AdkWebServer (#2191)
* Upgrade Kotlin docs to adk-kotlin 0.9.0 and move off AdkWebServer

adk-kotlin 0.9.0 split the web server into AdkApiServer, which serves the agent
runtime contract headlessly, and AdkDevServer, which adds the development UI.
AdkWebServer is deprecated in that release and goes away at 1.0, so WebMain.kt
as written here stops compiling the day 1.0 ships.

The quickstart snippet now builds an AdkDevServer from an AdkServerConfig. That
drops three imports: AdkServerConfig.inMemory() supplies the agent loader and
the in-memory session and artifact services the old constructor took one by one.

Two behaviour notes come with the split. AdkWebServer pinned host to 0.0.0.0;
the new classes bind loopback, which is a visible change for anyone reaching the
server from a container or a remote box, so the page now says so and names the
host parameter in prose. It prints no worked example on purpose: the only value
such a snippet could carry is either 127.0.0.1, which overrides the default with
itself, or 0.0.0.0, which is a copyable way to publish an unauthenticated server
on every interface, and AdkDevServer construction is already shown in full
earlier on the page. And AdkApiServer is the headless half of the same config,
so it gets a short section rather than a bare mention - the bundled Kotlin API
reference is still generated at 0.5.0 and documents none of these classes, so a
link there would not have helped. The "not meant for production" warning now
sits directly after the screenshot, where go.md, java.md and python.md put it.

The dependency blocks readers copy from still pinned 0.8.0, and so did the
examples project. Verified on Maven Central that 0.9.0 is published for every
artifact named across these pages: -core, -processor, -webserver, -litertlm,
-a2a and -integrations. Checked the 0.9.0 POMs before bumping: Ktor still
resolves to 2.3.13 and a2a-java-sdk-client to 1.0.0.Final, so the explicit pins
stay correct and the two comments citing them only needed their version
reference moved. The `Kotlin v0.x` support badges are deliberately left alone:
they record the release a feature landed in, not the current version.

Verified by compiling: every snippet added here was compiled verbatim against
the published 0.9.0 artifacts on JDK 17, and the whole examples project still
builds at 0.9.0. As a negative control, the old snippet still compiles at 0.9.0
but emits the deprecation warning, which is what makes this a 1.0 break rather
than a present-day one. Note the Kotlin snippet check only builds .kt files
changed in the PR, so it will not cover a markdown-only change like this.

* Apply suggestion from @joefernandez

* Apply suggestion from @joefernandez

* Removing information bloat from the Get Started

see comments for where to locate this information

---------

Co-authored-by: Joe Fernandez <931947+joefernandez@users.noreply.github.com>
2026-09-02 11:21:12 -07:00

5.4 KiB

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():

implementation("com.google.adk:google-adk-kotlin-a2a:0.9.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

!!! note "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.

??? note "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`:

```json title=".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:

--8<-- "examples/kotlin/snippets/a2a/A2AConsumer.kt:remote_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:

--8<-- "examples/kotlin/snippets/a2a/A2AConsumer.kt:root_agent"

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: