Skip to main content
Glama
cli.py10.6 kB
#!/usr/bin/env python3 """ Lightfast MCP Orchestrator - Multi-server management for creative applications. This is the main entry point for orchestrating multiple MCP servers simultaneously. Users can select which servers to start, run them in the background, and then use the dedicated AI client to interact with them. """ import argparse import asyncio from lightfast_mcp.utils.logging_utils import configure_logging, get_logger from .config_loader import ConfigLoader from .server_orchestrator import get_orchestrator from .server_selector import ServerSelector # Configure logging configure_logging(level="INFO") logger = get_logger("LightfastMCPOrchestrator") # Async wrapper functions for CLI def start_multiple_servers_sync(configs, background=True, show_logs=True): """Sync wrapper for async start_multiple_servers.""" orchestrator = get_orchestrator() async def _async_start(): result = await orchestrator.start_multiple_servers( configs, background, show_logs ) return result.data if result.is_success else {} return asyncio.run(_async_start()) def get_server_urls_sync(): """Get server URLs from orchestrator.""" orchestrator = get_orchestrator() servers = orchestrator.get_running_servers() return {name: info.url for name, info in servers.items() if info.url} def wait_for_shutdown_sync(): """Wait for shutdown signal.""" orchestrator = get_orchestrator() orchestrator._shutdown_event.wait() def shutdown_all_sync(): """Shutdown all servers.""" orchestrator = get_orchestrator() orchestrator.shutdown_all() def create_sample_config(): """Create a sample configuration file.""" print("[CONFIG] Creating sample configuration...") config_loader = ConfigLoader() success = config_loader.create_sample_config("servers.yaml") if success: print("[OK] Sample configuration created at: config/servers.yaml") print("[INFO] Edit this file to customize your server settings.") print("[START] Run 'lightfast-mcp-orchestrator start' to begin!") else: print("[ERROR] Failed to create sample configuration") def list_available_servers(): """List all available server types and configurations.""" print("[INFO] Available Server Types:") print("=" * 50) from .server_registry import get_registry registry = get_registry() server_info = registry.get_server_info() for server_type, info in server_info.items(): print(f"[SERVER] {server_type}") print(f" Version: {info['version']}") print(f" Description: {info['description']}") if info["required_dependencies"]: print(f" Dependencies: {', '.join(info['required_dependencies'])}") if info["required_apps"]: print(f" Required Apps: {', '.join(info['required_apps'])}") print() print("[CONFIG] Server Configurations:") print("=" * 50) config_loader = ConfigLoader() configs = config_loader.load_servers_config() if not configs: print("[ERROR] No server configurations found.") print( " Run 'lightfast-mcp-orchestrator init' to create a sample configuration." ) return for config in configs: server_type = config.config.get("type", "unknown") print(f"[SERVER] {config.name} ({server_type})") print(f" Description: {config.description}") print(f" Transport: {config.transport}") if config.transport in ["http", "streamable-http"]: print(f" URL: http://{config.host}:{config.port}{config.path}") print() def start_servers_interactive(show_logs: bool = True): """Start servers with interactive selection.""" print("[START] Lightfast MCP Multi-Server Orchestrator") print("=" * 50) # Interactive server selection selector = ServerSelector() selected_configs = selector.load_available_servers() if not selected_configs: print("[ERROR] No server configurations found.") print(" Would you like to create a sample configuration? (y/n)") try: create_sample = input().strip().lower() if create_sample in ["y", "yes"]: config_loader = ConfigLoader() if config_loader.create_sample_config("servers.yaml"): print("[OK] Sample configuration created at: config/servers.yaml") print("[INFO] Loading the new configuration...") selected_configs = selector.load_available_servers() else: print("[ERROR] Failed to create sample configuration") return else: print("[BYE] No configuration created. Goodbye!") return except KeyboardInterrupt: print("\n[BYE] Cancelled. Goodbye!") return if not selected_configs: print("[ERROR] Still no server configurations available.") return # Let user select servers selected_configs = selector.select_servers_interactive() if not selected_configs: print("[BYE] No servers selected. Goodbye!") return print(f"\n[START] Starting {len(selected_configs)} servers...") print(" This may take a few moments as servers initialize...") results = start_multiple_servers_sync( selected_configs, background=True, show_logs=show_logs ) # Show results successful = sum(1 for success in results.values() if success) print(f"[OK] Successfully started {successful}/{len(selected_configs)} servers") # Show any failures failed_servers = [name for name, success in results.items() if not success] if failed_servers: print(f"[ERROR] Failed to start: {', '.join(failed_servers)}") if successful > 0: # Show server URLs urls = get_server_urls_sync() if urls: print("\n[URLS] Server URLs:") for name, url in urls.items(): print(f" • {name}: {url}") print( "\n[INFO] Servers are running! Use the dedicated AI client to interact with them." ) print( " Run 'uv run lightfast-conversation-client chat' to start the AI client." ) print(" Press Ctrl+C to shutdown all servers.\n") try: # Wait for shutdown wait_for_shutdown_sync() except KeyboardInterrupt: print("\n[STOP] Shutting down servers...") shutdown_all_sync() print("[BYE] All servers stopped. Goodbye!") def start_servers_by_names(server_names: list[str], show_logs: bool = True): """Start specific servers by name.""" config_loader = ConfigLoader() all_configs = config_loader.load_servers_config() if not all_configs: print("[ERROR] No server configurations found.") return # Find requested servers selected_configs = [] for name in server_names: config = next((c for c in all_configs if c.name == name), None) if config: selected_configs.append(config) else: print(f"[WARN] Server configuration not found: {name}") if not selected_configs: print("[ERROR] No valid servers to start.") return # Start servers results = start_multiple_servers_sync( selected_configs, background=True, show_logs=show_logs ) # Show results successful = sum(1 for success in results.values() if success) print(f"[OK] Successfully started {successful}/{len(selected_configs)} servers") if successful > 0: urls = get_server_urls_sync() if urls: print("\n[URLS] Server URLs:") for name, url in urls.items(): print(f" • {name}: {url}") try: wait_for_shutdown_sync() except KeyboardInterrupt: print("\n[STOP] Shutting down servers...") shutdown_all_sync() def main(): """Main CLI entry point.""" parser = argparse.ArgumentParser( description="Lightfast MCP Orchestrator - Multi-server management for creative applications", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: lightfast-mcp-orchestrator init # Create sample configuration lightfast-mcp-orchestrator list # List available servers lightfast-mcp-orchestrator start # Interactive server selection lightfast-mcp-orchestrator start blender-server # Start specific server lightfast-mcp-orchestrator start --hide-logs # Start servers without showing logs lightfast-mcp-orchestrator start --verbose # Start with debug logging and server logs AI Client (use after starting servers): uv run lightfast-conversation-client chat # Start interactive AI chat uv run lightfast-conversation-client test # Quick AI test """, ) parser.add_argument( "command", choices=["init", "list", "start"], help="Command to run" ) parser.add_argument( "servers", nargs="*", help="Server names to start (for 'start' command)" ) parser.add_argument("--config", help="Configuration file path") parser.add_argument( "--verbose", "-v", action="store_true", help="Enable verbose logging" ) parser.add_argument( "--show-logs", action="store_true", default=True, help="Show server logs in terminal (default: True)", ) parser.add_argument( "--hide-logs", action="store_true", help="Hide server logs from terminal" ) args = parser.parse_args() # Set logging level if args.verbose: configure_logging(level="DEBUG") print("[DEBUG] Debug logging enabled") # Determine log visibility (--hide-logs takes precedence) show_logs = not args.hide_logs if args.hide_logs else args.show_logs if args.verbose: print( f"[INFO] Server logs visibility: {'Enabled' if show_logs else 'Disabled'}" ) # Handle commands if args.command == "init": create_sample_config() elif args.command == "list": list_available_servers() elif args.command == "start": if args.servers: start_servers_by_names(args.servers, show_logs=show_logs) else: start_servers_interactive(show_logs=show_logs) if __name__ == "__main__": main()

Latest Blog Posts

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/lightfastai/lightfast-mcp'

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