Running and Debugging A2A Agents in Gemini Enterprise

The vision for Gemini Enterprise is to become the ultimate welcome page for knowledge workers, allowing them to search for answers across all company data sources. But there is more to it than just search. Gemini Enterprise makes it incredibly easy for employees to collaborate with AI Agents across the organization. These agents are registered in the Agent Gallery, a central hub for discovering, using, and managing agents.

The gallery categorizes agents into three types:

  • Made by Google: Ready-to-use tools like Deep Research or NotebookLM.

  • From your organization: Agents your team created or purchased from the Marketplace.

  • Your agents: Custom agents created via the no-code Agent Designer.

While the no-code Designer is a sought-after feature, this article focuses on custom agents brought into the Agent Garden from the outside. These might be built by in-house teams using the Google Agent Development Kit (deployed to Vertex AI Agent Engine) or third-party solutions.

To make diverse AI Agents work together, we need a standard way for them to communicate. This is where the Agent 2 Agent (A2A) Protocol comes in.

https://a2a-protocol.org/latest/topics/what-is-a2a/

You can bring A2A agents to Gemini Enterprise using Agent Gallery Admin UI (Custom agent via A2A option) or from SDK/API.

What is A2A?

A2A is an open standard (donated by Google to the Linux Foundation) that acts as the “universal language” for agentic communication. It bridges the gap between different frameworks and vendors, allowing an agent built in Python on Google Cloud to talk seamlessly to an agent built in Java on another platform.

Bringing an A2A agent into Gemini Enterprise usually works out of the box. But when it doesn’t, debugging can be a nightmare.

The Philosophy: Debug Outside to Fix Inside. The core of this framework is simple: If we want to use our A2A Agent from Gemini Enterprise, we must first prove we can use it without Gemini Enterprise. Why? Because Gemini acts as an A2A Client. If a simple Python script (acting as a client) cannot authorize and access your server, Gemini won’t be able to either.

In this article, I will share the 5-Step Framework I use to debug connection issues when a Gemini Enterprise struggles to talk to a remote A2A agent.

How A2A Works: The “Lingua Franca” of Agents

To understand how to debug A2A, we need to look under the hood. How does A2A actually standardize communication?

The concept relies on the A2A Executor. Think of the Executor as a wrapper or a bridge. Agent developers package their agent logic into this Executor class, which exposes specific, standardized methods for exchanging messages. The developer builds a translation layer between their native framework (what they used to build the agent) and the A2A standard. This Executor needs a home. It runs inside an A2A Server that provides the necessary API endpoints. The beauty of this model is its flexibility: an A2A Server can run almost anywhere, including:

  • Vertex AI Agent Engine

  • Cloud Run

  • Google Kubernetes Engine (GKE)

  • On-premise servers or even other clouds

Because A2A follows a strict client-server model, anything that consumes your A2A Server is effectively an A2A Client. Whether it’s a custom script or Gemini Enterprise, the rules of engagement are the same.

Step 1: Build a “Hello World” A2A Client

The first step in our debugging framework is to bypass Gemini Enterprise entirely. We will use the A2A SDK to build a minimal A2A Client that sends a “Hello World” message to your agent.

You can host your A2A Server anywhere, but for these examples, I will assume you are using the Vertex AI Agent Engine.

Note: As you see A2A Client doesn’t need to be an agent itself. A simple Python, Go, or Java script works perfectly as an A2A Client.

Here is a Python boilerplate to get you started:

async with httpx.AsyncClient(
            headers={
                "Authorization": f"Bearer {get_bearer_token()}",
                "Content-Type": "application/json",
            }
    ) as httpx_client:
        config = ClientConfig(
                    httpx_client=httpx_client, 
                    supported_transports=[
                        TransportProtocol.http_json,
                    ],
                    use_client_preference=True,
        )

        client = await ClientFactory.connect(
            agent=AGENT_URL, 
            client_config=config,
            relative_card_path='/v1/card'
        )

        message_payload = {
            'role': 'user',
            'parts': [{'kind': 'text', 'text': USER_QUERY}],
            'messageId': uuid4().hex,
            'contextId': '959304c1-e814-4486-b9a7-efe885a6b066'
        }
        
        print(f"--- Sending Authenticated Message ---")
        # Send raw dictionary
        response_stream = client.send_message(message_payload)

In the code above, ClientFactory needs two things:

  1. AGENT_URL: The base URL of your agent.

  2. relative_card_path: The specific path to the Agent Card.

The Agent Card is a JSON document that acts as your agent’s digital business card. It usually resides at .well-known/agent-card.json or /v1/card. It tells the client exactly what the agent can do. Here is a sample Agent Card:

{
  "capabilities": { "streaming": false },
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["application/json"],
  "description": "Agent that works with Instavibe backend",
  "name": "Instavibe A2A Agent",
  "preferredTransport": "HTTP+JSON",
  "protocolVersion": "0.3.0",
  "skills": [
    {
      "description": "creates post on instavibe platform",
      "name": "create_post",
      "id": "create_post"
    }
  ],
  "supportsAuthenticatedExtendedCard": true,
  "url": "https://your-agent-url-here.com",
  "version": "1.0.0"
}

The url field inside the Agent Card is the endpoint where the A2A service can be reached.

Locating your Vertex AI Agent Engine A2A Endpoints

If you are deploying to Vertex AI Agent Engine, your endpoints typically follow this pattern:

where Agent Engine Resource Name: AGENT_ENGINE_RESOURCE_NAME = projects/{PROJECT_ID}/locations/{LOCATION}/reasoningEngines/{AGENT_ENGINE_ID}

  • Agent Card URL: {AGENT_URL}/v1/card

The OAuth2 Hurdle

This is where most developers get stuck. Enterprise A2A Servers are secured, they talk to other enterprise systems.

Typical mechanism used to authorize requests is to use OAuth2 protocol. In this approach your script must retrieve an OAuth2 token and inject it into the header: "Authorization": f"Bearer {get_bearer_token()}".

This is a great exercise to do outside of Gemini Enterprise. Why? Because OAuth2 is often a stumbling block for ML and Data specialists moving into agentic workflows. If you can’t get a valid token for this script, Gemini Enterprise won’t be able to get one either.

Success Criteria for Step 1:

  • You have a valid OAuth2 token.

  • Your script connects to the A2A Server.

  • You receive a response from the agent.

If this works, you have verified that the agent is fine. Now we can introduce Gemini Enterprise.

Step 2: Registering the Agent in Gemini

Only once Step 1 is successful should you proceed to the Gemini Enterprise Admin Panel. Select option: [Custom agent via A2A]:

You will be asked to provide the Agent Card (the JSON document we discussed above).

You will also configure the OAuth2 details so Gemini knows how to start Oauth2 flow.

Pro-Tip: Behind the scenes, Gemini Enterprise simply injects the resulting token as a Bearer token into requests sent to your A2A Server—exactly like our Python script did.

Make sure your Authorization URL includes all necessary scopes. For example:

https://accounts.google.com/o/oauth2/v2/auth?client_id=XXXXXXXXX-yyyyyyuvo6xxxxxxxxxxxx.apps.googleusercontent.com&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&include_granted_scopes=true&response_type=code&access_type=offline&prompt=consent

Step 3: Verify Authorization in the UI

Now, go to Gemini Enterprise as a user and try to chat with your agent.

Since this is the first time accessing the agent, Gemini should prompt you with an “Authorize” button.

Clicking this triggers the standard OAuth2 popup flow.

Common Pitfall: If you get “400 redirect_uri_mismatch” error here, check your OAuth Client settings. You must add the Gemini Enterprise redirect URI to your Authorized Redirect URIs:

https://vertexaisearch.cloud.google.com/oauth-redirect

When Gemini Enterprise asks a user to authorize an AI agent, the flow looks like this:

  1. The Request: Gemini Enterprise initiates the Oauth2 flow by redirecting the user to the Authorization Endpoint (authorization_url) hosted by Authorization Server. In that request, Gemini Enterprise says, “Once you are done, please send them back to me at this specific URL (the redirect URI).”

  2. The Check: Authorization Server looks at that URL. It then checks your OAuth Client settings to see if you have pre-registered that specific URL as “trusted.”

Redirect URI functions like a verified “Return Address.” Without it, authentication servers will block the attempt to protect the user’s data.

If the authorization flow completes successfully, you will see a confirmation, followed by the agent’s response.

Step 4: Analyzing the Conversation

If Step 3 works, you are ready to send questions to you A2A Agent. Gemini Enterprise is now acting as the A2A Client, parsing your prompt, sending message which payload is consistent with A2A protocol, and parsing and rendering the response.

But what if it fails silently? If the agent returns a generic error or behaves unexpectedly, debugging becomes difficult because you don’t own the “Client” (Gemini Enterprise backend) and you might not own the “Server” (if it’s a third-party agent like ServiceNow or Salesforce).

You could ask Google Cloud Support for help using the assistToken, but there is a faster way to debug this yourself but I will show you things you can do on your side.

Step 5: Advanced Debugging with an A2A Proxy

This is the “secret weapon” of this framework. To see exactly what Gemini Enterprise is sending to your agent, we will insert a “man-in-the-middle” proxy.

However, you might think a proxy just needs to forward requests back and forth. But the A2A protocol adds a twist that trips up many developers.

Let’s trace the sequence of actions when an A2A Client (like Gemini or our Python script) connects:

  1. Handshake: The Client calls the Proxy to get the Agent Card.

  2. Discovery: The Proxy fetches the card from the real Agent and returns it to the Client.

  3. The Catch: The Client parses the Agent Card and looks for the url attribute. This attribute tells the Client where to send future chat messages.

Here is the problem: If your Proxy simply forwards the original Agent Card, that card will contain the Real Agent’s URL. The Client will read that URL and send the next message directly to the Real Agent, completely bypassing your Proxy. You won’t see a single log entry for the actual conversation.

To keep the conversation flowing through our debugger, the Proxy must do one additional thing: Intercept and Modify the Agent Card.

When the Proxy fetches the card from the Real Agent, it must:

  1. Parse the Agent Card JSON.

  2. Find the url attribute.

  3. Replace it with the Proxy’s own URL.

  4. Return the modified card to the Client.

Now, when the Client reads the card, it thinks the “Agent” lives at the Proxy’s address. It will send all chat messages to the Proxy, allowing us to log and inspect every payload before forwarding it to the real destination.

This is how Gemini 3 Pro Nano Banana pictured this:

This problem does not exist when we use Gemini Enterprise though. Why?

Understanding the Agent Card Registry

There is an important nuance here. A2A Servers often provide two distinct endpoints:

  1. Communication Endpoint: Where the actual chat messages are sent.

  2. Agent Card Endpoint: Where the server self-describes its capabilities (as a JSON document).

In a standard A2A client (like our script above), the client fetches the card directly from the server.

However, Gemini Enterprise works differently. Gemini’s Agent Gallery acts as an Agent Registry. When you register an agent, you don’t provide a URL to the card (at least now); you actually copy and paste the JSON document into the Gemini UI.

This means Gemini stores a static copy of your agent’s definition.

Deploy A2A Proxy to Cloud Run

We can test A2A proxy locally if it works with our Python A2A Client but then we will deploy it to Cloud Run so it can be easily access by Gemini Enterprise. We will package the Proxy into a Docker container and deploy it to Cloud Run. This gives us a public HTTPS URL that Gemini can reach.

Registering the A2A Agent Proxy in Gemini

This is the critical final step. When you go to the Gemini Enterprise Admin Console to register your agent:

  1. Do not use the original Agent URL.

  2. Instead, use the A2A Proxy’s URL in the Agent Card configuration.

This forces Gemini to route all traffic through your Cloud Run service, giving you a live stream of request/response logs in Google Cloud Logging. You can now see exactly why a request is failing — whether it’s a malformed JSON payload, a missing field, or a protocol mismatch.

We are ready to send questions to our A2A Server from Gemini Enterprise but this time all message payloads sent from Gemini Enterprise will be logged by our A2A Proxy running on Cloud Run:

A Note on Authorization with A2A Proxy

In my experiments, both my remote A2A Agent (Agent Engine) and A2A Proxy (Cloud Run) were running on Google Cloud where both use the same Google identity management, so I could easily enable authorization on Cloud Run for A2A Proxy.

However, things get complicated with A2A Proxy if your agent lives outside Google Cloud. Gemini Enterprise injects a single Authorization header (the Bearer token) into the request. It cannot send two tokens (one for the Proxy and one for the target Agent).

Picture this:

  • The Scenario: Your target agent is Jira or ServiceNow, you need Bearer token to authorize your agent to act in these systems.

  • The Conflict: If you also enable IAM Authentication on your Cloud Run Proxy, the Proxy will try to validate that Jira token as a Google token, and it will fail (403 Forbidden).

To debug external agents, the simplest approach would be to allow unauthenticated invocations on your Cloud Run Proxy. When applied this allows the Proxy to act as a transparent “dumb pipe,” passing the specific Jira or ServiceNow headers through to the destination without interfering (to make it secure, you can restrict sources that can make unauthenticated invocations, but that is outside the scope of this article).

Summary:

Connecting remote A2A agents to Gemini Enterprise is a powerful capability, but some may struggle with network and protocol complexities. By treating Gemini Enterprise as just another A2A Client and validating your connection with a standalone script first (Step 1), you eliminate the biggest source of errors. When all else fails, the Proxy pattern (Step 5) gives you X-Ray vision into the conversation, allowing you to debug even the most opaque connection issues.

This article is authored by Lukasz Olejniczak — Customer Engineer at Google Cloud. The views expressed are those of the authors and don’t necessarily reflect those of Google.

Please clap for this article if you enjoyed reading it. For more about google cloud, data science, data engineering, and AI/ML follow me on LinkedIn.

Hey, do you know when would be no-code agent sharing be available? Like it’s From your Organization, but not Agent Engine, it’s Agent Designer inside the Gemini Enterprise!

Thanks for this @lolejniczak17! I want to ask for some advice around understanding how Gemini Enterprise interacts with the stream of messages received from a Custom Agent.

We are have developed our own ADK-built A2A agents, hosted on Cloud Run (NOT Vertex AI Engine) that follows the same kind of Auth pattern that you described.

A frustrating thing for us has been the lack of understanding in terms of how Gemini Enterprise interacts with A2A and how it makes use of different metadata - such as the adk_thoughts that come through.

Example:

We have an agent that has a thinking budget, thoughts included and uses SSE. When making streaming calls to it from eg. Postman or a Custom UI, we can see the various A2A StreamResponse coming in with the expected set of Task, TaskStatusUpdateEvent, ArtifactUpdateEvent, Message payloads.

When inspecting these, it contains the various ADK related Metadata, such as adk_thoughts.

We then have registered this as a custom agent in Gemini Enterprise. What we would have thought was that the various updates are surfaced through the Thoughts section in the response, however we have found that Gemini Enterprise always behaves strangely. The thoughts that came from the ADK agent are all included in the final response message, and when expanding the thought section, there are almost no thoughts

Hello @lolejniczak17, thanks for this explanation.

I have create an agent for my organisation and histed it on Cloud Run.
and i have followed these steps to link Gemini Enterprise in A2A, but it could not respond, while with classic A2A client it works. Why doesn’t it respond, it blocks itsself after thinking ?

Thanks for your response.