npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

claude-a2a-cli

v0.1.4

Published

A2A-compatible server wrapping the Claude CLI for agent-to-agent communication

Readme

claude-a2a

An A2A-compatible server that wraps the Claude Code CLI, enabling any A2A client to send messages to Claude agents on a machine and receive responses. Supports multimodal input (images, PDFs), session continuity, multi-agent configurations, and cost tracking. Also includes an MCP client so that interactive Claude Code sessions can natively call remote agents.

What problem does this solve?

Claude Code agents running on different machines have no built-in way to communicate with each other. There is no push mechanism in MCP, no way to inject messages into an active Claude Code session, and no standard protocol for bridging separate Claude instances.

claude-a2a solves this by exposing the local claude CLI as a network service using the A2A protocol. Any machine that can reach the server over HTTP can send messages to Claude and get responses back, complete with session continuity, cost tracking, and access controls.

Protocols

claude-a2a implements two protocols:

A2A (Agent-to-Agent)

A2A is Google's open protocol for communication between AI agents. It defines how agents discover each other (via Agent Cards), exchange messages, and track tasks. claude-a2a implements A2A v0.3.0 using the official @a2a-js/sdk.

The server exposes both JSON-RPC and REST transports:

  • POST /a2a/jsonrpc — A2A JSON-RPC 2.0 endpoint
  • /a2a/rest/v1/... — A2A REST endpoints
  • GET /.well-known/agent-card.json — Agent Card for discovery

MCP (Model Context Protocol)

MCP is Anthropic's protocol for giving AI models access to tools and data. The included MCP client runs as a stdio server that Claude Code can connect to, giving an interactive Claude session tools to call remote claude-a2a servers.

How it works

Remote Agent / A2A Client
        |
        | A2A Protocol (HTTP)
        v
+------------------+
|    claude-a2a    |   Express + @a2a-js/sdk
|                  |
|  Agent Card      |   /.well-known/agent-card.json
|  Auth layer      |   Master key / JWT tokens
|  Rate limiter    |
|  Budget tracker  |
|  Claude Session  |   Long-lived claude CLI process (stream-json NDJSON I/O)
+------------------+
        |
        v
   Claude CLI (local)

The server spawns a long-lived Claude CLI process per session using --input-format stream-json --output-format stream-json. Messages are sent as NDJSON on stdin and results are read from stdout. Session continuity is maintained by keeping the process alive across messages, with --resume for recovery after restarts.

| A2A Concept | claude-a2a Implementation | |---|---| | Agent Card | Describes each configured Claude agent | | Message (user) | Written to Claude process stdin as NDJSON | | Message (agent) | Parsed from Claude process stdout result | | Task context | Maps to a long-lived Claude CLI session | | Skills | Agent configurations (tools, model, description) |

Each response includes Claude-specific metadata (session ID, token usage, cost, model used) in the message's metadata.claude field.

Multimodal input

claude-a2a supports sending images, PDFs, and structured data to Claude via A2A's FilePart and DataPart message types:

| A2A Part Type | Claude Content Block | |---|---| | TextPart | Plain text (or { type: "text" } block) | | FilePart (image MIME + base64) | { type: "image", source: { type: "base64" } } | | FilePart (PDF/other MIME + base64) | { type: "document", source: { type: "base64" } } | | FilePart (URI) | Text description (URI download not supported) | | DataPart | JSON stringified as text |

Text-only messages are sent as plain strings for backward compatibility. When non-text parts are present, the message is sent as a ContentBlock[] array.

Supported input MIME types are advertised in the Agent Card's defaultInputModes: text, image/png, image/jpeg, image/gif, image/webp, application/pdf.

Installation

# Use directly with npx (no install needed)
CLAUDE_A2A_MASTER_KEY=my-secret-key npx claude-a2a-cli serve --agent my-agent

# Or install globally
npm install -g claude-a2a-cli
CLAUDE_A2A_MASTER_KEY=my-secret-key claude-a2a serve --agent my-agent

Requirements

  • Node.js >= 18 (tested with 24)
  • Claude Code CLI installed and authenticated (claude command available in PATH)

Quick start

Option A: npx (no clone required)

# Scaffold a config in the current directory
npx claude-a2a-cli init --yes

# Start the server
CLAUDE_A2A_MASTER_KEY=my-secret-key npx claude-a2a-cli serve

Option B: Single-agent mode (no config file at all)

# Start a single agent directly from CLI flags
CLAUDE_A2A_MASTER_KEY=my-secret-key npx claude-a2a-cli serve \
  --agent my-agent \
  --work-dir ./my-project \
  --model claude-sonnet-4-6 \
  --max-budget 5.0

Option C: Clone and build

cd claude-a2a
npm install
npm run build

# Start with a master key for auth
CLAUDE_A2A_MASTER_KEY=my-secret-key ./dist/cli.js serve

Verify it works

# Check health
curl http://localhost:8462/health

# View the agent card
curl http://localhost:8462/.well-known/agent-card.json

# Send a message
curl -X POST http://localhost:8462/a2a/jsonrpc \
  -H "Authorization: Bearer my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "message/send",
    "params": {
      "message": {
        "kind": "message",
        "messageId": "msg-1",
        "role": "user",
        "parts": [{"kind": "text", "text": "What is 2+2?"}]
      },
      "configuration": {"blocking": true}
    }
  }'

Note: If running from within a Claude Code session, the CLAUDECODE environment variable will cause spawned Claude processes to exit immediately. Start the server in a separate terminal or use env -u CLAUDECODE -u CLAUDE_CODE_ENTRYPOINT to unset it.

Configuration

There are three ways to configure the server:

1. init command (recommended for new projects)

claude-a2a init              # interactive prompts
claude-a2a init --yes        # non-interactive with defaults
claude-a2a init --yes -d ./my-project  # specify target directory

This scaffolds a config.yaml and a .claude/settings.json with tool permissions.

2. Single-agent CLI flags (no config file)

claude-a2a serve --agent <name> [options]

| Flag | Description | |---|---| | --agent <name> | Agent name (enables single-agent mode) | | --work-dir <path> | Agent working directory | | --model <model> | Claude model (e.g. claude-sonnet-4-6) | | --permission-mode <mode> | Permission mode (default: default) | | --system-prompt <text> | System prompt | | --max-budget <usd> | Max budget per invocation in USD |

When --agent is set, the server skips config file lookup entirely. Data is stored in ./data by default.

3. YAML config file

The server looks for a config file in this order:

  1. Path passed via --config / -c flag
  2. ./config.yaml in the current directory
  3. /etc/claude-a2a/config.yaml

If no file is found, sensible defaults are used. Copy config/example.yaml to get started:

cp config/example.yaml config.yaml

Environment variables

Secrets should be set via environment variables rather than in the config file:

| Variable | Purpose | |---|---| | CLAUDE_A2A_MASTER_KEY | Master authentication key (full access) | | CLAUDE_A2A_JWT_SECRET | Secret for signing/verifying JWT tokens | | CLAUDE_A2A_PORT | Override server port (default: 8462) | | CLAUDE_A2A_DATA_DIR | Override data directory (default: /var/lib/claude-a2a or ./data in single-agent mode) | | CLAUDE_A2A_CONFIG | Override config file path | | LOG_LEVEL | Logging level: debug, info, warn, error (default: info) |

Key config sections

server — Host, port, TLS, max concurrent Claude processes, request timeout, max body size (default 10mb to support base64-encoded files).

auth — Master key and JWT settings. If neither is configured, the server allows unauthenticated access.

rate_limiting — Token-bucket rate limiter. Per-client, configurable requests per minute and burst.

budgets — Daily spending limits (global and per-client) to prevent runaway costs.

sessions — Max session lifetime, idle timeout, and per-client session limits.

claude — Path to the claude binary, default model, default permission mode, and working directory.

agents — The most important section. This is where you define your agents.

Agents

In the A2A protocol, an Agent Card is a JSON document that describes what an agent can do. It is served at a well-known URL (/.well-known/agent-card.json) so that other agents and tools can discover and understand the agent's capabilities before sending it messages.

claude-a2a automatically generates an Agent Card from the agents section of your config. Each entry in agents becomes a skill on the card.

Defining agents

Each agent is a named configuration that controls how Claude behaves when it receives messages for that agent. Here is a full example:

agents:
  general:
    description: "General-purpose Claude assistant"
    enabled: true
    model: null                  # null = use Claude's default model
    append_system_prompt: "You are responding via the claude-a2a A2A API. Be concise."
    settings_file: null          # path to a Claude Code settings.json file
    permission_mode: "default"   # Claude's permission mode
    allowed_tools: []            # passed as --allowedTools to the CLI
    max_budget_usd: 1.0          # max spend per invocation
    required_scopes:             # JWT scopes needed to use this agent
      - "agent:general"
    work_dir: null               # working directory (null = use global default)

Agent config fields

| Field | Description | |---|---| | description | Human-readable description. Appears in the Agent Card. | | enabled | Set to false to disable an agent without removing its config. | | model | Claude model to use (e.g. claude-sonnet-4-6). null uses the CLI default. | | append_system_prompt | Extra instructions appended to Claude's system prompt for this agent. | | settings_file | Path to a Claude Code settings JSON file. Required for granting tool permissions in headless mode. See Permissions. | | permission_mode | Claude's permission mode. See Permissions. | | allowed_tools | List of tools passed as --allowedTools to the CLI (e.g. ["Bash(git:*)"]). | | max_budget_usd | Maximum spend (in USD) per single invocation. | | required_scopes | JWT scopes required to call this agent. Ignored for master key auth. | | work_dir | Working directory for Claude. Determines what files Claude can see. |

Example: multiple agents

agents:
  general:
    description: "General-purpose assistant for questions and research"
    enabled: true
    max_budget_usd: 0.50
    required_scopes: ["agent:general"]

  code:
    description: "Code assistant that can read, write, and run code"
    enabled: true
    model: "claude-sonnet-4-6"
    append_system_prompt: "You are a code assistant. Focus on writing clean, correct code."
    settings_file: "/home/projects/my-app/.claude/settings.json"
    permission_mode: "default"
    max_budget_usd: 5.0
    required_scopes: ["agent:code"]
    work_dir: "/home/projects/my-app"

  reviewer:
    description: "Code reviewer that reads code and provides feedback"
    enabled: true
    max_budget_usd: 1.0
    required_scopes: ["agent:reviewer"]
    work_dir: "/home/projects/my-app"

Clients target a specific agent by including "metadata": {"agent": "code"} in their message. If no agent is specified, the first enabled agent is used.

Viewing the Agent Card

Once the server is running, view the generated Agent Card:

curl http://localhost:8462/.well-known/agent-card.json

This returns the full A2A Agent Card JSON, including all enabled agents as skills, supported authentication schemes, and capability declarations.

Permissions

Claude CLI's permission system controls which tools the agent can use. This is critical for headless (non-interactive) operation because there is no human to approve permission prompts.

Permission modes

The permission_mode field maps to --permission-mode on the CLI:

| Mode | Behavior | |---|---| | default | Auto-approves reads. Writes and Bash require explicit allow rules in a settings file. Recommended for headless use. | | acceptEdits | Auto-approves file reads and writes within the project directory. Blocks Bash. | | plan | Enters planning workflow — not suitable for headless use. | | dontAsk | Denies all tool use that would normally prompt. | | bypassPermissions | Allows everything. Cannot be used when running as root. |

Settings file (recommended approach)

The most reliable way to grant permissions for headless operation is via a Claude Code settings file. Set settings_file in the agent config to point at it, and use permission_mode: "default":

{
  "permissions": {
    "allow": [
      "Read",
      "Edit",
      "Glob",
      "Grep",
      "Write"
    ]
  }
}

Place this file at <work_dir>/.claude/settings.json and reference it from the agent config:

agents:
  myagent:
    work_dir: "/home/projects/my-app"
    settings_file: "/home/projects/my-app/.claude/settings.json"
    permission_mode: "default"

The settings file allow rules grant tool access that would otherwise require interactive approval. Without a settings file, most tools will be denied in headless mode.

Path patterns: In settings files, /path is relative to the settings file. Use //path for absolute filesystem paths (e.g. Write(//tmp/**)). Note that some system paths like /tmp may require blanket tool allow ("Write") rather than path-scoped rules.

Running as root

bypassPermissions mode is blocked when running as root for security. Use default mode with a settings file instead.

Authentication

claude-a2a supports three tiers of authentication:

1. Master key

A shared secret that grants full access. Set via the CLAUDE_A2A_MASTER_KEY environment variable. Pass it as a Bearer token:

curl -H "Authorization: Bearer my-secret-key" http://localhost:8462/admin/stats

Best for: trusted agents on the same network or VPN.

2. JWT tokens

Scoped tokens with per-client controls. Generate them using the CLI:

# Generate a token for "my-agent" with access to the "general" agent
CLAUDE_A2A_JWT_SECRET=your-jwt-secret \
  npx claude-a2a-cli token my-agent agent:general

# Generate a token with access to all agents
CLAUDE_A2A_JWT_SECRET=your-jwt-secret \
  npx claude-a2a-cli token my-agent '*'

JWT claims can include:

  • scopes — which agents the token can access (e.g. agent:general, agent:code, or *)
  • budget_daily_usd — per-client daily spending limit
  • rate_limit_rpm — per-client rate limit override

3. No authentication

If neither CLAUDE_A2A_MASTER_KEY nor CLAUDE_A2A_JWT_SECRET is set, the server allows unauthenticated access. Only appropriate for local development.

Session continuity

claude-a2a maintains session continuity across messages using A2A's contextId. When you send a first message, the response includes a contextId. Include that same contextId in subsequent messages to continue the conversation in the same Claude session:

# First message — note the contextId in the response
RESPONSE=$(curl -s -X POST http://localhost:8462/a2a/jsonrpc \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0", "id": "1",
    "method": "message/send",
    "params": {
      "message": {
        "kind": "message", "messageId": "m1", "role": "user",
        "parts": [{"kind": "text", "text": "Remember the number 42."}]
      },
      "configuration": {"blocking": true}
    }
  }')

# Extract contextId from response
CONTEXT_ID=$(echo "$RESPONSE" | jq -r '.result.contextId')

# Second message — same contextId, Claude remembers the conversation
curl -s -X POST http://localhost:8462/a2a/jsonrpc \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\", \"id\": \"2\",
    \"method\": \"message/send\",
    \"params\": {
      \"message\": {
        \"kind\": \"message\", \"messageId\": \"m2\", \"role\": \"user\",
        \"contextId\": \"$CONTEXT_ID\",
        \"parts\": [{\"kind\": \"text\", \"text\": \"What number did I say?\"}]
      },
      \"configuration\": {\"blocking\": true}
    }
  }"

Under the hood, claude-a2a keeps a long-lived Claude CLI process per session. If the process dies (e.g. server restart), it respawns with --resume <session-id> to recover the conversation.

MCP client (for interactive Claude Code sessions)

The included MCP client lets an interactive Claude Code session call remote claude-a2a servers as tools. This means a Claude agent on your laptop can ask a Claude agent on your server to do work.

Setup

  1. Create a client config file at ~/.claude-a2a/client.json:
{
  "servers": {
    "my-server": {
      "url": "http://192.168.1.80:8462",
      "token": "my-secret-key"
    }
  }
}
  1. Add the MCP server to your project's .mcp.json:
{
  "mcpServers": {
    "claude-a2a": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/claude-a2a/dist/client.js"]
    }
  }
}

Restart Claude Code after adding the MCP config.

Available MCP tools

Once connected, Claude Code gains these tools:

| Tool | Description | |---|---| | list_remote_servers | List configured remote servers | | list_remote_agents | Fetch the Agent Card from a remote server | | send_message | Send a message to a remote agent and get a response | | get_server_health | Check server health and status | | list_sessions | List active sessions (admin) | | delete_session | Clean up a remote session (admin) |

Admin API

Admin endpoints require master key authentication.

# Server stats
curl -H "Authorization: Bearer $MASTER_KEY" http://localhost:8462/admin/stats

# List active sessions
curl -H "Authorization: Bearer $MASTER_KEY" http://localhost:8462/admin/sessions

# Delete a session
curl -X DELETE -H "Authorization: Bearer $MASTER_KEY" \
  http://localhost:8462/admin/sessions/<session-id>

# Create a JWT token
curl -X POST -H "Authorization: Bearer $MASTER_KEY" \
  -H "Content-Type: application/json" \
  http://localhost:8462/admin/tokens \
  -d '{"sub": "my-client", "scopes": ["agent:general"]}'

# Revoke a token
curl -X DELETE -H "Authorization: Bearer $MASTER_KEY" \
  http://localhost:8462/admin/tokens/<token-jti>

Production deployment

A systemd service file is included for production deployment:

# Build
npm run build

# Run the install script (creates user, directories, copies files)
sudo bash scripts/install.sh

# Configure
sudo vim /etc/claude-a2a/config.yaml
sudo vim /etc/claude-a2a/env    # set CLAUDE_A2A_MASTER_KEY, CLAUDE_A2A_JWT_SECRET

# Start
sudo systemctl enable --now claude-a2a

# Check status
sudo systemctl status claude-a2a
curl http://localhost:8462/health

The systemd service runs with security hardening (read-only filesystem, no new privileges, restricted syscalls).

Development

# Run in dev mode (uses tsx, no build step)
CLAUDE_A2A_MASTER_KEY=dev-key npm run dev

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Lint
npm run lint

# Build
npm run build

Project structure

claude-a2a/
  src/
    cli.ts                        # CLI entry point (serve, init, client, token)
    init.ts                       # Interactive config scaffolding
    version.ts                    # Version constant
    server/
      index.ts                    # Express server setup, wires everything together
      config.ts                   # YAML config loading + Zod validation
      agent-card.ts               # Generates A2A Agent Card from config
      claude-session.ts           # Long-lived Claude CLI process wrapper (NDJSON I/O)
      claude-runner.ts            # Session pool manager
      agent-executor.ts           # A2A executor: bridges A2A protocol to Claude Runner
      auth/
        middleware.ts             # Express auth middleware (master key + JWT)
        tokens.ts                 # JWT creation, verification, revocation
        user.ts                   # User context type
      services/
        database.ts               # SQLite connection with migrations
        session-store.ts          # Tracks Claude sessions by context ID
        task-store.ts             # A2A task persistence with tenant isolation
        rate-limiter.ts           # Token-bucket rate limiter
        budget-tracker.ts         # Daily per-client and global cost tracking
      routes/
        admin.ts                  # Token CRUD, session management, stats
        health.ts                 # Health check endpoint
    client/
      index.ts                    # MCP client entry point
      mcp-server.ts               # MCP tool definitions
      a2a-client.ts               # HTTP client for remote A2A servers
      config.ts                   # Client config loading
  tests/                          # Vitest unit tests
  config/
    example.yaml                  # Example server configuration
  systemd/
    claude-a2a.service            # systemd unit file
  scripts/
    install.sh                    # Production install script

Response metadata

Every response from claude-a2a includes Claude-specific metadata in result.metadata.claude:

{
  "claude": {
    "agent": "general",
    "session_id": "7fcfc468-2111-4fc2-97ad-bcb4d91ce0c8",
    "context": null,
    "cost_usd": 0.014664,
    "duration_ms": 1932,
    "duration_api_ms": 1859,
    "permission_denials": [],
    "model_used": "claude-sonnet-4-6",
    "num_turns": 1,
    "usage": {
      "input_tokens": 3,
      "output_tokens": 5,
      "cache_creation_input_tokens": 816,
      "cache_read_input_tokens": 18848
    }
  }
}

This lets clients track costs, monitor token usage, detect permission issues, and manage session state.

Built with