Skip to content

aws-samples/sample-agent-interoperability

AWS × GCP Agent Interoperability Demo

Disclaimer: AWS code samples are example code that demonstrates practical implementations of AWS services for specific use cases and scenarios. These application solutions are not supported products in their own right, but educational examples to help our customers use our products for their applications. As our customer, any applications you integrate these examples into should be thoroughly tested, secured, and optimized according to your business's security standards & policies before deploying to production or handling production workloads.

Why This Matters

Enterprises adopting AI agents face a real tension: they want to use the best models from multiple providers (Anthropic Claude on AWS, Google Gemini), but they also need agents to be accessible from their existing productivity tools — which increasingly means Gemini Enterprise. Meanwhile, their data, APIs, and infrastructure live on AWS.

This demo proves that these worlds don't have to be separate. It shows:

  • Model flexibility without lock-in. The same agent framework code runs on Anthropic Claude (via Amazon Bedrock) or Google Gemini — swap the model string, keep everything else. Enterprises can evaluate models side-by-side and switch without rewriting agents.

  • Meet users where they are. Agents deployed on AWS infrastructure are consumed directly from Gemini Enterprise's chat interface — the same UI employees already use for email and documents. No new app to roll out, no new login to remember.

  • Meet workloads where they are. Amazon Bedrock AgentCore Runtime deploys next to your existing AWS workloads — same VPC, same IAM, same region. Agents access internal APIs, databases, and services without crossing network boundaries or building new integrations. The compute runs where the data already lives.

  • Identity travels end-to-end. When a user talks to an agent from Gemini Enterprise or the React frontend, the agent knows who they are — Google Sign-In federated through Amazon Cognito, with email and name in the JWT all the way to the agent. This is the foundation for personalized responses, access control, and audit trails.

  • Open protocols, not proprietary glue. Agents speak A2A (Agent-to-Agent protocol) and consume tools via MCP (Model Context Protocol). These are open standards — any compliant client can talk to any compliant agent, regardless of who built either side.

  • Enterprise-grade infrastructure. Amazon Cognito handles auth, Amazon API Gateway handles routing and rate limiting, Amazon Bedrock AgentCore Runtime handles scaling and session management. No self-managed containers, no custom auth middleware in production.

The result: an enterprise can deploy AI agents on AWS, expose them to thousands of employees through Gemini Enterprise, let each employee be recognized by name, and swap LLM backends without touching the frontend. That's the multi-cloud agent story.


All 4 agents registered in Gemini Enterprise
Four agents (2 ADK + 2 Strands Agents) registered in Gemini Enterprise, each backed by a different framework and LLM.

Multi-cloud AI agent interoperability: Agent Development Kit (ADK) and Strands Agents SDK on Amazon Bedrock AgentCore Runtime, exposed via A2A protocol, using two LLM backends (Anthropic Claude via Amazon Bedrock, Google Gemini), with tools served through Amazon Bedrock AgentCore Gateway and direct MCP connections. Consumed by a React frontend and Gemini Enterprise.

User identity (Google Sign-In → Amazon Cognito federation → JWT with email) propagated end-to-end — agents greet users by name.

Chatting with an agent in Gemini Enterprise
An employee talks to the Strands Bedrock Agent directly from Gemini Enterprise — the agent is identified, authenticated, and responds using Amazon Bedrock AgentCore tools.

Architecture

Open docs/architecture.html in a browser for the full interactive diagram.

graph TD
    subgraph GCP["☁️ Google Cloud"]
        GE["🔷 Gemini Enterprise"]
        GAPI["✦ Gemini 2.5 Flash API"]
    end

    FE["🖥️ React Frontend<br/><small>Google Sign-In → Amazon Cognito PKCE</small>"]

    subgraph AWS["☁️ AWS (eu-west-1)"]
        subgraph PROXY["Gemini Proxy — Multi-Agent Router"]
            AUTH["🔐 Custom Authorizer"]
            ROUTER["🔀 AWS Lambda Router<br/><small>/bedrock /gemini /strands-*</small>"]
        end

        subgraph RT_ADK["Amazon Bedrock AgentCore Runtime — ADK"]
            ADK_B["🧠 ADK Bedrock<br/><small>Anthropic Claude Sonnet 4.6</small>"]
            ADK_G["🧠 ADK Gemini<br/><small>Gemini 2.5 Flash</small>"]
        end

        subgraph RT_STRANDS["Amazon Bedrock AgentCore Runtime — Strands Agents"]
            ST_B["⚡ Strands Bedrock<br/><small>Anthropic Claude Sonnet 4.6</small>"]
            ST_G["⚡ Strands Gemini<br/><small>Gemini 2.5 Flash</small>"]
        end

        subgraph GW["Amazon Bedrock AgentCore Gateway"]
            L1["λ Weather"]
            L2["λ Calculator"]
            MCP_A["🔌 MCP Server A<br/><small>word_count · summarize · keywords</small>"]
        end

        subgraph MCP_B["MCP Server B (Direct)"]
            T["🌡️ temperature"]
            D["📏 distance"]
            W["⚖️ weight"]
        end
    end

    FE -->|"A2A · Amazon Cognito JWT (email)"| RT_ADK
    FE -->|"A2A · Amazon Cognito JWT (email)"| RT_STRANDS
    GE -->|"A2A · Google → Amazon Cognito"| PROXY
    PROXY --> RT_ADK
    PROXY --> RT_STRANDS

    ADK_G -.->|"model invocation"| GAPI
    ST_G -.->|"model invocation"| GAPI

    RT_ADK -->|MCP| GW
    RT_STRANDS -->|MCP| GW
    RT_ADK -->|MCP| MCP_B
    RT_STRANDS -->|MCP| MCP_B
Loading

Prerequisites

AWS

  • AWS account with Amazon Bedrock AgentCore access in eu-west-1
  • AWS CDK bootstrapped (cdk bootstrap aws://<account>/eu-west-1)
  • Amazon Bedrock model access enabled for Claude Sonnet 4.6 (eu-west-1)

Google Cloud

  • Active Gemini Enterprise subscription (required for the Gemini Enterprise client integration)
  • Google Cloud project with the following APIs enabled: Vertex AI Search & Conversation (Discovery Engine)
  • Google API key for Gemini model invocation (used by ADK Gemini and Strands Gemini agents). Generate one at Google AI Studio and save to .google-api-key (gitignored).
  • OAuth consent screen configured with test users, and a Google OAuth 2.0 client ID (for Cognito federation)

Tools

  • Node.js 18+, Python 3.12+, AWS CDK CLI (npm install -g aws-cdk)
  • Docker (Colima or Docker Desktop) — for building ARM64 agent container images
  • uv (Python package manager) — for local agent development

Deployment

1. CDK Infrastructure (AWS)

First deploy creates the Amazon Cognito User Pool and M2M client. Subsequent deploys need the M2M client secret.

cd infra
npm install
npm run build

# First deploy — creates Cognito pool + M2M client (no secret needed yet)
AWS_PROFILE=<profile> AWS_REGION=eu-west-1 npx cdk deploy AwsGcpAgentsGateway

# Retrieve the M2M client secret (created by CDK, stored in Cognito)
M2M_SECRET=$(aws cognito-idp describe-user-pool-client \
  --user-pool-id $(aws cloudformation describe-stacks --stack-name AwsGcpAgentsGateway \
    --query 'Stacks[0].Outputs[?OutputKey==`UserPoolId`].OutputValue' --output text) \
  --client-id $(aws cloudformation describe-stacks --stack-name AwsGcpAgentsGateway \
    --query 'Stacks[0].Outputs[?OutputKey==`MachineClientId`].OutputValue' --output text) \
  --query 'UserPoolClient.ClientSecret' --output text)

# Deploy all stacks (pass M2M secret + Google API key)
bash ../scripts/bundle-agent.sh   # Copy shared/ into each agent dir
AWS_PROFILE=<profile> AWS_REGION=eu-west-1 npx cdk deploy --all \
  -c clientSecret=$M2M_SECRET \
  -c googleApiKey=$(cat ../.google-api-key) \
  -c deployStrands=true \
  --require-approval never

Note: The M2M client secret is auto-generated by Amazon Cognito when CDK creates the client. It's passed as a CDK context parameter (-c clientSecret=...) because CDK cannot export secrets as stack outputs. Store it securely — e.g. in .aws-profile alongside your AWS profile (both gitignored).

Stacks deployed:

Stack What
AwsGcpAgentsGateway Amazon Cognito User Pool (Google IdP, Pre-Token V2 trigger), Amazon Bedrock AgentCore Gateway + AWS Lambda tools, frontend client
AwsGcpAgentsRuntime 4 Amazon Bedrock AgentCore Runtimes (ADK + Strands Agents, Bedrock + Gemini), Docker ARM64
AwsGcpAgentsMcpServers MCP Server A (text analysis) + MCP Server B (unit conversion) on Amazon Bedrock AgentCore
AwsGcpAgentsGeminiProxy Amazon API Gateway + AWS Lambda proxy with multi-agent routing + custom authorizer

2. Gateway Wiring (one-time, after MCP Server A is deployed)

npx cdk deploy AwsGcpAgentsGatewayWiring \
  -c clientSecret=<secret> \
  -c serverAArn=<mcp-server-a-arn>

3. Gemini Enterprise (GCP)

Agents are registered via the Discovery Engine REST API. Each agent needs its own authorization resource (OAuth, one per agent — cannot be shared).

# Set variables
PROJECT=<gcp-project-id>
ENGINE=<gemini-enterprise-app-id>
TOKEN=$(gcloud auth print-access-token)
BASE=https://global-discoveryengine.googleapis.com/v1alpha/projects/$PROJECT/locations/global

# Create authorization resource (one per agent)
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" -H "x-goog-user-project: $PROJECT" \
  "$BASE/authorizations?authorizationId=<auth-id>" \
  -d '{
    "serverSideOauth2": {
      "clientId": "<cognito-auth-code-client-id>",
      "clientSecret": "<cognito-auth-code-client-secret>",
      "tokenUri": "https://<cognito-domain>/oauth2/token",
      "authorizationUri": "https://<cognito-domain>/oauth2/authorize?response_type=code&scope=openid+email+profile+aws-gcp-agents-gateway%2Fread+aws-gcp-agents-gateway%2Fwrite&redirect_uri=https%3A%2F%2Fvertexaisearch.cloud.google.com%2Foauth-redirect&identity_provider=Google"
    }
  }'

# Register agent
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" -H "x-goog-user-project: $PROJECT" \
  "$BASE/collections/default_collection/engines/$ENGINE/assistants/default_assistant/agents" \
  -d '{
    "displayName": "Agent Display Name",
    "description": "Agent description",
    "a2aAgentDefinition": {
      "jsonAgentCard": "<escaped agent card JSON with url pointing to API Gateway route>"
    },
    "authorizationConfig": {
      "agentAuthorization": "projects/<project-number>/locations/global/authorizations/<auth-id>"
    }
  }'

# List agents
curl -s -H "Authorization: Bearer $TOKEN" -H "x-goog-user-project: $PROJECT" \
  "$BASE/collections/default_collection/engines/$ENGINE/assistants/default_assistant/agents"

API Gateway routes → Agents:

Route Agent
/ (default) Strands Bedrock (Claude Sonnet 4.6)
/bedrock/ ADK Bedrock (Claude Sonnet 4.6)
/gemini/ ADK Gemini (Gemini 2.5 Flash)
/strands-gemini/ Strands Gemini (Gemini 2.5 Flash)

4. React Frontend

cd frontend
npm install
npm run dev    # http://localhost:3000

Click Sign in → Google Sign-In → Amazon Cognito federation → JWT with email/name → agents greet you by name. Sign-in is required to interact with agents.

Project Structure

src/
├── agents/
│   ├── shared/              # Shared agent code (both ADK + Strands)
│   │   ├── agent_core.py    # ADK: tools, instruction, IdentityMiddleware, /ping
│   │   ├── strands_agent_core.py  # Strands: MCP client, A2A server, identity
│   │   ├── gateway_tools.py # Amazon Bedrock AgentCore Gateway MCP toolset
│   │   └── direct_mcp_tools.py   # Direct MCP Server B toolset
│   ├── bedrock-agent/       # ADK Bedrock (thin wrapper)
│   ├── gemini-agent/        # ADK Gemini (thin wrapper)
│   ├── strands-bedrock-agent/  # Strands Bedrock (native BedrockModel)
│   └── strands-gemini-agent/   # Strands Gemini (native GeminiModel)
├── mcp-server-gateway/      # MCP Server A: word_count, summarize, keywords
├── mcp-server-direct/       # MCP Server B: temperature, distance, weight
├── lambda-tools/            # AWS Lambda functions (weather, calculator)
└── gemini-proxy/            # AWS Lambda proxy + custom authorizer
infra/
├── bin/app.ts               # CDK app entry
└── lib/                     # AWS CDK stacks (gateway, runtime, mcp, proxy)
frontend/                    # React + Vite + Tailwind
docs/                        # Architecture diagram (HTML)
scripts/                     # bundle-agent.sh, test-deployed-agent.sh

Key Technical Details

  • Identity propagation: Pre-Token-Generation V2 AWS Lambda trigger injects email/name into Amazon Cognito access tokens. AWS CDK escape hatch forces V2_0 (CDK defaults to V1_0). requestHeaderConfiguration allowlists Authorization header on Amazon Bedrock AgentCore Runtimes. ASGI IdentityMiddleware decodes JWT, stores in contextvars. get_current_user tool reads identity.
  • A2A protocol: JSON-RPC 2.0 over HTTP. Agent card at /.well-known/agent.json. Health check at /ping ({"status": "Healthy", "time_of_last_update": <epoch>}).
  • Static agent cards: Passed to to_a2a(agent_card=path) to skip MCP tool enumeration at startup (30s init limit on Amazon Bedrock AgentCore).
  • MCP on Amazon Bedrock AgentCore: terminate_on_close=False required. Auth headers in StreamableHTTPConnectionParams.headers, not header_provider.
  • Docker: ARM64 platform for Amazon Bedrock AgentCore Runtime. scripts/bundle-agent.sh copies shared/ into each agent dir before AWS CDK deploy.
  • Multi-agent routing: Amazon API Gateway routes (/bedrock, /gemini, /strands-bedrock, /strands-gemini) → AWS Lambda proxy resolves target agent ARN from path prefix.

Security Considerations

This is a sample application for educational purposes. The code is intentionally kept simple to focus on demonstrating multi-cloud agent interoperability patterns. For production deployments, you should:

  • IAM policies: The sample uses broad permissions (bedrock-agentcore:*, Resource: "*") for simplicity. In production, scope IAM policies to specific resource ARNs and use least-privilege actions.
  • Amazon Bedrock Guardrails: No content filtering, prompt attack protection, or PII detection is configured. Production deployments should enable Amazon Bedrock Guardrails for content safety.
  • Amazon API Gateway: Access logging and AWS WAF are not enabled. Production APIs should enable Amazon CloudWatch access logging, AWS WAF, and request throttling.
  • Secrets management: All sensitive credentials (Cognito M2M secret, Google API key) are stored in AWS Secrets Manager and fetched at runtime via boto3. See SECURITY.md for details on the CDK synthesis caveat and production upgrade path.

Inter-Cloud Connectivity

This demo uses public endpoints for cross-cloud communication (Gemini API calls from AWS, A2A traffic from Gemini Enterprise). For production deployments requiring private connectivity between AWS and Google Cloud, AWS Interconnect – multicloud (public preview) provides fully managed, private Layer 3 connectivity — provisioned in minutes, MACsec encrypted, with traffic flowing entirely on AWS and Google Cloud private backbones. See the announcement blog post and reference architectures.

Alternatives include AWS Site-to-Site VPN + Google Cloud HA VPN (lower throughput, simpler setup) or Google Cloud Cross-Cloud Interconnect via shared colocation facilities.

About

Multi-cloud AI agent interoperability sample. Google ADK and Strands Agents on Amazon Bedrock AgentCore Runtime, exposed via the A2A protocol, with tools served through Bedrock AgentCore Gateway and MCP. Consumed from a React frontend and Gemini Enterprise.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors