Skip to content

Quickstart: Exposing a remote agent via A2A

Supported in ADKGoExperimental

This quickstart covers the most common starting point for any developer: "I have an agent. How do I expose it so that other agents can use my agent via A2A?". This is crucial for building complex multi-agent systems where different agents need to collaborate and interact.

Overview

This sample demonstrates how you can easily expose an ADK agent so that it can be then consumed by another agent using the A2A Protocol.

In Go, you expose an agent by using the A2A launcher, which dynamically generates an agent card for you.

┌─────────────────┐                             ┌───────────────────────────────┐
│   Root Agent    │       A2A Protocol          │ A2A-Exposed Check Prime Agent │
│                 │────────────────────────────▶│      (localhost: 8001)        │
└─────────────────┘                             └───────────────────────────────┘

The sample consists of :

  • Remote Prime Agent (remote_a2a/check_prime_agent/main.go): This is the agent that you want to expose so that other agents can use it via A2A. It is an agent that handles prime number checking. It becomes exposed using the A2A launcher.
  • Root Agent (main.go): A simple agent that is just calling the remote prime agent.

Exposing the Remote Agent with the A2A Launcher

You can take an existing agent built using the Go ADK and make it A2A-compatible by using the A2A launcher.

1. Getting the Sample Code

First, make sure you have Go installed and your environment is set up.

You can clone and navigate to the a2a_basic sample here:

cd examples/go/a2a_basic

As you'll see, the folder structure is as follows:

a2a_basic/
├── remote_a2a/
│   └── check_prime_agent/
│       └── main.go    # Remote Prime Agent
├── go.mod
├── go.sum
└── main.go            # Root agent

Root Agent (a2a_basic/main.go)

  • newRootAgent: A local agent that connects to the remote A2A service.

Remote Prime Agent (a2a_basic/remote_a2a/check_prime_agent/main.go)

  • checkPrimeTool: Function for prime number checking.
  • main: The main function that creates the agent and starts the A2A server.

2. Start the Remote A2A Agent server

You can now start the remote agent server, which will host the check_prime_agent:

# Start the remote agent
go run remote_a2a/check_prime_agent/main.go

Once executed, you should see something like:

2025/11/06 11:00:19 Starting A2A prime checker server on port 8001
2025/11/06 11:00:19 Starting the web server: &{port:8001}
2025/11/06 11:00:19 
2025/11/06 11:00:19 Web servers starts on http://localhost:8001
2025/11/06 11:00:19        a2a:  you can access A2A using jsonrpc protocol: http://localhost:8001

3. Check that your remote agent is running

You can check that your agent is up and running by visiting the agent card that was auto-generated by the A2A launcher:

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

You should see the contents of the agent card.

4. Run the Main (Consuming) Agent

Now that your remote agent is running, you can run the main agent.

# In a separate terminal, run the main agent
go run main.go

How it works

The remote agent is exposed using the A2A launcher in the main function. The launcher takes care of starting the server and generating the agent card.

remote_a2a/check_prime_agent/main.go
func main() {
    ctx := context.Background()
    primeTool, err := functiontool.New(functiontool.Config{
        Name:        "prime_checking",
        Description: "Check if numbers in a list are prime using efficient mathematical algorithms",
    }, checkPrimeTool)
    if err != nil {
        log.Fatalf("Failed to create prime_checking tool: %v", err)
    }

    model, err := gemini.NewModel(ctx, "gemini-2.0-flash", &genai.ClientConfig{})
    if err != nil {
        log.Fatalf("Failed to create model: %v", err)
    }

    primeAgent, err := llmagent.New(llmagent.Config{
        Name:        "check_prime_agent",
        Description: "check prime agent that can check whether numbers are prime.",
        Instruction: `
            You check whether numbers are prime.
            When checking prime numbers, call the check_prime tool with a list of integers. Be sure to pass in a list of integers. You should never pass in a string.
            You should not rely on the previous history on prime results.
    `,
        Model: model,
        Tools: []tool.Tool{primeTool},
    })
    if err != nil {
        log.Fatalf("Failed to create agent: %v", err)
    }

    // Create launcher. The a2a.NewLauncher() will dynamically generate the agent card.
    port := 8001
    launcher := web.NewLauncher(a2a.NewLauncher())
    _, err = launcher.Parse([]string{
        "--port", strconv.Itoa(port),
        "a2a", "--a2a_agent_url", "http://localhost:" + strconv.Itoa(port),
    })
    if err != nil {
        log.Fatalf("launcher.Parse() error = %v", err)
    }

    // Create ADK config
    config := &adk.Config{
        AgentLoader:    services.NewSingleAgentLoader(primeAgent),
        SessionService: session.InMemoryService(),
    }

    log.Printf("Starting A2A prime checker server on port %d\n", port)
    // Run launcher
    if err := launcher.Run(context.Background(), config); err != nil {
        log.Fatalf("launcher.Run() error = %v", err)
    }
}

Example Interactions

Once both services are running, you can interact with the root agent to see how it calls the remote agent via A2A:

Prime Number Checking:

This interaction uses a remote agent via A2A, the Prime Agent:

User: roll a die and check if it's a prime
Bot: Okay, I will first roll a die and then check if the result is a prime number.

Bot calls tool: transfer_to_agent with args: map[agent_name:roll_agent]
Bot calls tool: roll_die with args: map[sides:6]
Bot calls tool: transfer_to_agent with args: map[agent_name:prime_agent]
Bot calls tool: prime_checking with args: map[nums:[3]]
Bot: 3 is a prime number.
...

Next Steps

Now that you have created an agent that's exposing a remote agent via an A2A server, the next step is to learn how to consume it from another agent.