You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: Add MCP-to-A2A bridge for protocol interoperability
This PR introduces a bridge that allows MCP (Model Context Protocol) servers to be exposed as A2A (Agent-to-Agent) compatible services, enabling seamless protocol interoperability between the two major agent communication standards.
## Implementation
### Core Components
- MCPBridgeExecutor: Translates A2A requests to MCP tool calls
- MCPToA2ABridgeConfig: Configuration for bridge settings
- serve_mcp_as_a2a_async: Main function to start the bridge server
### Features
- Full protocol translation between MCP and A2A
- Support for AGNTCY Identity (tracked internally, not exposed via A2A due to protocol limitations)
- Comprehensive error handling and logging
- Clean integration with existing any-agent patterns
- Zero custom rules or patterns - follows any-agent conventions exactly
### Documentation
- Added detailed section in docs/serving.md
- Created cookbook example (mcp_a2a_bridge.ipynb) with practical usage patterns
- Added bridge feature to README.md
- Complete example script in examples/mcp_a2a_bridge_demo.py
### Testing
- Integration tests covering basic bridge, identity support, and tool invocation
- Test for multiple concurrent bridges
- All tests properly handle the simplified single-tool bridge design
## Design Decisions
1. Single-tool bridges only - Keeps implementation simple and follows any-agent patterns
2. Identity support - Accepts AGNTCY Identity DIDs from mcpd but acknowledges A2A limitations
3. No custom patterns - Strictly follows existing any-agent conventions
4. Clean separation - Bridge is separate from native A2A serving implementation
## Usage Example
```python
from any_agent.config import MCPStdio
from any_agent.serving import MCPToA2ABridgeConfig, serve_mcp_as_a2a_async
# Configure MCP server
mcp_config = MCPStdio(
command="uvx",
args=["mcp-server-time"],
tools=["get_current_time"],
)
# Configure and start bridge
bridge_config = MCPToA2ABridgeConfig(
mcp_config=mcp_config,
port=8080,
endpoint="/time-bridge",
server_name="time-server",
)
bridge_handle = await serve_mcp_as_a2a_async(mcp_config, bridge_config)
```
This bridge enables Mozilla's any-agent to connect local MCP tools with Google's A2A ecosystem, providing a unified interface for agent communication across protocols.
Copy file name to clipboardExpand all lines: README.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -93,6 +93,7 @@ Get started quickly with these practical examples:
93
93
-**[Creating an agent with MCP](https://mozilla-ai.github.io/any-agent/cookbook/mcp_agent/)** - Integrate Model Context Protocol tools.
94
94
-**[Serve an Agent with A2A](https://mozilla-ai.github.io/any-agent/cookbook/serve_a2a/)** - Deploy agents with Agent-to-Agent communication.
95
95
-**[Building Multi-Agent Systems with A2A](https://mozilla-ai.github.io/any-agent/cookbook/a2a_as_tool/)** - Using an agent as a tool for another agent to interact with.
96
+
-**[Bridge MCP servers to A2A](https://mozilla-ai.github.io/any-agent/cookbook/mcp_a2a_bridge/)** - Expose MCP tools as A2A-compatible services for protocol interoperability.
"This cookbook demonstrates how to expose MCP (Model Context Protocol) servers as A2A-compatible services, enabling seamless interoperability between different agent ecosystems.\n",
10
+
"\n",
11
+
"## Why Bridge MCP to A2A?\n",
12
+
"\n",
13
+
"- **Protocol Interoperability**: Make MCP tools available to Google's A2A ecosystem\n",
14
+
"- **Enterprise Integration**: Connect local tools with enterprise agent systems\n",
15
+
"- **Identity Support**: Leverage AGNTCY Identity for secure tool access\n",
16
+
"- **Zero Changes**: MCP servers work as-is without modifications\n",
17
+
"\n",
18
+
"This tutorial assumes familiarity with both MCP and A2A. If you're new to these protocols:\n",
19
+
"- MCP: See [Creating an agent with MCP](./mcp_agent.ipynb)\n",
20
+
"- A2A: See [Serve an Agent with A2A](./serve_a2a.ipynb)"
21
+
]
22
+
},
23
+
{
24
+
"cell_type": "markdown",
25
+
"metadata": {},
26
+
"source": [
27
+
"## Install Dependencies\n",
28
+
"\n",
29
+
"You'll need both MCP and A2A support:"
30
+
]
31
+
},
32
+
{
33
+
"cell_type": "code",
34
+
"execution_count": null,
35
+
"metadata": {},
36
+
"outputs": [],
37
+
"source": [
38
+
"%pip install 'any-agent[mcp,a2a]'\n",
39
+
"\n",
40
+
"import nest_asyncio\n",
41
+
"nest_asyncio.apply()"
42
+
]
43
+
},
44
+
{
45
+
"cell_type": "code",
46
+
"execution_count": null,
47
+
"metadata": {},
48
+
"outputs": [],
49
+
"source": [
50
+
"import os\n",
51
+
"from getpass import getpass\n",
52
+
"\n",
53
+
"# This example uses Mistral models\n",
54
+
"if \"MISTRAL_API_KEY\" not in os.environ:\n",
55
+
" print(\"MISTRAL_API_KEY not found in environment!\")\n",
56
+
" api_key = getpass(\"Please enter your MISTRAL_API_KEY: \")\n",
57
+
" os.environ[\"MISTRAL_API_KEY\"] = api_key\n",
58
+
" print(\"MISTRAL_API_KEY set for this session!\")\n",
59
+
"else:\n",
60
+
" print(\"MISTRAL_API_KEY found in environment.\")"
61
+
]
62
+
},
63
+
{
64
+
"cell_type": "markdown",
65
+
"metadata": {},
66
+
"source": [
67
+
"## Basic Bridge: Single MCP Server\n",
68
+
"\n",
69
+
"Let's start by bridging a single MCP server (time server) to A2A:"
70
+
]
71
+
},
72
+
{
73
+
"cell_type": "code",
74
+
"metadata": {},
75
+
"outputs": [],
76
+
"source": "from any_agent.config import MCPStdio\nfrom any_agent.serving import (\n MCPToA2ABridgeConfig,\n serve_mcp_as_a2a_async,\n)\n\n# Configure MCP server\nmcp_config = MCPStdio(\n command=\"uvx\",\n args=[\"mcp-server-time\", \"--local-timezone=America/New_York\"],\n tools=[\"get_current_time\"],\n)\n\n# Configure bridge\nbridge_config = MCPToA2ABridgeConfig(\n mcp_config=mcp_config,\n port=0, # Use dynamic port\n endpoint=\"/time-bridge\",\n server_name=\"time-server\",\n)\n\n# Start the bridge\nbridge_handle = await serve_mcp_as_a2a_async(mcp_config, bridge_config)\nbridge_port = bridge_handle.port\n\nprint(f\"✓ MCP time server bridged to A2A at: http://localhost:{bridge_port}/time-bridge\")"
77
+
},
78
+
{
79
+
"cell_type": "markdown",
80
+
"metadata": {},
81
+
"source": [
82
+
"## Use the Bridged MCP Tool via A2A\n",
83
+
"\n",
84
+
"Now we can access the MCP tool through A2A protocol:"
85
+
]
86
+
},
87
+
{
88
+
"cell_type": "code",
89
+
"execution_count": null,
90
+
"metadata": {},
91
+
"outputs": [],
92
+
"source": [
93
+
"from any_agent import AgentConfig, AnyAgent\n",
94
+
"from any_agent.tools import a2a_tool_async\n",
95
+
"\n",
96
+
"# Create an A2A tool from the bridged MCP server\n",
"source": "## Advanced: Bridge with AGNTCY Identity\n\nIf you're using mcpd with AGNTCY Identity support, you can include identity information in the bridge configuration. While the identity won't be exposed through the A2A protocol (due to AgentCard limitations), it will be logged and can be used for internal tracking:",
122
+
"outputs": []
123
+
},
124
+
{
125
+
"cell_type": "code",
126
+
"metadata": {},
127
+
"outputs": [],
128
+
"source": "import json\nfrom pathlib import Path\n\n# Check if identity exists (from mcpd)\nidentity_path = Path(\"~/.config/mcpd/identity/time-server.json\").expanduser()\nidentity_id = None\n\nif identity_path.exists():\n with open(identity_path) as f:\n identity_data = json.load(f)\n identity_id = identity_data.get(\"id\")\n print(f\"Found identity: {identity_id}\")\nelse:\n print(\"No identity found - proceeding without identity\")\n\n# Create bridge with identity\nbridge_config_with_id = MCPToA2ABridgeConfig(\n mcp_config=mcp_config,\n port=0,\n endpoint=\"/secure-time\",\n server_name=\"time-server\",\n identity_id=identity_id, # Will be logged but not exposed via A2A\n)\n\n# The identity will be logged when the bridge starts\nsecure_bridge = await serve_mcp_as_a2a_async(mcp_config, bridge_config_with_id)\nprint(f\"✓ Secure bridge started (check logs for identity verification)\")"
Copy file name to clipboardExpand all lines: docs/serving.md
+80-2Lines changed: 80 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,6 +7,8 @@
7
7
8
8
-[Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2025-03-26), via the [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk).
9
9
10
+
-**MCP to A2A Bridge**: Expose MCP servers as A2A-compatible services, enabling protocol interoperability. Requires both extras: `pip install 'any-agent[mcp,a2a]'`.
11
+
10
12
## Configuring and Serving Agents
11
13
12
14
You can configure and serve an agent using the [`A2AServingConfig`][any_agent.serving.A2AServingConfig] or [`MCPServingConfig`][any_agent.serving.MCPServingConfig] and the [`AnyAgent.serve_async`][any_agent.AnyAgent.serve_async] method.
@@ -152,10 +154,86 @@ if __name__ == "__main__":
152
154
153
155
```
154
156
157
+
## Bridging MCP to A2A
158
+
159
+
any-agent provides a bridge that allows you to expose MCP servers as A2A-compatible services. This enables:
160
+
161
+
-**Protocol Interoperability**: Make MCP tools available to Google's A2A ecosystem
162
+
-**Enterprise Integration**: Connect local tools with enterprise agent systems
163
+
-**Identity Support**: Leverage AGNTCY Identity for secure tool access
0 commit comments