← Back to Plugins
Tools

A2a Gateway

win4r By win4r ⭐ 13 stars 👁 3 views ▲ 0 votes

OpenClaw plugin implementing the A2A (Agent-to-Agent) protocol v0.3.0 โ€” bidirectional agent communication gateway

Homepage GitHub

Install

npm install --production

README

# OpenClaw A2A Gateway Plugin

An [OpenClaw](https://github.com/openclaw/openclaw) plugin that implements the [A2A (Agent-to-Agent) v0.3.0 protocol](https://github.com/google/A2A), enabling OpenClaw agents to communicate with each other across different servers.

## What It Does

- Exposes an **A2A-compliant endpoint** (JSON-RPC + REST) so other agents can send messages to your OpenClaw agent
- Publishes an **Agent Card** at `/.well-known/agent-card.json` for peer discovery (legacy alias: `/.well-known/agent.json`)
- Supports **bearer token authentication** for secure inter-agent communication
- Routes inbound A2A messages to your OpenClaw agent and returns the response
- Allows your agent to **call peer agents** via the A2A protocol

## Architecture

```
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         A2A/JSON-RPC          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    OpenClaw Server A  โ”‚ โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚    OpenClaw Server B  โ”‚
โ”‚                       โ”‚      (Tailscale / LAN)       โ”‚                       โ”‚
โ”‚  Agent: AGI           โ”‚                               โ”‚  Agent: Coco          โ”‚
โ”‚  A2A Port: 18800      โ”‚                               โ”‚  A2A Port: 18800      โ”‚
โ”‚  Peer: Server-B       โ”‚                               โ”‚  Peer: Server-A       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```

## Prerequisites

- **OpenClaw** โ‰ฅ 2026.3.0 installed and running
- **Network connectivity** between servers (Tailscale, LAN, or public IP)
- **Node.js** โ‰ฅ 22

## Installation

### 1. Clone the plugin

```bash
# Into your workspace plugins directory
mkdir -p ~/.openclaw/workspace/plugins
cd ~/.openclaw/workspace/plugins
git clone https://github.com/win4r/openclaw-a2a-gateway.git a2a-gateway
cd a2a-gateway
npm install --production
```

### 2. Register the plugin in OpenClaw

```bash
# Add to allowed plugins list
openclaw config set plugins.allow '["telegram", "a2a-gateway"]'

# Tell OpenClaw where to find the plugin
openclaw config set plugins.load.paths '["<FULL_PATH_TO>/plugins/a2a-gateway"]'

# Enable the plugin
openclaw config set plugins.entries.a2a-gateway.enabled true
```

> **Note:** Replace `<FULL_PATH_TO>` with the actual absolute path, e.g., `/home/ubuntu/.openclaw/workspace/plugins/a2a-gateway`. Keep any existing plugins in the `plugins.allow` array.

### 3. Configure the Agent Card

Every A2A agent needs an Agent Card that describes itself:

```bash
openclaw config set plugins.entries.a2a-gateway.config.agentCard.name 'My Agent'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.description 'My OpenClaw A2A Agent'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.url 'http://<YOUR_IP>:18800/a2a/jsonrpc'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.skills '[{"id":"chat","name":"chat","description":"Bridge chat/messages to OpenClaw agents"}]'
```

> **Important:** Replace `<YOUR_IP>` with the IP address reachable by your peers (Tailscale IP, LAN IP, or public IP).

### 4. Configure the A2A server

```bash
openclaw config set plugins.entries.a2a-gateway.config.server.host '0.0.0.0'
openclaw config set plugins.entries.a2a-gateway.config.server.port 18800
```

### 5. Configure security (recommended)

Generate a token for inbound authentication:

```bash
TOKEN=$(openssl rand -hex 24)
echo "Your A2A token: $TOKEN"

openclaw config set plugins.entries.a2a-gateway.config.security.inboundAuth 'bearer'
openclaw config set plugins.entries.a2a-gateway.config.security.token "$TOKEN"
```

> Save this token โ€” peers will need it to authenticate with your agent.

### 6. Configure agent routing

```bash
openclaw config set plugins.entries.a2a-gateway.config.routing.defaultAgentId 'main'
```

### 7. Restart the gateway

```bash
openclaw gateway restart
```

### 8. Verify

```bash
# Check the Agent Card is accessible
curl -s http://localhost:18800/.well-known/agent-card.json | python3 -m json.tool
```

You should see your Agent Card with name, skills, and URL.

## Adding Peers

To communicate with another A2A agent, add it as a peer:

```bash
openclaw config set plugins.entries.a2a-gateway.config.peers '[
  {
    "name": "PeerName",
    "agentCardUrl": "http://<PEER_IP>:18800/.well-known/agent-card.json",
    "auth": {
      "type": "bearer",
      "token": "<PEER_TOKEN>"
    }
  }
]'
```

Then restart:

```bash
openclaw gateway restart
```

### Mutual Peering (Both Directions)

For two-way communication, **both servers** need to add each other as peers:

| Server A | Server B |
|----------|----------|
| Peer: Server-B (with B's token) | Peer: Server-A (with A's token) |

Each server generates its own security token and shares it with the other.

## Sending Messages via A2A

### From the command line

```bash
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
  --peer-url http://<PEER_IP>:18800 \
  --token <PEER_TOKEN> \
  --message "Hello from Server A!"
```

The script uses `@a2a-js/sdk` ClientFactory to auto-discover the Agent Card and select the best transport.

### Async task mode (recommended for long-running prompts)

For long prompts or multi-round discussions, avoid blocking a single request. Use non-blocking mode + polling:

```bash
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
  --peer-url http://<PEER_IP>:18800 \
  --token <PEER_TOKEN> \
  --non-blocking \
  --wait \
  --timeout-ms 600000 \
  --poll-ms 1000 \
  --message "Discuss A2A advantages in 3 rounds and provide final conclusion"
```

This sends `configuration.blocking=false` and then polls `tasks/get` until the task reaches a terminal state.

Tip: the default `--timeout-ms` for the script is 10 minutes; override it for very long tasks.

### Target a specific OpenClaw agentId (OpenClaw extension)

By default, the peer routes inbound A2A messages to `routing.defaultAgentId` (often `main`).

To route a single request to a specific OpenClaw `agentId` on the peer, pass `--agent-id`:

```bash
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
  --peer-url http://<PEER_IP>:18800 \
  --token <PEER_TOKEN> \
  --agent-id coder \
  --message "Run a health check"
```

This is implemented as a non-standard `message.agentId` field understood by this plugin. It is most reliable over JSON-RPC/REST. gRPC transport may drop unknown Message fields.

### Agent-side runtime awareness (TOOLS.md)

Even if the plugin is installed and configured, an LLM agent will not reliably "infer" how to call A2A peers (peer URL, token, command to run). For dependable **outbound** A2A calls, you should add an A2A section to the agent's `TOOLS.md`.

Add this to your agent's `TOOLS.md` so it knows how to call peers (see `skill/references/tools-md-template.md` for the full template):

```markdown
## A2A Gateway (Agent-to-Agent Communication)

You have an A2A Gateway plugin running on port 18800.

### Peers

| Peer | IP | Auth Token |
|------|-----|------------|
| PeerName | <PEER_IP> | <PEER_TOKEN> |

### How to send a message to a peer

Use the exec tool to run:

\```bash
node <PLUGIN_PATH>/skill/scripts/a2a-send.mjs \
  --peer-url http://<PEER_IP>:18800 \
  --token <PEER_TOKEN> \
  --message "YOUR MESSAGE HERE"

# Optional (OpenClaw extension): route to a specific peer agentId
#  --agent-id coder
\```

The script auto-discovers the Agent Card, handles auth, and prints the peer's response text.
```

Then users can say things like:
- "Send to PeerName: what's your status?"
- "Ask PeerName to run a health check"

## Network Setup

### Option A: Tailscale (Recommended)

[Tailscale](https://tailscale.com/) creates a secure mesh network between your servers with zero firewall configuration.

```bash
# Install on both servers
curl -fsSL https://tailscale.com/install.sh | sh

# Authenticate (same account on both)
sudo tailscale up

# Check connectivity
tailscale status
# You'll see IPs like 100.x.x.x for each machine

# Verify
ping <OTHER_SERVER_TAILSCALE_IP>
```

Use the `100.x.x.x` Tailscale IPs in your A2A configuration. Traffic is encrypted end-to-end.

### Option B: LAN

If both servers are on the same local network, use their LAN IPs directly. Make sure port 18800 is accessible.

### Option C: Public IP

Use public IPs with bearer token authentication. Consider adding firewall rules to restrict access to known IPs.

## Full Example: Two-Server Setup

### Server A setup

```bash
# Generate Server A's token
A_TOKEN=$(openssl rand -hex 24)
echo "Server A token: $A_TOKEN"

# Configure A2A
openclaw config set plugins.entries.a2a-gateway.config.agentCard.name 'Server-A'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.url 'http://100.10.10.1:18800/a2a/jsonrpc'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.skills '[{"id":"chat","name":"chat","description":"Chat bridge"}]'
openclaw config set plugins.entries.a2a-gateway.config.server.host '0.0.0.0'
openclaw config set plugins.entries.a2a-gateway.config.server.port 18800
openclaw config set plugins.entries.a2a-gateway.config.security.inboundAuth 'bearer'
openclaw config set plugins.entries.a2a-gateway.config.security.token "$A_TOKEN"
openclaw config set plugins.entries.a2a-gateway.config.routing.defaultAgentId 'main'

# Add Server B as peer (use B's token)
openclaw config set plugins.entries.a2a-gateway.config.peers '[{"name":"Server-B","agentCardUrl":"http://100.10.10.2:18800/.well-known/agent-card.json","auth":{"type":"bearer","token":"<B_TOKEN>"}}]'

openclaw gateway restart
```

### Server B setup

```bash
# Generate Server B's token
B_TOKEN=$(openssl rand -hex 24)
echo "Server B token: $B_TOKEN"

# Configure A2A
openclaw config set plugins.entries.a2a-gateway.config.agentCard.name 'Server-B'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.url 'http://100.10.10.2:18800/a2a/jsonrpc'
openclaw config set plugins.entries.a2a-gateway.config.agentCard.skills '[{"id":"chat","name":"chat","description":"Chat bridge"}]'
openclaw config set plugins.entries.a2a-gateway.config.server.host '0.0.0.0'
openclaw config set plugins.entries.a2a-gateway.co

... (truncated)
tools

Comments

Sign in to leave a comment

Loading comments...