Resolve endpoints and build orchestrators

The Agent Development Kit (ADK) provides a dedicated AgentRegistry client that lets you programmatically discover, look up, and connect to AI agents and Model Context Protocol (MCP) servers cataloged within Agent Registry.

Instead of hardcoding endpoint URLs into your application, you can use the ADK to resolve these endpoints at runtime.

Agent Registry provides the underlying endpoints, but production deployments typically route these invocations through Agent Gateway. Agent Gateway helps you enforce security policies, perform protocol mediation, and apply content filtering to the tools you discover.

This document describes how to retrieve remote agents and MCP toolsets from Agent Registry and include them in a parent orchestrator agent.

Before you begin

Before you integrate the ADK with Agent Registry, complete the following:

  1. Set up Agent Registry in your project.
  2. Install or upgrade to the latest version of the ADK with the necessary A2A dependencies:

    pip

    pip install --upgrade "google-adk[a2a]"
    

    uv

    uv add "google-adk[a2a]"
    

    You must upgrade to at least google-adk>=1.29.0.

  3. Configure Application Default Credentials (ADC):

    gcloud auth application-default login
    

ADC credentials must have the necessary IAM permissions for the underlying services the agents or tools interact with. Optionally, you can also use custom headers for external toolsets. For more information, see Authenticate to tools and resources.

Set environment variables

To follow this guide, set the following environment variables:

export GOOGLE_CLOUD_PROJECT=PROJECT_ID
export GOOGLE_CLOUD_LOCATION=LOCATION

Replace the following:

  • PROJECT_ID: your project ID.
  • LOCATION: the registry region or location, such as us-central1.

Initialize the registry client

To interact with your registry programmatically, initialize the AgentRegistry client with your project and location:

import os
from google.adk.integrations.agent_registry import AgentRegistry

project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")
location = os.environ.get("GOOGLE_CLOUD_LOCATION", "global")

if not project_id:
    raise ValueError("GOOGLE_CLOUD_PROJECT environment variable not set.")

# Initialize the client
registry = AgentRegistry(
    project_id=project_id,
    location=location,
)

Compose a multi-agent system

The ADK abstracts the underlying connection mechanics, letting you design scalable applications by composing multiple specialized agents into flexible hierarchies.

You can use the registry client to fetch specific resources and pass them directly into the definition of a new LlmAgent agent. Your orchestrator can invoke remote agents as sub-agents and execute MCP tools as if they were local Python functions.

Use the following methods:

  • To fetch a remote agent: Use get_remote_a2a_agent()
  • To fetch an MCP toolset: Use get_mcp_toolset()

The following example demonstrates how to compose a multi-agent system by building an orchestrator agent that takes advantage of a registered travel agent and a registered Compute Engine MCP server. In this example, authentication is handled by the agent's own identity, but you can use other methods, such as API keys and OAuth. For more information, see Authenticate to tools and resources.

import httpx
import google.auth
from google.auth.transport.requests import Request
from google.adk.agents.llm_agent import LlmAgent

# Define the GoogleAuth class for the HTTP client
class GoogleAuth(httpx.Auth):
    def __init__(self):
        self.creds, _ = google.auth.default()
    def auth_flow(self, request):
        if not self.creds.valid:
            self.creds.refresh(Request())
        request.headers["Authorization"] = f"Bearer {self.creds.token}"
        yield request

# Connect to a remote A2A agent using its resource name in short or full format
# Short formats automatically imply the client's configured project and location
# Short format: "agents/AGENT_ID"
# Full format: f"projects/{project_id}/locations/{location}/agents/AGENT_ID"
agent_name = "agents/AGENT_ID"

# Configure the HTTP client with GoogleAuth and a 60-second timeout
httpx_client = httpx.AsyncClient(auth=GoogleAuth(), timeout=httpx.Timeout(60.0))
my_remote_agent = registry.get_remote_a2a_agent(
    agent_name=agent_name,
    httpx_client=httpx_client
)

# Retrieve an MCP toolset using its resource name in short or full format
# Short formats automatically imply the client's configured project and location
# Short format: "mcpServers/SERVER_ID"
# Full format: f"projects/{project_id}/locations/{location}/mcpServers/SERVER_ID"
mcp_server_name = "mcpServers/SERVER_ID"
my_mcp_toolset = registry.get_mcp_toolset(mcp_server_name=mcp_server_name)

# Compose the orchestrator agent
main_agent = LlmAgent(
    model="MODEL_ID", # Replace with a model such as gemini-1.5-flash
    name="travel_orchestrator",
    instruction="""You are a travel coordinator. You can use your
                   sub-agents to book travel and your tools to query
                   historical travel data.""",
    tools=[my_mcp_toolset],
    sub_agents=[my_remote_agent],
)

# You can now run your orchestrator agent
# response = await main_agent.run('Book a flight to Paris and check my past trips.')

Best practices for reusing agents

To minimize network latency, fetch your agents and toolsets from the registry once at application startup instead of calling get_remote_a2a_agent() on every invocation.

An agent can only have one parent agent at a time. If you attempt to assign the same fetched agent instance to multiple orchestrators, the ADK might throw an error indicating that the agent already has a parent.

To reuse a discovered agent across multiple parent agents, use the .clone() method to create a new instance of the agent object.

The following example shows how to fetch an agent once and clone it for use in different orchestrators:

import httpx
import google.auth
from google.auth.transport.requests import Request
from google.adk.agents.llm_agent import LlmAgent

# Define the GoogleAuth class for the HTTP client
class GoogleAuth(httpx.Auth):
    def __init__(self):
        self.creds, _ = google.auth.default()
    def auth_flow(self, request):
        if not self.creds.valid:
            self.creds.refresh(Request())
        request.headers["Authorization"] = f"Bearer {self.creds.token}"
        yield request

# Configure the HTTP client with GoogleAuth and a 60-second timeout
httpx_client = httpx.AsyncClient(auth=GoogleAuth(), timeout=httpx.Timeout(60.0))

# Fetch the remote agent once during startup
# Use the resource name in short or full format
# Short formats automatically imply the client's configured project and location
# Short format: "agents/AGENT_ID"
# Full format: f"projects/{project_id}/locations/{location}/agents/AGENT_ID"
agent_name = f"projects/PROJECT_ID/locations/LOCATION/agents/AGENT_ID"
base_remote_agent = registry.get_remote_a2a_agent(
    agent_name=agent_name,
    httpx_client=httpx_client
)

# Use .clone() to assign the agent to different parent orchestrators
flight_orchestrator = LlmAgent(
    model="gemini-1.5-flash",
    name="flight_orchestrator",
    sub_agents=[base_remote_agent.clone()]
)

hotel_orchestrator = LlmAgent(
    model="gemini-1.5-flash",
    name="hotel_orchestrator",
    sub_agents=[base_remote_agent.clone()]
)

What's next