a2a-gateway-mcp

An MCP server that bridges the Model Context Protocol and the Agent-to-Agent (A2A) protocol, enabling LLMs and MCP clients to discover, connect to, and communicate with remote A2A agents.
Overview
a2a-gateway-mcp provides two main packages:
gateway — An MCP server library that exposes 7 tools for managing and communicating with A2A agents through an ephemeral, session-scoped registry.
directory — A server-side agent directory service that stores agent cards and serves them over HTTP, acting as the counterpart to the gateway's discover_agents tool.
The project also ships a standalone CLI binary that runs the gateway on stdio transport, ready to plug into any MCP-compatible client.
Installation
go install github.com/nisimpson/a2a-gateway-mcp/cmd/a2a-gateway-mcp@latest
Or add the library to your project:
go get github.com/nisimpson/a2a-gateway-mcp
Quick Start
As a standalone MCP server
# Run with defaults
a2a-gateway-mcp
# Configure via environment variables
A2A_GATEWAY_NAME=my-gateway A2A_GATEWAY_VERSION=1.0.0 a2a-gateway-mcp
The server communicates over stdio using JSON-RPC, making it compatible with any MCP client (Claude Desktop, Cursor, Kiro, etc.).
MCP client configuration
Add to your MCP client config (e.g., mcp.json):
{
"mcpServers": {
"a2a-gateway": {
"command": "a2a-gateway-mcp",
"env": {
"A2A_GATEWAY_NAME": "my-gateway"
}
}
}
}
As a Go library
package main
import (
"context"
"log"
"github.com/nisimpson/a2a-gateway-mcp/gateway"
)
func main() {
srv := gateway.NewServer(
gateway.WithName("my-gateway"),
gateway.WithVersion("1.0.0"),
)
if err := srv.Run(context.Background()); err != nil {
log.Fatal(err)
}
}
The gateway exposes 7 tools to MCP clients:
| Tool |
Description |
connect_agent |
Register a remote A2A agent with a friendly alias |
disconnect_agent |
Remove a registered agent by alias |
list_agents |
List all connected agents with their aliases and URLs |
get_agent_card |
Retrieve an agent's capabilities from its card endpoint |
send_message |
Send a text message to an agent by alias or URL |
broadcast_message |
Send the same message to multiple agents concurrently |
discover_agents |
Query a remote agent directory for available agents |
connect_agent
Register an A2A agent with an alias for easy reference:
{
"alias": "code-reviewer",
"agent_url": "https://agent.example.com",
"headers": {
"Authorization": "Bearer token123"
}
}
send_message
Send a message to a connected agent:
{
"agent": "code-reviewer",
"message": "Review this pull request for security issues"
}
The gateway manages conversation context automatically — subsequent messages to the same agent continue the conversation.
broadcast_message
Fan out a message to multiple agents simultaneously:
{
"aliases": ["code-reviewer", "summarizer", "translator"],
"message": "Analyze this document",
"timeout_seconds": 60
}
Returns per-agent results with success/error status for each.
discover_agents
Query an agent directory service:
{
"directory_url": "https://directory.example.com/agents",
"query": "code review",
"limit": 5
}
Agent Directory
The directory package provides the server-side counterpart — an HTTP service that discover_agents connects to.
Standalone directory server
package main
import (
"context"
"log"
"github.com/a2aproject/a2a-go/v2/a2a"
"github.com/nisimpson/a2a-gateway-mcp/directory"
)
func main() {
dir := directory.New()
ctx := context.Background()
dir.Register(ctx, a2a.AgentCard{
Name: "code-reviewer",
Description: "Reviews code for bugs and style issues",
Skills: []a2a.AgentSkill{
{ID: "review", Name: "Code Review", Tags: []string{"code", "review"}},
},
})
log.Fatal(dir.ListenAndServe(ctx, ":8080"))
}
Embedded in an existing server
mux := http.NewServeMux()
mux.Handle("/agents", dir)
http.ListenAndServe(":8080", mux)
HTTP API
GET /agents?filter=code&limit=10
Returns a JSON array of matching agent cards. Supports:
filter — Case-insensitive substring search on name, description, and skill tags
limit — Cap the number of results returned
Custom backends
The directory uses a pluggable Registry interface, defaulting to an in-memory store:
dir := directory.New(
directory.WithRegistry(myRedisRegistry),
directory.WithFilterResolver(myElasticSearchResolver),
)
Registries that support native querying can implement the optional Filterer interface to push filtering down to the storage layer.
Architecture
graph TD
subgraph MCP Client
C[LLM / IDE / MCP Client]
end
subgraph Gateway Server
S[MCP Server - stdio transport]
R[Agent Registry]
CS[Context Store]
HC[HTTP Client]
end
subgraph Remote Agents
A1[A2A Agent 1]
A2[A2A Agent 2]
end
subgraph Directory
D[Agent Directory Service]
end
C <-->|JSON-RPC over stdio| S
S --> R
S --> CS
S --> HC
HC -->|HTTP + per-agent headers| A1
HC -->|HTTP + per-agent headers| A2
HC -->|GET ?filter=...&limit=...| D
Configuration
Environment Variables
| Variable |
Default |
Description |
A2A_GATEWAY_NAME |
a2a-gateway-mcp |
MCP server name |
A2A_GATEWAY_VERSION |
0.1.0 |
MCP server version |
Functional Options
gateway.NewServer(
gateway.WithName("custom-name"),
gateway.WithVersion("2.0.0"),
gateway.WithHTTPClient(customClient),
)
Development
See DEVELOPMENT.md for build instructions, testing, and project structure.
License
See LICENSE for details.