Files
AICycling_mcp/mcp_debug.py
2025-09-23 10:23:12 -07:00

204 lines
6.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Debug script to identify MCP tools hanging issue
"""
import asyncio
import yaml
import logging
import signal
from main import GarthMCPConnector, Config
# Set up more detailed logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class TimeoutError(Exception):
pass
def timeout_handler(signum, frame):
raise TimeoutError("Operation timed out")
async def debug_mcp_connection():
"""Debug the MCP connection step by step"""
# Load config
with open("config.yaml") as f:
config_data = yaml.safe_load(f)
config = Config(**config_data)
garmin = GarthMCPConnector(config.garth_token, config.garth_mcp_server_path)
print("=== MCP CONNECTION DEBUG ===")
# Step 1: Test connection
print("\n1. Testing MCP connection...")
try:
success = await garmin.connect()
if success:
print("✓ MCP connection successful")
else:
print("✗ MCP connection failed")
return
except Exception as e:
print(f"✗ MCP connection error: {e}")
return
# Step 2: Test session availability
print("\n2. Testing session availability...")
if garmin._session:
print("✓ Session is available")
else:
print("✗ No session available")
return
# Step 3: Test tools listing with timeout
print("\n3. Testing tools listing (with 10s timeout)...")
try:
# Set up timeout
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(10) # 10 second timeout
tools_result = await garmin._session.list_tools()
signal.alarm(0) # Cancel timeout
if tools_result:
print(f"✓ Tools result received: {type(tools_result)}")
if hasattr(tools_result, 'tools'):
tools = tools_result.tools
print(f"✓ Found {len(tools)} tools")
# Show first few tools
for i, tool in enumerate(tools[:3]):
print(f" Tool {i+1}: {tool.name} - {getattr(tool, 'description', 'No desc')}")
if len(tools) > 3:
print(f" ... and {len(tools) - 3} more tools")
else:
print(f"✗ tools_result has no 'tools' attribute: {dir(tools_result)}")
else:
print("✗ No tools result received")
except TimeoutError:
print("✗ Tools listing timed out after 10 seconds")
print("This suggests the MCP server is hanging on list_tools()")
except Exception as e:
print(f"✗ Tools listing error: {e}")
import traceback
traceback.print_exc()
finally:
signal.alarm(0) # Make sure to cancel any pending alarm
# Step 4: Test our wrapper method
print("\n4. Testing our get_available_tools_info() method...")
try:
# Clear cache first
garmin.cached_tools = []
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(15) # 15 second timeout
tools = await garmin.get_available_tools_info()
signal.alarm(0)
print(f"✓ get_available_tools_info() returned {len(tools)} tools")
for tool in tools[:3]:
print(f" - {tool['name']}: {tool['description']}")
except TimeoutError:
print("✗ get_available_tools_info() timed out")
except Exception as e:
print(f"✗ get_available_tools_info() error: {e}")
finally:
signal.alarm(0)
# Cleanup
print("\n5. Cleaning up...")
await garmin.disconnect()
print("✓ Cleanup complete")
async def test_alternative_approach():
"""Test an alternative approach to getting tools info"""
print("\n=== TESTING ALTERNATIVE APPROACH ===")
# Load config
with open("config.yaml") as f:
config_data = yaml.safe_load(f)
config = Config(**config_data)
# Create a simpler MCP connector for testing
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import os
import shutil
try:
# Set up environment
env = os.environ.copy()
env['GARTH_TOKEN'] = config.garth_token
# Find server command
server_command = shutil.which("garth-mcp-server")
if not server_command:
print("✗ garth-mcp-server not found")
return
print(f"✓ Found server at: {server_command}")
# Create server parameters
server_params = StdioServerParameters(
command="/bin/bash",
args=["-c", f"exec {server_command} \"$@\" 1>&2"],
env=env,
)
print("Starting direct MCP test...")
async with stdio_client(server_params) as streams:
if len(streams) == 3:
read_stream, write_stream, stderr_stream = streams
else:
read_stream, write_stream = streams
session = ClientSession(read_stream, write_stream)
await session.initialize()
print("✓ Direct session initialized")
# Try to list tools with timeout
try:
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(10)
print("Calling list_tools()...")
tools_result = await session.list_tools()
signal.alarm(0)
print(f"✓ Direct list_tools() successful: {len(tools_result.tools) if tools_result and hasattr(tools_result, 'tools') else 0} tools")
if tools_result and hasattr(tools_result, 'tools'):
for tool in tools_result.tools[:3]:
print(f" - {tool.name}")
except TimeoutError:
print("✗ Direct list_tools() timed out")
except Exception as e:
print(f"✗ Direct list_tools() error: {e}")
finally:
signal.alarm(0)
except Exception as e:
print(f"✗ Alternative approach failed: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
async def main():
await debug_mcp_connection()
await test_alternative_approach()
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n\n✗ Interrupted by user")
except Exception as e:
print(f"\n\n✗ Debug script failed: {e}")
import traceback
traceback.print_exc()