BirdScopeAI / langgraph_agent /mcp_clients.py.ebird
facemelter's picture
Initial commit to hf space for hackathon
ff0e97f verified
"""
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 eBird server.
Returns:
MultiServerMCPClient configured for both servers
"""
print("[STATUS]: Connecting to Modal and eBird servers...")
servers_config = {
"bird_classifier": {
"transport": "streamable_http",
"url": AgentConfig.MODAL_MCP_URL,
"headers": {
"X-API-Key": AgentConfig.BIRD_CLASSIFIER_API_KEY
}
}
}
# Add eBird server (Phase 2)
if AgentConfig.EBIRD_USE_STDIO:
# Stdio transport (run server as subprocess)
# IMPORTANT: Explicitly pass environment variables to subprocess
# HuggingFace Spaces Secrets don't auto-inherit to subprocesses
servers_config["ebird"] = {
"transport": "stdio",
"command": "python",
"args": ["ebird_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
"EBIRD_API_KEY": AgentConfig.EBIRD_API_KEY,
"EBIRD_BASE_URL": AgentConfig.EBIRD_BASE_URL,
"ENVIRONMENT": os.getenv("ENVIRONMENT", "development"),
"MCP_API_KEY": AgentConfig.EBIRD_MCP_AUTH_KEY or "",
}
}
else:
# HTTP transport (server running separately)
ebird_config = {
"transport": "streamable_http",
"url": AgentConfig.EBIRD_MCP_URL
}
# Add auth header if configured (DebugTokenVerifier expects Bearer token)
if AgentConfig.EBIRD_MCP_AUTH_KEY:
ebird_config["headers"] = {
"Authorization": f"Bearer {AgentConfig.EBIRD_MCP_AUTH_KEY}"
}
servers_config["ebird"] = ebird_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