Skip to main content
Glama

LLM Gateway MCP Server

test_stdio_client.py15 kB
#!/usr/bin/env python3 """ Stdio Test Client for Ultimate MCP Server Tests server functionality over stdio transport """ import asyncio import json import os import subprocess from pathlib import Path from fastmcp import Client async def test_stdio_server(): """Test Ultimate MCP Server over stdio transport.""" print("📡 Ultimate MCP Server Stdio Test Client") print("=" * 50) print("🔗 Starting Ultimate MCP Server in stdio mode...") # Find the umcp command umcp_cmd = None if os.path.exists("uv.lock"): # Try uv run first umcp_cmd = ["uv", "run", "umcp", "run"] else: # Try direct umcp command umcp_cmd = ["umcp", "run"] print(f"📡 Command: {' '.join(umcp_cmd)}") try: # Start the server process in stdio mode # Note: stdio is the default mode, so no -t flag needed process = subprocess.Popen( umcp_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=0, # Unbuffered cwd=Path.cwd(), env=os.environ.copy() ) print("✅ Server process started, connecting via stdio...") # Create FastMCP client for stdio transport # Use the process stdin/stdout for communication async with Client.stdio( process.stdin, process.stdout ) as client: print("✅ Successfully connected to stdio server") # Test 1: List available tools print("\n📋 Testing tool discovery via stdio...") tools = await client.list_tools() print(f"Found {len(tools)} tools via stdio transport:") for i, tool in enumerate(tools[:10]): # Show first 10 print(f" {i+1:2d}. {tool.name}") if len(tools) > 10: print(f" ... and {len(tools) - 10} more tools") # Test 2: List available resources print("\n📚 Testing resource discovery via stdio...") resources = await client.list_resources() print(f"Found {len(resources)} resources:") for resource in resources: print(f" - {resource.uri}") # Test 3: Echo tool test print("\n🔊 Testing echo tool via stdio...") echo_result = await client.call_tool("echo", {"message": "Hello from stdio client!"}) if echo_result: echo_data = json.loads(echo_result[0].text) print(f"✅ Echo response: {json.dumps(echo_data, indent=2)}") # Test 4: Provider status test print("\n🔌 Testing provider status via stdio...") try: provider_result = await client.call_tool("get_provider_status", {}) if provider_result: provider_data = json.loads(provider_result[0].text) providers = provider_data.get("providers", {}) print(f"✅ Found {len(providers)} providers via stdio:") for name, status in providers.items(): available = "✅" if status.get("available") else "❌" model_count = len(status.get("models", [])) print(f" {available} {name}: {model_count} models") except Exception as e: print(f"❌ Provider status failed: {e}") # Test 5: Resource reading test print("\n📖 Testing resource reading via stdio...") if resources: try: resource_uri = resources[0].uri resource_content = await client.read_resource(resource_uri) if resource_content: content = resource_content[0].text preview = content[:200] + "..." if len(content) > 200 else content print(f"✅ Resource {resource_uri} content preview:") print(f" {preview}") except Exception as e: print(f"❌ Resource reading failed: {e}") # Test 6: Simple completion test (if providers available) print("\n🤖 Testing completion via stdio...") try: completion_result = await client.call_tool( "generate_completion", { "prompt": "Say hello in exactly 3 words", "provider": "ollama", "model": "mix_77/gemma3-qat-tools:27b", "max_tokens": 10, }, ) if completion_result: result_data = json.loads(completion_result[0].text) print("✅ Completion via stdio:") print(f" Text: '{result_data.get('text', 'No text')}'") print(f" Model: {result_data.get('model', 'Unknown')}") print(f" Success: {result_data.get('success', False)}") print(f" Processing time: {result_data.get('processing_time', 0):.2f}s") except Exception as e: print(f"⚠️ Completion test failed (expected if no providers): {e}") # Test 7: Filesystem tool test print("\n📁 Testing filesystem tools via stdio...") try: dirs_result = await client.call_tool("list_allowed_directories", {}) if dirs_result: dirs_data = json.loads(dirs_result[0].text) print(f"✅ Allowed directories via stdio: {dirs_data.get('count', 0)} directories") except Exception as e: print(f"❌ Filesystem test failed: {e}") # Test 8: Text processing tool test print("\n📝 Testing text processing via stdio...") try: ripgrep_result = await client.call_tool( "run_ripgrep", { "args_str": "'import' . -t py --max-count 3", "input_dir": "." } ) if ripgrep_result: ripgrep_data = json.loads(ripgrep_result[0].text) if ripgrep_data.get("success"): lines = ripgrep_data.get("output", "").split('\n') line_count = len([l for l in lines if l.strip()]) # noqa: E741 print(f"✅ Ripgrep via stdio found {line_count} matching lines") else: print("⚠️ Ripgrep completed but found no matches") except Exception as e: print(f"❌ Text processing test failed: {e}") print("\n🎉 Stdio transport functionality test completed!") # Clean up process print("\n🔄 Shutting down server process...") process.terminate() try: process.wait(timeout=5) print("✅ Server process terminated cleanly") except subprocess.TimeoutExpired: print("⚠️ Server process didn't terminate, forcing kill...") process.kill() process.wait() return True except FileNotFoundError: print("❌ Could not find umcp command") print("\nTroubleshooting:") print("1. Make sure you're in the Ultimate MCP Server directory") print("2. Make sure umcp is installed and in PATH") print("3. Try running 'uv run umcp run' manually to test") return False except Exception as e: print(f"❌ Stdio connection failed: {e}") print("\nTroubleshooting:") print("1. Make sure the server can start in stdio mode") print("2. Check for any startup errors in stderr") print("3. Verify all dependencies are installed") # Try to get stderr from process if available if 'process' in locals(): try: stderr_output = process.stderr.read() if process.stderr else "" if stderr_output: print(f"\nServer stderr:\n{stderr_output}") process.terminate() process.wait(timeout=5) except Exception: pass return False async def test_stdio_interactive(): """Interactive stdio testing mode.""" print("\n🎮 Entering stdio interactive mode...") print("⚠️ Note: Interactive mode with stdio requires careful process management") print("Type 'list' to see available tools, 'quit' to exit") # Find the umcp command umcp_cmd = None if os.path.exists("uv.lock"): umcp_cmd = ["uv", "run", "umcp", "run"] else: umcp_cmd = ["umcp", "run"] try: # Start the server process process = subprocess.Popen( umcp_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=0, cwd=Path.cwd(), env=os.environ.copy() ) async with Client.stdio(process.stdin, process.stdout) as client: tools = await client.list_tools() resources = await client.list_resources() while True: try: command = input("\nStdio> ").strip() if command.lower() in ['quit', 'exit', 'q']: print("👋 Goodbye!") break elif command.lower() == 'list': print("Available tools:") for i, tool in enumerate(tools[:20]): print(f" {i+1:2d}. {tool.name}") if len(tools) > 20: print(f" ... and {len(tools) - 20} more") elif command.lower() == 'resources': print("Available resources:") for resource in resources: print(f" - {resource.uri}") elif command.startswith("tool "): # Call tool: tool <tool_name> <json_params> parts = command[5:].split(' ', 1) tool_name = parts[0] params = json.loads(parts[1]) if len(parts) > 1 else {} try: result = await client.call_tool(tool_name, params) if result: print(f"✅ Tool result: {result[0].text}") else: print("❌ No result returned") except Exception as e: print(f"❌ Tool call failed: {e}") elif command.startswith("read "): # Read resource: read <resource_uri> resource_uri = command[5:].strip() try: result = await client.read_resource(resource_uri) if result: content = result[0].text preview = content[:500] + "..." if len(content) > 500 else content print(f"✅ Resource content: {preview}") else: print("❌ No content returned") except Exception as e: print(f"❌ Resource read failed: {e}") else: print("Commands:") print(" list - List available tools") print(" resources - List available resources") print(" tool <name> <params> - Call a tool with JSON params") print(" read <uri> - Read a resource") print(" quit - Exit interactive mode") except KeyboardInterrupt: print("\n👋 Goodbye!") break except Exception as e: print(f"❌ Command error: {e}") # Clean up process.terminate() try: process.wait(timeout=5) except subprocess.TimeoutExpired: process.kill() process.wait() except Exception as e: print(f"❌ Stdio interactive mode failed: {e}") def check_prerequisites(): """Check if prerequisites are available.""" print("🔍 Checking prerequisites...") # Check if we're in the right directory if not Path("pyproject.toml").exists(): print("❌ Not in Ultimate MCP Server directory (no pyproject.toml found)") return False # Check if umcp is available try: if Path("uv.lock").exists(): result = subprocess.run(["uv", "run", "umcp", "--version"], capture_output=True, text=True, timeout=10) else: result = subprocess.run(["umcp", "--version"], capture_output=True, text=True, timeout=10) if result.returncode == 0: print("✅ umcp command is available") return True else: print(f"❌ umcp command failed: {result.stderr}") return False except FileNotFoundError: print("❌ umcp command not found") print("Try: pip install -e . or uv sync") return False except subprocess.TimeoutExpired: print("❌ umcp command timed out") return False except Exception as e: print(f"❌ Error checking umcp: {e}") return False async def main(): """Main test function.""" # Check prerequisites first if not check_prerequisites(): print("\n❌ Prerequisites not met. Please fix the issues above.") return print("✅ Prerequisites check passed\n") # Run basic functionality test success = await test_stdio_server() if success: # Ask if user wants interactive mode try: response = input("\nWould you like to enter stdio interactive mode? (y/n): ").strip().lower() if response in ['y', 'yes']: await test_stdio_interactive() except KeyboardInterrupt: print("\n👋 Goodbye!") else: print("\n❌ Basic stdio test failed. Skipping interactive mode.") if __name__ == "__main__": asyncio.run(main())

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Dicklesworthstone/llm_gateway_mcp_server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server