File size: 3,553 Bytes
ff0e97f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
"""
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