Skip to content

Repository files navigation

OpenClaw A2A Plugin

OpenClaw A2A Plugin

npm version License A2A Protocol Discord

OpenClaw A2A protocol community plugin. Send messages and files to other agents over the internet, and/or allow your agent to receive messages and files with Tailscale. The plugin is powered by A2A Utils, a comprehensive set of utility functions for using A2A servers (remote agents), that powers the A2A MCP Server.

The plugin gives your agent 6 tools to send messages and files to other agents without relying on a third-party chat app or email:

  • a2a_get_agents to list the agents it's connected to
  • a2a_get_agent to view an agent's skills in detail
  • a2a_send_message to send messages and files. The agent will respond with a context_id and task_id, which your agent can use to continue the conversation.
  • a2a_get_task to poll for a response if either agent loses connection or a response hasn't been recieved in over a minute
  • a2a_view_text_artifact to view large text responses that have been minimised
  • a2a_view_data_artifact to view large data responses that have been minimised

The plugin also allows your agent to receive messages and files with Tailscale and other reverse proxies (nginx, Caddy, etc). It's secure by default, requiring you to generate an API key (openclaw a2a generate-key <label>) for each agent you want to give access to. Your agent will see the sender (<label>), and each inbound message creates a separate conversation that is identified by the sender (<label>) and context_id. This way, your agent can support multiple conversations simulateneously, including from the same sender.

📺 Demo

Watch OpenClaw A2A Plugin Demo - Connect your OpenClaw to other OpenClaws (and agents) over the internet on YouTube.

📦 Installation

Install the plugin:

openclaw plugins install @a2anet/openclaw-a2a-plugin

Restart the gateway:

openclaw gateway restart

Follow the set up instructions in "📤 Sending Messages (outbound)" and/or "📥 Receiving Messages (inbound)".

💡 Use Cases

  • Connect your OpenClaw to a company-wide OpenClaw to ask questions, give updates, and access company accounts and services
  • Connect your OpenClaw to agents on A2A marketplaces to ehance OpenClaw's capabilities
  • Connect a sandboxed local OpenClaw to a full access cloud OpenClaw to efficiently share context and files
  • Connect your OpenClaw to a hackathon teammate's to sync code plans when vibe coding at the same time to avoid merge conflicts
  • Connect your OpenClaw to a classmate's or co-worker's to work together on a project
  • Connect your OpenClaw to a friend's to plan a fun day out based on what it knows about you

✨ Features

  • Send messages to remote agents — 6 outbound tools (a2a_get_agents, a2a_get_agent, a2a_send_message, a2a_get_task, a2a_view_text_artifact, a2a_view_data_artifact) for communicating with any A2A agent
  • Receive messages from remote agents — expose your OpenClaw agent as an A2A server with Agent Card discovery, JSON-RPC 2.0 endpoint, and SSE streaming
  • Host multiple agents — expose several agents from one gateway, each with its own /a2a/<agentId> endpoint, Agent Card discovery URL, and card metadata
  • Send and receive files — outbound messages can include local file paths (up to 1MB) or URLs; inbound files are saved locally
  • Multi-turn conversations — continue conversations across multiple messages using context_id
  • Long-running task support — if a2a_send_message times out, use a2a_get_task to monitor until the task reaches a terminal state
  • Automatic artifact minimization — large text and data artifacts are automatically minimized for LLM context windows, with dedicated tools for detailed navigation
  • Inbound authentication — API key-based auth with timing-safe HMAC-SHA256 comparison, per-key labels, and CLI key management
  • Live Agent Card updates — update your agent's name, description, and skills at runtime with a2a_update_agent_card without restarting
  • Tailscale integration — expose your agent to the internet via Tailscale Funnel, or restrict to your tailnet with Tailscale Serve
  • Custom headers and outbound auth — per-agent custom headers with ${ENV_VAR} substitution for secrets
  • Configurable timeouts and limits — control character limits, timeouts, poll intervals, and whether to enable task and file storage

🤖 A2A Core Concepts

The A2A protocol is a protocol for agent-to-agent communication supported by AWS, Azure, GCP, and 150+ enterprises.

  • Agent Card — A JSON object at a publicly available URL (e.g. /.well-known/agent-card.json) that describes an agent (name, description, skills, etc).
  • Message — a single communication turn between agents, containing one or more Parts. Each message has a role (user or agent).
  • Part — content within a Message, Task, or Artifact: text (TextPart), JSON data (DataPart), or files (FilePart).
  • Task — a unit of work with a unique ID. Useful for long-running tasks, agents can disconnect and poll intermittently.
  • Artifact — output produced by a task (e.g. generated text, JSON data, files).

📤 Sending Messages (outbound)

Set Up

Configure at least one remote agent in your OpenClaw config. You just need the remote agent's Agent Card URL (and API key, if required). No Tailscale or port exposure needed.

{
    "tools": {
        "profile": "full"
    },
    "plugins": {
        "entries": {
            "a2a": {
                "enabled": true,
                "config": {
                    "outbound": {
                        "agents": {
                            "weather": {
                                "url": "https://weather-agent.example.com/.well-known/agent-card.json"
                            },
                            "search": {
                                "url": "https://example.com/search-agent/agent-card.json",
                                "custom_headers": {
                                    "Authorization": "Bearer ${SEARCH_API_KEY}"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "sandbox": {
        "tools": {
            "alsoAllow": [
                "a2a_get_agents",
                "a2a_get_agent",
                "a2a_send_message",
                "a2a_get_task",
                "a2a_view_text_artifact",
                "a2a_view_data_artifact"
            ]
        }
    }
}

Note: Header values support ${ENV_VAR} substitution so you can keep secrets out of your config file. The "sandbox" section is only required if sandbox is enabled.

Field Type Default Description
agents Record<string, {url, custom_headers?}> Named remote agents. Keys are agent IDs used in tool calls.
taskStore boolean true Enable persistent task storage.
fileStore boolean true Enable persistent file artifact storage.
sendMessageCharacterLimit number 50000 Maximum characters for minimized artifact text.
minimizedObjectStringLength number 5000 Maximum string length for minimized data objects.
viewArtifactCharacterLimit number 50000 Maximum characters returned by view artifact tools.
agentCardTimeout number 15 Timeout in seconds for fetching remote agent cards.
sendMessageTimeout number 60 Timeout in seconds for send message requests.
getTaskTimeout number 60 Timeout in seconds for get task monitoring.
getTaskPollInterval number 5 Interval in seconds between task status polls.

Tools

The a2a_* tools are registered when at least one agent is configured (agents). The plugin is powered by A2A Utils, for example tool usage, results, etc. see A2A Utils JavaScript A2ATools.

a2a_get_agents

List all available remote A2A agents with names and descriptions.

No parameters.

a2a_get_agent

Get detailed info about a specific agent, including skills.

Parameter Type Required Description
agent_id string Yes The agent's unique identifier

a2a_send_message

Send a message to a remote agent and receive a structured response. The message is sent non-blocking — the tool streams or polls for updates until the task reaches a terminal state or the timeout is reached. If the task is still in progress after the timeout, the current task state is returned. Use a2a_get_task with the returned id to continue monitoring.

Parameter Type Required Description
agent_id string Yes ID of the target agent
message string Yes Message content to send
context_id string No Continue an existing multi-turn conversation
task_id string No Attach to an existing task (for input_required flows)
timeout number No Override default timeout in seconds
data array No Structured data to include with the message. Each item is sent as a separate JSON object or array alongside the text.
files array No Files to include with the message. Accepts local file paths (read and sent as binary, max 1MB) or URLs (sent as references for the remote agent to fetch).

a2a_get_task

Check the progress of an A2A task that is still in progress. Monitors until the task reaches a terminal state or the timeout is reached. If still in progress, returns the current task state — call again to continue monitoring.

Parameter Type Required Description
agent_id string Yes ID of the agent owning the task
task_id string Yes Task ID from a previous a2a_send_message
timeout number No Monitoring timeout in seconds
poll_interval number No Interval between status checks in seconds

a2a_view_text_artifact

View text content from an artifact, optionally selecting a line or character range. Can select by line range OR character range, but not both.

Parameter Type Required Description
agent_id string Yes ID of the agent that produced the artifact
task_id string Yes Task ID containing the artifact
artifact_id string Yes The artifact's unique identifier
line_start number No Starting line number (1-based, inclusive)
line_end number No Ending line number (1-based, inclusive)
character_start number No Starting character index (0-based, inclusive)
character_end number No Ending character index (0-based, exclusive)

a2a_view_data_artifact

View structured data from an artifact with optional JSON path, row, and column filtering.

Parameter Type Required Description
agent_id string Yes ID of the agent that produced the artifact
task_id string Yes Task ID containing the artifact
artifact_id string Yes The artifact's unique identifier
json_path string No Dot-separated path to navigate data (e.g. "results.items")
rows string No Row selection for list data ("0", "0-10", "0,2,5", or "all")
columns string No Column selection for tabular data ("name", "name,age", or "all")

📥 Receiving Messages (inbound)

Set Up

Other agents can discover and message your OpenClaw agent through the inbound endpoint. Follow the steps below to make your agent reachable.

1. Configure Inbound

{
    "tools": {
        "profile": "full"
    },
    "plugins": {
        "entries": {
            "a2a": {
                "enabled": true
            }
        }
    },
    "sandbox": {
        "tools": {
            "alsoAllow": ["a2a_update_agent_card"]
        }
    }
}

Note: The "sandbox" section is only required if sandbox is enabled.

Field Type Default Description
agentCard.name string Agent identity name Agent Card display name.
agentCard.description string "AI assistant powered by OpenClaw" Agent Card description.
agentCard.skills array [] Skills to advertise. Each needs id, name, description. Optional: tags, examples, inputModes, outputModes. Can also be set at runtime with a2a_update_agent_card.
apiKeys array Array of { label, key } objects for inbound auth.
allowUnauthenticated boolean false Skip API key validation for inbound requests.
agents object Named inbound agents, keyed by agent ID. Each value takes an agentCard (name, description, skills). See Hosting Multiple Agents.

Hosting Multiple Agents

A single gateway can expose several agents, each as its own addressable A2A endpoint. Add inbound.agents, keyed by agent ID. Each key is both the URL path segment and the OpenClaw agent ID that handles the message, so a message to /a2a/swe is routed to the OpenClaw agent swe. The key must match a configured OpenClaw agent ID, or requests to it will fail to route.

{
    "plugins": {
        "entries": {
            "a2a": {
                "enabled": true,
                "config": {
                    "inbound": {
                        "apiKeys": [{ "label": "flynn", "key": "..." }],
                        "agents": {
                            "swe": {
                                "agentCard": {
                                    "name": "SWE",
                                    "description": "Software engineering agent",
                                    "skills": [
                                        { "id": "code", "name": "Code", "description": "Writes and reviews code" }
                                    ]
                                }
                            },
                            "pmo": {
                                "agentCard": { "name": "PMO", "description": "Project management agent" }
                            }
                        }
                    }
                }
            }
        }
    }
}

Each agent gets its own JSON-RPC endpoint and Agent Card discovery URL:

Agent JSON-RPC endpoint Agent Card discovery URL
swe /a2a/swe /a2a/swe/agent-card.json
pmo /a2a/pmo /a2a/pmo/agent-card.json

The apiKeys / allowUnauthenticated settings apply to every agent on the host. Each agent can update its own card at runtime with a2a_update_agent_card — the edit is scoped to the calling agent and persisted under its inbound.agents.<agentId>.agentCard. When inbound.agents is omitted, a single agent is exposed on the default /a2a and /.well-known/agent-card.json paths, configured via inbound.agentCard.

2. Restart the Gateway

The plugin registers its HTTP endpoints on startup, so a restart is required:

openclaw gateway restart

3. Expose Your Gateway

You need to make your gateway's HTTP port (default 18789) reachable from the internet. Tailscale Funnel is the recommended approach — it gives your machine a public HTTPS URL with automatic TLS certificates, no port forwarding or DNS configuration needed. You can also use any reverse proxy (nginx, Caddy, etc.).

Note: The commands below were verified on macOS (Apple Silicon) with the Tailscale Mac app. The overall flow is the same on Linux and Windows, but the install and daemon setup will differ — consult the Tailscale install docs for your OS.

Install Tailscale

Install the Tailscale Mac app. The GUI app ships a Network Extension that plumbs MagicDNS into macOS's system resolver, so browsers and other apps can resolve your *.ts.net hostname.

After installing, launch the app, click the Tailscale menu bar icon, and sign in. The CLI is bundled with the app.

Confirm you're online:

tailscale status

You should see your node name, tailnet IP, and user.

Provision an HTTPS Certificate

Funnel needs a LetsEncrypt cert for your node's *.ts.net name. Running tailscale cert once provisions it and also confirms that HTTPS certificates and MagicDNS are enabled on your tailnet:

cd /tmp && tailscale cert "$(tailscale status --json | jq -r '.Self.DNSName | rtrimstr(".")')"

The cd /tmp is because tailscale cert writes <host>.crt and <host>.key to the current directory.

Enable Funnel
tailscale funnel --bg http://localhost:18789

On success, Tailscale prints the public URL, e.g.:

Available on the internet:

https://your-machine.tailXXXXXX.ts.net/
|-- proxy http://localhost:18789

If the funnel command fails with a policy error, you need to add the Funnel ACL attribute in the admin console (there is no CLI equivalent for editing ACLs):

"nodeAttrs": [
  {
    "target": ["autogroup:member"],
    "attr": ["funnel"]
  }
]

It can take up to a minute or two after tailscale funnel --bg returns before the public URL actually serves traffic from the open internet, because the Funnel edge has to propagate your config and finish TLS provisioning. If an external request returns a TLS error or "broken pipe", wait ~60s and retry.

Tailscale Serve (Tailnet-Only)

If you only need agents on your tailnet to reach you (not the public internet), use Tailscale Serve instead of Funnel:

tailscale serve --bg http://localhost:18789

With Serve, traffic is restricted to your tailnet, so disabling authentication is reasonable.

Stopping Funnel
tailscale funnel --https=443 off

4. Verify

Open your Agent Card URL in a browser:

https://your-machine.tail123.ts.net/.well-known/agent-card.json

You should see the JSON Agent Card (name, description, skills, etc.).

5. Generate an API Key

The Agent Card is public, but for other people to send messages to your OpenClaw you'll need to generate an API key for them:

openclaw a2a generate-key flynn

6. Customise Your Agent Card

The Agent Card will have default values. Once you've generated an API key, ask your OpenClaw to use the a2a_update_agent_card tool to update its Agent Card:

Update your Agent Card with the a2a_update_agent_card tool

7. Share Your URL and Key

Send your Agent Card URL and the generated API key to the person you generated it for. They'll need to install the plugin and add your OpenClaw as a remote agent with the headers:

"custom_headers": {
    "Authorization": "Bearer [GENERATED API KEY]"
}

That's it! Your friend's agent should now be able to send messages and files to your OpenClaw.

Tools

The a2a_update_agent_card tool is registered when inbound is configured (apiKeys or allowUnauthenticated).

a2a_update_agent_card

Live-update this agent's A2A Agent Card name, description, or skills. Changes take effect immediately and persist to config — no restart needed. At least one field must be provided. When inbound.agents is configured, the edit is scoped to the calling agent's own card.

Parameter Type Required Description
name string No Display name for the Agent Card
description string No Description for the Agent Card
skills array No Skills to advertise (objects with id, name, description, and optional tags/examples)

🌐 HTTP Endpoints

Endpoint Method Auth Description
/.well-known/agent-card.json GET No Returns the Agent Card for discovery (single-agent configuration)
/a2a POST Bearer token JSON-RPC 2.0 endpoint supporting message/send, message/stream, tasks/get, tasks/cancel
/a2a/<agentId>/agent-card.json GET No Returns the Agent Card for <agentId> (when inbound.agents is configured)
/a2a/<agentId> POST Bearer token JSON-RPC 2.0 endpoint for <agentId> (when inbound.agents is configured)

Supported JSON-RPC Methods

Method Description
message/send Send a message and wait for the full response
message/stream Send a message with Server-Sent Events (SSE) streaming
tasks/get Get the status and details of a task
tasks/cancel Cancel an ongoing task

Error Codes

Code Meaning
-32700 Parse error
-32600 Invalid request
-32601 Method not found
-32602 Invalid params
-32001 Authentication required
-32000 Server error

💾 Data Storage

Tasks and file artifacts are saved locally, separated by direction. Task state lives under OpenClaw's state directory; file artifacts live under OpenClaw's workspace directory so the agent can access received files.

Direction Type Path
Outbound Tasks <state>/a2a/outbound/tasks/
Outbound Files <workspace>/a2a/outbound/files/
Inbound Tasks <state>/a2a/inbound/tasks/
Inbound Files <workspace>/a2a/inbound/files/

When inbound.agents is configured, each agent's inbound tasks and files are isolated under its agent ID — <state>/a2a/inbound/<agentId>/tasks/ and <workspace>/a2a/inbound/<agentId>/files/.

Outbound task/file storage can be disabled with outbound.taskStore: false and outbound.fileStore: false.

🛠️ Development

Install the dependencies:

make install

Install git hooks:

make install-hooks

Install the plugin:

openclaw plugins install /absolute/path/to/openclaw-a2a-plugin

Restart the gateway:

openclaw gateway restart

📄 License

Apache-2.0

🤝 Join the A2A Net Community

A2A Net is a site to find and share AI agents and open-source community. Join to share your A2A agents, ask questions, stay up-to-date with the latest A2A news, be the first to hear about open-source releases, tutorials, and more!

About

OpenClaw A2A protocol community plugin. Send messages and files to other agents over the internet, and allow other people to connect to your agent with Tailscale

Resources

Stars

28 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages