Add multiple MCP support

Add multiple MCP support
pull/891/head
Pavan Kumar 1 month ago committed by GitHub
commit a7aa469345
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -2,8 +2,16 @@
This example demonstrates using a list of MCP servers with an `Agent`.
Start the example servers in separate terminals:
```bash
python examples/tools/mcp_examples/servers/weather_server.py
python examples/tools/mcp_examples/servers/news_server.py
```
```python
import os
import json
from swarms import Agent
# Configure multiple MCP URLs
@ -15,11 +23,12 @@ agent = Agent(
max_loops=1,
)
# Example payloads produced by your model
payloads = [
# Example JSON payloads produced by your model
response = json.dumps([
{"function_name": "get_weather", "server_url": "http://localhost:8000/sse", "payload": {"city": "London"}},
{"function_name": "get_news", "server_url": "http://localhost:9001/sse", "payload": {"topic": "ai"}},
]
])
agent.handle_multiple_mcp_tools(agent.mcp_urls, response)
agent.handle_multiple_mcp_tools(agent.mcp_urls, payloads)
```

@ -483,8 +483,16 @@ print(agent.to_toml())
Execute tools from multiple MCP servers by providing a list of URLs via the
`mcp_urls` parameter or the `MCP_URLS` environment variable.
Start the example servers:
```bash
python examples/tools/mcp_examples/servers/weather_server.py
python examples/tools/mcp_examples/servers/news_server.py
```
```python
import os
import json
from swarms import Agent
# Using an environment variable for server configuration
@ -497,7 +505,8 @@ agent = Agent(
)
# Example MCP payloads returned by your model
mcp_payloads = [
mcp_response = json.dumps([
{
"function_name": "get_price",
"server_url": "http://localhost:8000/sse",
@ -508,9 +517,10 @@ mcp_payloads = [
"server_url": "http://localhost:9001/sse",
"payload": {"symbol": "BTC"},
},
]
])
agent.handle_multiple_mcp_tools(agent.mcp_urls, mcp_response)
agent.handle_multiple_mcp_tools(agent.mcp_urls, mcp_payloads)
```
## Auto Generate Prompt + CPU Execution

@ -145,6 +145,14 @@ payload in the following format:
Use `handle_multiple_mcp_tools` to execute each payload across the configured
servers.
Example servers can be started with:
```bash
python examples/tools/mcp_examples/servers/weather_server.py
python examples/tools/mcp_examples/servers/news_server.py
```
---
## Integration Flow

@ -0,0 +1,12 @@
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("NewsServer")
mcp.settings.port = 9001
@mcp.tool(name="get_news", description="Return simple news headline")
def get_news(topic: str) -> str:
return f"Latest {topic} news headline"
if __name__ == "__main__":
mcp.run(transport="sse")

@ -0,0 +1,12 @@
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("WeatherServer")
mcp.settings.port = 8000
@mcp.tool(name="get_weather", description="Return simple weather info")
def get_weather(city: str) -> str:
return f"Weather in {city}: Sunny 22°C"
if __name__ == "__main__":
mcp.run(transport="sse")

@ -0,0 +1,73 @@
import os
import json
from swarms import Agent
import io
import sys
from contextlib import redirect_stdout
print("\n=== Testing Multiple MCP Tool Execution ===\n")
# Configure multiple MCP URLs
os.environ["MCP_URLS"] = "http://localhost:8000/sse,http://localhost:9001/sse"
def capture_output(func):
"""Capture printed output from a function"""
f = io.StringIO()
with redirect_stdout(f):
func()
return f.getvalue()
def test_direct_tool_execution():
"""Test directly executing tools on different MCP servers"""
print("Testing direct tool execution...\n")
agent = Agent(
agent_name="Multi-MCP-Agent",
model_name="gpt-4o-mini",
max_loops=1
)
# Create JSON payloads for multiple tools
payloads = [
{
"function_name": "get_weather",
"server_url": "http://localhost:8000/sse",
"payload": {"city": "Paris"}
},
{
"function_name": "get_news",
"server_url": "http://localhost:9001/sse",
"payload": {"topic": "science"}
}
]
# Execute the tools and capture output
print("Executing tools on multiple MCP servers...")
output = capture_output(
lambda: agent.handle_multiple_mcp_tools(agent.mcp_urls, json.dumps(payloads))
)
# Extract and display results
print("\nResults from MCP tools:")
print(output)
print("\nTest complete - Multiple MCP execution successful!")
def test_agent_configuration():
"""Test different ways to configure agents with multiple MCP URLs"""
print("\n=== Testing Agent MCP Configuration Methods ===\n")
# Method 1: Configure via environment variables (already set above)
agent1 = Agent(agent_name="Env-Config-Agent")
print(f"Agent1 MCP URLs (from env): {agent1.mcp_urls}")
# Method 2: Configure via direct parameter
agent2 = Agent(
agent_name="Direct-Config-Agent",
mcp_urls=["http://localhost:8000/sse", "http://localhost:9001/sse"]
)
print(f"Agent2 MCP URLs (from param): {agent2.mcp_urls}")
if __name__ == "__main__":
test_agent_configuration()
test_direct_tool_execution()

@ -1,5 +1,6 @@
import asyncio
import json
import re
import logging
import os
import random
@ -74,6 +75,7 @@ from swarms.structs.ma_utils import set_random_models_for_agents
from swarms.tools.mcp_client_call import (
execute_tool_call_simple,
get_mcp_tools_sync,
execute_mcp_call,
)
from swarms.schemas.mcp_schemas import (
MCPConnection,
@ -98,6 +100,25 @@ def parse_done_token(response: str) -> bool:
return "<DONE>" in response
def extract_json_from_response(response: str) -> List[Dict[str, Any]]:
"""Extract a JSON list from a model response string."""
if not response:
return []
if not isinstance(response, str):
return response if isinstance(response, list) else []
try:
return json.loads(response)
except json.JSONDecodeError:
match = re.search(r"\[[\s\S]*?\]", response)
if match:
try:
return json.loads(match.group(0))
except json.JSONDecodeError:
pass
logger.error("Failed to parse MCP payloads from response")
return []
# Agent ID generator
def agent_id():
"""Generate an agent id"""
@ -442,6 +463,8 @@ class Agent:
self.sop = sop
self.sop_list = sop_list
self.tools = tools
# Ensure tool_struct exists even when no tools are provided
self.tool_struct = {}
self.system_prompt = system_prompt
self.agent_name = agent_name
self.agent_description = agent_description
@ -1098,18 +1121,12 @@ class Agent:
if exists(self.mcp_urls):
try:
payload = (
json.loads(response)
if isinstance(response, str)
else response
self.handle_multiple_mcp_tools(
self.mcp_urls,
response,
current_loop=loop_count,
)
if isinstance(payload, list):
self.handle_multiple_mcp_tools(
self.mcp_urls,
payload,
current_loop=loop_count,
)
except Exception as e:
logger.error(
f"Error handling multiple MCP tools: {e}"
@ -2820,12 +2837,14 @@ class Agent:
def handle_multiple_mcp_tools(
self,
mcp_url_list: List[str],
mcp_payloads: List[Dict[str, Any]],
response: Union[str, List[Dict[str, Any]]],
current_loop: int = 0,
) -> None:
"""Execute a list of MCP tool calls across multiple servers."""
"""Execute multiple MCP tool calls across configured servers."""
payloads = extract_json_from_response(response)
for payload in payloads:
for payload in mcp_payloads:
function_name = payload.get("function_name")
server_url = payload.get("server_url")
arguments = payload.get("payload", {})
@ -2836,25 +2855,31 @@ class Agent:
)
continue
try:
tool_response = asyncio.run(
execute_mcp_call(
function_name=function_name,
server_url=server_url,
payload=arguments,
attempt = 0
while attempt < 3:
try:
tool_response = asyncio.run(
execute_mcp_call(
function_name=function_name,
server_url=server_url,
payload=arguments,
)
)
)
self.short_memory.add(
role="Tool Executor",
content=str(tool_response),
)
self.pretty_print(
str(tool_response), loop_count=current_loop
)
except Exception as e: # noqa: PERF203
logger.error(
f"Error executing {function_name} on {server_url}: {e}"
)
self.short_memory.add(
role="Tool Executor",
content=str(tool_response),
)
self.pretty_print(
str(tool_response),
loop_count=current_loop,
)
break
except Exception as e: # noqa: PERF203
attempt += 1
logger.error(
f"Error executing {function_name} on {server_url}: {e}"
)
time.sleep(1)
def temp_llm_instance_for_tool_summary(self):
return LiteLLM(

@ -1,5 +1,7 @@
import asyncio
from swarms.structs.agent import Agent
import json
from swarms.structs.agent import Agent, extract_json_from_response
from swarms.structs.agent import execute_mcp_call
from unittest.mock import patch
@ -30,9 +32,19 @@ def test_handle_multiple_mcp_tools():
with patch(
"swarms.structs.agent.execute_mcp_call", side_effect=fake_exec
):
agent.handle_multiple_mcp_tools(urls, payloads)
agent.handle_multiple_mcp_tools(urls, json.dumps(payloads))
assert called == [
("tool1", "http://server1", {"a": 1}),
("tool2", "http://server2", {}),
]
def test_extract_json_from_response():
payloads = [
{"function_name": "foo", "server_url": "http://x", "payload": {"x": 1}}
]
text = "Random text" + json.dumps(payloads) + " end"
result = extract_json_from_response(text)
assert result == payloads

Loading…
Cancel
Save