""" MCP client configuration and setup for bird classification agents. """ import os from typing import List, Dict, Any from langchain_mcp_adapters.client import MultiServerMCPClient from .config import AgentConfig class MCPClientManager: """Manages MCP client connections to various servers""" @staticmethod async def create_classifier_client() -> MultiServerMCPClient: """ Create MCP client for Modal bird classifier only. Returns: MultiServerMCPClient configured for Modal server """ print("[STATUS]: Connecting to Modal MCP server...") client = MultiServerMCPClient({ "bird_classifier": { "transport": "streamable_http", "url": AgentConfig.MODAL_MCP_URL, "headers": { "X-API-Key": AgentConfig.BIRD_CLASSIFIER_API_KEY } } }) return client @staticmethod async def create_multi_server_client() -> MultiServerMCPClient: """ Create MCP client for both Modal classifier and Nuthatch species database. Returns: MultiServerMCPClient configured for both servers """ print("[STATUS]: Connecting to Modal and Nuthatch servers...") servers_config = { "bird_classifier": { "transport": "streamable_http", "url": AgentConfig.MODAL_MCP_URL, "headers": { "X-API-Key": AgentConfig.BIRD_CLASSIFIER_API_KEY } } } # Add Nuthatch server (Phase 2.5 - species reference database) # Supports both STDIO (default) and HTTP transport if AgentConfig.NUTHATCH_USE_STDIO: # STDIO mode - subprocess for integrated agent use servers_config["nuthatch"] = { "transport": "stdio", "command": "python", "args": ["nuthatch_tools.py"], # Same directory as where app runs "env": { # Pass through critical env vars from parent process # HuggingFace Spaces Secrets don't auto-inherit to subprocesses "NUTHATCH_API_KEY": AgentConfig.NUTHATCH_API_KEY, "NUTHATCH_BASE_URL": AgentConfig.NUTHATCH_BASE_URL } } else: # HTTP mode - external server (requires nuthatch_tools.py running separately) nuthatch_config = { "transport": "streamable_http", "url": AgentConfig.NUTHATCH_MCP_URL } # Add auth header if configured (DebugTokenVerifier expects Bearer token) if AgentConfig.NUTHATCH_MCP_AUTH_KEY: nuthatch_config["headers"] = { "Authorization": f"Bearer {AgentConfig.NUTHATCH_MCP_AUTH_KEY}" } servers_config["nuthatch"] = nuthatch_config client = MultiServerMCPClient(servers_config) return client @staticmethod async def get_tools(client: MultiServerMCPClient) -> List[Any]: """ Get tools from MCP client and print summary. Args: client: MultiServerMCPClient instance Returns: List of tools """ print("[STATUS]: Loading MCP tools...") tools = await client.get_tools() print(f"[LOADED]: {len(tools)} tools available") for tool in tools: print(f" - {tool.name}") return tools