import httpx from typing import List, Dict, Any class MCPClient: """ A client for interacting with a Model Context Protocol (MCP) server. Handles listing and executing tools via HTTP requests. """ def __init__(self, server_url: str): self.server_url = server_url.rstrip('/') self.http_client = httpx.AsyncClient(timeout=30.0) async def list_tools(self) -> List[Dict[str, Any]]: """Fetches the list of available tools from the MCP server.""" try: response = await self.http_client.get(f"{self.server_url}/mcp/tools") response.raise_for_status() tools_response = response.json() # Ensure the response is in the expected format if "tools" in tools_response and isinstance(tools_response["tools"], list): return tools_response["tools"] return [] except (httpx.RequestError, httpx.HTTPStatusError) as e: print(f"Error fetching tools from {self.server_url}: {e}") return [] async def execute_tool(self, tool_name: str, params: Dict[str, Any]) -> Dict[str, Any]: """Executes a specific tool on the MCP server with the given parameters.""" try: response = await self.http_client.post( f"{self.server_url}/mcp/tools/{tool_name}", json={"params": params} ) response.raise_for_status() return response.json() except (httpx.RequestError, httpx.HTTPStatusError) as e: print(f"Error executing tool '{tool_name}' on {self.server_url}: {e}") return { "status": "error", "result": f"Failed to connect or execute tool on {self.server_url}. Error: {e}" } async def close(self): """Closes the underlying HTTP client.""" await self.http_client.aclose()