What a2a multi-agent systems are and why agents need a shared protocol
If you want to build a2a multi-agent systems that span organizational boundaries, the hard part is the seam between them: agents built by different organizations, on different frameworks, must discover each other, exchange tasks, and collaborate without exposing their internals or forcing both sides onto the same stack. Without a shared protocol, every customer and every framework needs its own custom integration code — which is why vendors care about A2A: build once, and work with the A2A-compatible frameworks customers already use.
A2A is now a Linux Foundation project: Google created it in April 2025, and it joined the Foundation on 23 June 2025 with support from more than 100 technology companies, AWS among them. The protocol lets agents discover each other, negotiate tasks, and collaborate across boundaries, using OAuth 2.0 and OpenID Connect for security. AWS published a deployed reference architecture on 12 November 2026 showing it end to end: a LangChain enterprise orchestrator talking to a Strands compliance agent in a separate AWS account, OAuth in both directions, no shared secrets. It builds on an earlier AWS post that established Agent Card discovery, structured task execution, and the A2A server pattern.
How the A2A protocol works

In this reference implementation, A2A runs as JSON-RPC 2.0 over HTTPS, built around message/send. An agent publishes an Agent Card — a JSON document at /.well-known/agent-card.json — describing its name, capabilities, and skills, plus, through securitySchemes, how a caller authenticates. One document tells a compatible client what the agent can do. Here is the card the compliance agent publishes, abridged:
{
"name": "Compliance SaaS Agent",
"description": "Scans AWS accounts for compliance with your organization's policies; returns findings by severity, remediation steps, and escalation contacts.",
"url": "https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/.../invocations/",
"protocolVersion": "0.3.0",
"capabilities": { "streaming": true },
"skills": [
{ "id": "compliance-scan", "name": "Compliance scan",
"description": "Scans your AWS accounts against your organization's policies." }
],
"securitySchemes": {
"cognito": { "type": "oauth2",
"description": "OAuth 2.0 client credentials from the customer's identity provider." }
},
"security": [ { "cognito": ["a2a-enterprise-compliance-saas/invoke"] } ]
}Two details matter most. At startup the orchestrator creates a LangChain tool per skill, so the model routes by the user’s question with no hardcoded routing. And the card declares how a caller authenticates, which the orchestrator checks rather than following blindly: it keeps the card only if its url matches the address it was fetched from (card pinning) and its securitySchemes name the registered token endpoint and scope.
The AWS reference architecture: three agents, two accounts

The deployed system runs three agents in two AWS accounts. On the enterprise side, two agents run on Amazon ECS with AWS Fargate in private subnets. The Enterprise Orchestrator is the entry point: LangChain on Amazon Bedrock, with Anthropic Claude Sonnet 4.6. At startup it fetches the SaaS agent’s Agent Card and creates a LangChain tool per skill, so the model routes by the user’s question with no hardcoded routing. The Enterprise Context Agent, built on Bedrock (Amazon Nova Lite), supplies internal account metadata: policy rules, data classification, business criticality, escalation contacts. It serves A2A via the official a2a-sdk, pinned to a2a-sdk[http-server]==1.2.2, and publishes its own Agent Card at /.well-known/agent-card.json. Both directions speak A2A v0.3; the compliance agent runs Strands with a2a-sdk 0.3.
On the SaaS provider side, the Compliance SaaS Agent runs on Amazon Bedrock AgentCore in the provider’s own AWS account. Built with the Strands Agents SDK, it checks AWS accounts against the enterprise’s internal policies — no public storage in production, encryption at rest for confidential data. It exposes three compliance tools — listing accounts, running scans, retrieving remediation steps — plus a fourth that calls back to the enterprise. Its Agent Card lists none of those tools, just one curated skill, so callers’ models see what the product does, not how it is built. In the demo the scanning tools return synthetic data; in production they would connect to AWS Config, Security Hub, or GuardDuty.
Each account has its own Cognito user pool, so each side authenticates with its own identity provider. During onboarding, the two sides exchange only public values — identity provider URLs, client IDs, scopes, endpoint URLs — in onboarding-request.json and onboarding-response.json. Each side then trusts the other’s tokens, and no secrets are shared. Each agent uses the model that fits its workload: the orchestrator uses Claude Sonnet 4.6 and the context agent uses Amazon Nova Lite.
How a request flows end to end

After onboarding, each request follows seven steps:
- The enterprise app gets a token from the enterprise pool.
- The app sends a question over HTTPS to the user API in API Gateway, then polls for the answer.
- API Gateway forwards the request privately, via a VPC link and an internal Network Load Balancer, to the Enterprise Orchestrator.
- When its model decides the question needs a compliance scan, the orchestrator gets its own token from the enterprise pool.
- The orchestrator sends an A2A request to the compliance agent on Bedrock AgentCore, using the skill from the agent’s Agent Card.
- The compliance agent checks the enterprise context agent’s Agent Card at the callback URL registered at onboarding, then gets a token from the SaaS pool.
- The compliance agent calls back to the enterprise context agent for account metadata, finishes its scan, and returns the answer to the orchestrator and the app.
The orchestrator’s A2A client is deliberately plain: raw httpx calls with A2A JSON-RPC, no Strands SDK dependency — if the vendor switched frameworks, the orchestrator would keep working as long as the SaaS agent still speaks A2A. Its token goes only to the agent URL pinned to the address the Agent Card was fetched from. The core request is a JSON-RPC message/send:
{
"jsonrpc": "2.0",
"id": "lc-<uuid>",
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{ "kind": "text", "text": "<question>" }],
"messageId": "<uuid>"
}
}
}Every A2A message/send carries a JWT from the sender’s own identity provider, and the receiving side accepts only that provider, one client, and one scope. The only unauthenticated endpoint is the context agent’s public Agent Card, and access tokens last 15 minutes. One OAuth detail trips people up: a Cognito client-credentials token carries client_id and scope but no aud claim, so the API Gateway authorizer checks client_id against the audience list, and on the AgentCore side allowedClients is set with allowedAudience left unset:
{"customJWTAuthorizer": {
"discoveryUrl": "https://cognito-idp.us-east-1.amazonaws.com/<enterprise pool ID>/.well-known/openid-configuration",
"allowedClients": ["<a2a-enterprise-orchestrator-saas client ID>"],
"allowedScopes": ["a2a-enterprise-compliance-saas/invoke"]
}}The callback matters when the called agent needs information only the caller has: which accounts are production, which policies apply, who to escalate to. The SaaS agent calls back over A2A, but only to the callback URL registered at onboarding: it verifies the customer’s public context card there, then gets a token from the SaaS pool and sends message/send to the enterprise partner API. A verified card is reused for 5 minutes; a failed check is never cached. Every failure gives the model one message — “Enterprise context unavailable”. The agents become true peers, not a client and a server.
Deploying it: notebooks, the a2a-sdk, and the end-to-end test
You deploy the system with three Jupyter notebooks, run in order, one cell at a time. Notebook 1 (enterprise account, about 3 minutes) creates the enterprise identity and writes an onboarding request. Notebook 2 (SaaS provider account, about 5 minutes) deploys the compliance agent and writes an onboarding response. Notebook 3 (enterprise account, about 20 minutes) deploys the enterprise agents and runs the tests — five CloudFormation stacks in total, three enterprise and two SaaS. The public repository is aws-samples/sample-a2a-cross-org-agents on GitHub, with the three notebooks, the CloudFormation templates, and a README covering the trust model, Agent Card discovery, and the tests.
Prerequisites: two AWS accounts in the same Region (us-east-1, us-east-2, or us-west-2), Claude Sonnet 4.6 access in both, Nova Lite in the enterprise account, and a Jupyter environment with Python 3.10 or later — JupyterLab on your computer, or a SageMaker AI notebook instance in each account (ml.t3.medium is enough). Each notebook first checks Bedrock model access before deploying anything.
Notebook 3 runs one end-to-end test through both accounts. It gets a token for the enterprise app, submits the question — “Scan our production accounts for compliance with our internal policies, and include escalation contacts for critical findings” — receives HTTP 202 with a job ID, and polls every 5 seconds until the report is ready.
The test passes only if the reply has compliance findings, includes an on-call rotation code only the enterprise context agent knows, and the partner API’s access log shows a 200 from the SaaS callback client. In the sample run, the report covered two production accounts and six findings, and the test finished in 52.5 seconds (usually 1 to 3 minutes, waiting up to 10). Notebook 3 then runs seven trust boundary checks sending a wrong, missing, or forged token to each gate; every call must be rejected with a 401, and all seven passed in 1.4 seconds. You can send the same request from any HTTP client, without an A2A SDK. For recurring costs, check the deployment resources in the repository; when you finish, follow the repository’s cleanup instructions.
When this pattern fits — and where it gets hard
The pattern fits when agents from different organizations must compose into a workflow neither team built alone. The ISV use case is clearest: a vendor’s compliance agent and an enterprise’s context agent compose into a report neither produces alone, and the vendor can change its internals without changing customer integrations, as long as its Agent Card and A2A interface stay compatible. The same shape applies to agents exposed to partners, customers, or internal teams on different frameworks. As the system grows, you add skills by registering Agent Cards: when the vendor adds a capability, its Agent Card changes with it and the orchestrator picks up the new skills at the next restart.
Cross-organization trust setup is real work: each side must register the other’s issuer, client ID, and scope at every gate, and the token rules are exact. Both sides must be A2A-compatible; the pattern does not help if one side speaks only a proprietary protocol. The orchestrator holds a single OAuth client today, so adding a second vendor takes one extension: one client and scope per vendor, the same onboarding exchange, its Agent Card URL added, and the orchestrator restarted. For production, seven changes: per-customer runtimes or a front door for several identity providers, key-based auth (private_key_jwt or mutual TLS) instead of client secrets, PrivateLink and TLS inside the VPC, customer-managed KMS keys, flow logs, credential rotation, and an authenticated onboarding portal. Deploy it only in sandbox accounts: the sample uses synthetic data and certifies nothing. The security controls are worth copying anyway — HTTPS for external communication, a Cognito JWT on every route but the public Agent Card, Bedrock guardrails on every model call, least-privilege IAM roles, and hardened containers.
What to build next
Start from the AWS notebooks. Clone aws-samples/sample-a2a-cross-org-agents, set up two AWS profiles for local runs or one notebook instance per account, and run the three notebooks in order, handing the onboarding files between the accounts as you go. Run the end-to-end test and the seven trust boundary checks, and confirm the report carries the context-only marker before you trust the callback.
Once the deployed system works, add a second skill via a new Agent Card before writing custom integration code: register the new card, restart the orchestrator, and watch the model pick up the new tool from the card text. That is the whole point — the next capability arrives as a document, not a meeting. Two limits the sources do not answer: neither the post nor the repository states limits on Agent Card size or A2A task payload sizes, so verify the behavior yourself.












