zequn-fireworks commited on
Commit
c1c4565
·
1 Parent(s): 65af9fc

Add mcp-a2a-gateway config and seed script

Browse files

Replace a2a-mcp-bridge (hardcoded 30s timeout) with mcp-a2a-gateway
which supports configurable timeouts (set to 300s) and persistent
agent registrations. Includes a seed script to pre-register all
5 provider agents from the HF Space deployment.

Made-with: Cursor

Files changed (3) hide show
  1. .cursor/mcp.json +13 -0
  2. README.md +62 -0
  3. scripts/seed_gateway.py +96 -0
.cursor/mcp.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcpServers": {
3
+ "fireaction": {
4
+ "command": "uvx",
5
+ "args": ["mcp-a2a-gateway"],
6
+ "env": {
7
+ "MCP_REQUEST_TIMEOUT": "300",
8
+ "MCP_DATA_DIR": "~/.cursor/fireaction-gateway-data",
9
+ "LOG_LEVEL": "INFO"
10
+ }
11
+ }
12
+ }
13
+ }
README.md CHANGED
@@ -40,6 +40,68 @@ Each provider agent exposes three internal tools to an LLM planner:
40
  The planner runs a ReAct loop: search for contracts, inspect their schemas,
41
  generate instance nodes, execute, and feed results back for multi-step tasks.
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  ## Configuration
44
 
45
  All via environment variables:
 
40
  The planner runs a ReAct loop: search for contracts, inspect their schemas,
41
  generate instance nodes, execute, and feed results back for multi-step tasks.
42
 
43
+ ## MCP setup (Cursor / Claude Code / VS Code Copilot)
44
+
45
+ The agents can be used from any MCP-compatible client via
46
+ [`mcp-a2a-gateway`](https://pypi.org/project/mcp-a2a-gateway/), a Python-based
47
+ MCP↔A2A bridge with configurable timeouts and persistent agent registrations.
48
+
49
+ ### 1. Add the MCP server
50
+
51
+ The repo ships a `.cursor/mcp.json` that Cursor picks up automatically.
52
+ For other clients, add the equivalent config:
53
+
54
+ ```json
55
+ {
56
+ "mcpServers": {
57
+ "fireaction": {
58
+ "command": "uvx",
59
+ "args": ["mcp-a2a-gateway"],
60
+ "env": {
61
+ "MCP_REQUEST_TIMEOUT": "300",
62
+ "MCP_DATA_DIR": "~/.cursor/fireaction-gateway-data",
63
+ "LOG_LEVEL": "INFO"
64
+ }
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### 2. Register the agents
71
+
72
+ **Option A** — Run the seed script (pre-registers all agents in one step):
73
+
74
+ ```bash
75
+ python scripts/seed_gateway.py
76
+ ```
77
+
78
+ This fetches agent cards from the HF Space deployment and writes them to the
79
+ gateway's data directory. Registrations persist across restarts.
80
+
81
+ **Option B** — Register interactively from your MCP client:
82
+
83
+ Ask the AI to run `register_agent` for each provider URL:
84
+
85
+ ```
86
+ https://zequn-fireworks-fireaction-a2a.hf.space/resend/
87
+ https://zequn-fireworks-fireaction-a2a.hf.space/discord/
88
+ https://zequn-fireworks-fireaction-a2a.hf.space/github/
89
+ https://zequn-fireworks-fireaction-a2a.hf.space/plaid/
90
+ https://zequn-fireworks-fireaction-a2a.hf.space/square/
91
+ ```
92
+
93
+ ### 3. Use the agents
94
+
95
+ Once registered, the gateway exposes these MCP tools:
96
+
97
+ | Tool | Purpose |
98
+ |---|---|
99
+ | `send_message` | Send a task to an agent and get a response |
100
+ | `get_task_result` | Poll for completion of a long-running task |
101
+ | `get_task_list` | List all tasks and their statuses |
102
+ | `list_agents` | Show all registered agents |
103
+ | `register_agent` / `unregister_agent` | Add or remove agents dynamically |
104
+
105
  ## Configuration
106
 
107
  All via environment variables:
scripts/seed_gateway.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Pre-register fireaction A2A agents with mcp-a2a-gateway.
3
+
4
+ Fetches agent cards from the deployed HF Space and writes them to the
5
+ gateway's data directory so they're available immediately on first launch
6
+ (no manual ``register_agent`` calls needed).
7
+
8
+ Usage:
9
+ python scripts/seed_gateway.py # defaults
10
+ python scripts/seed_gateway.py --base-url http://localhost:7860
11
+ python scripts/seed_gateway.py --providers resend discord
12
+ python scripts/seed_gateway.py --data-dir /custom/path
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import json
19
+ import os
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ import httpx
24
+
25
+ DEFAULT_BASE_URL = "https://zequn-fireworks-fireaction-a2a.hf.space"
26
+ DEFAULT_PROVIDERS = ["resend", "discord", "github", "plaid", "square"]
27
+ DEFAULT_DATA_DIR = "~/.cursor/fireaction-gateway-data"
28
+
29
+ REGISTERED_AGENTS_FILE = "registered_agents.json"
30
+
31
+
32
+ def fetch_agent_card(client: httpx.Client, agent_url: str) -> dict:
33
+ """Fetch the .well-known/agent.json card from an A2A agent."""
34
+ card_url = agent_url.rstrip("/") + "/.well-known/agent.json"
35
+ resp = client.get(card_url, follow_redirects=True)
36
+ resp.raise_for_status()
37
+ return resp.json()
38
+
39
+
40
+ def main() -> None:
41
+ parser = argparse.ArgumentParser(description="Seed mcp-a2a-gateway with fireaction agents")
42
+ parser.add_argument(
43
+ "--base-url",
44
+ default=os.environ.get("FIREACTION_BASE_URL", DEFAULT_BASE_URL),
45
+ help=f"Base URL of the fireaction-a2a deployment (default: {DEFAULT_BASE_URL})",
46
+ )
47
+ parser.add_argument(
48
+ "--providers",
49
+ nargs="+",
50
+ default=DEFAULT_PROVIDERS,
51
+ help=f"Provider names to register (default: {' '.join(DEFAULT_PROVIDERS)})",
52
+ )
53
+ parser.add_argument(
54
+ "--data-dir",
55
+ default=os.environ.get("MCP_DATA_DIR", DEFAULT_DATA_DIR),
56
+ help=f"Gateway data directory (default: {DEFAULT_DATA_DIR})",
57
+ )
58
+ parser.add_argument(
59
+ "--timeout",
60
+ type=int,
61
+ default=30,
62
+ help="HTTP timeout in seconds for fetching agent cards (default: 30)",
63
+ )
64
+ args = parser.parse_args()
65
+
66
+ data_dir = Path(os.path.expanduser(args.data_dir))
67
+ data_dir.mkdir(parents=True, exist_ok=True)
68
+ agents_file = data_dir / REGISTERED_AGENTS_FILE
69
+
70
+ existing: dict = {}
71
+ if agents_file.exists():
72
+ existing = json.loads(agents_file.read_text())
73
+ print(f"Loaded {len(existing)} existing agent(s) from {agents_file}")
74
+
75
+ agent_urls = [f"{args.base_url.rstrip('/')}/{p}/" for p in args.providers]
76
+ registered = dict(existing)
77
+
78
+ with httpx.Client(timeout=args.timeout) as client:
79
+ for url in agent_urls:
80
+ try:
81
+ card = fetch_agent_card(client, url)
82
+ registered[url] = {"card": card}
83
+ print(f" OK {card.get('name', url)}")
84
+ except httpx.HTTPStatusError as e:
85
+ print(f" FAIL {url} — HTTP {e.response.status_code}", file=sys.stderr)
86
+ except httpx.ConnectError:
87
+ print(f" FAIL {url} — connection refused (is the server running?)", file=sys.stderr)
88
+ except Exception as e:
89
+ print(f" FAIL {url} — {e}", file=sys.stderr)
90
+
91
+ agents_file.write_text(json.dumps(registered, indent=4))
92
+ print(f"\nWrote {len(registered)} agent(s) to {agents_file}")
93
+
94
+
95
+ if __name__ == "__main__":
96
+ main()