Coverage for excalidraw_mcp/server.py: 54%
56 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-16 08:08 -0700
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-16 08:08 -0700
1#!/usr/bin/env python3
2"""Excalidraw MCP Server - Python FastMCP Implementation
3Provides MCP tools for creating and managing Excalidraw diagrams with canvas sync.
4"""
6import asyncio
7import atexit
8import logging
9import signal
10from typing import Any
12from fastmcp import FastMCP
14from .monitoring.supervisor import MonitoringSupervisor
16# Initialize FastMCP server
17mcp = FastMCP("Excalidraw MCP Server", streamable_http_path="/mcp")
19# Configure logging
20logging.basicConfig(level=logging.INFO)
21logger = logging.getLogger(__name__)
23# Global instances
24process_manager: Any = None
25monitoring_supervisor: Any = None
28def get_process_manager() -> Any:
29 """Get or create the global process manager instance."""
30 global process_manager
31 if process_manager is None:
32 from .process_manager import CanvasProcessManager
34 process_manager = CanvasProcessManager()
35 # Register cleanup function
36 atexit.register(process_manager.cleanup)
37 return process_manager
40def get_monitoring_supervisor() -> Any:
41 """Get or create the global monitoring supervisor instance."""
42 global monitoring_supervisor
43 if monitoring_supervisor is None:
44 from .monitoring.supervisor import MonitoringSupervisor
46 monitoring_supervisor = MonitoringSupervisor()
47 return monitoring_supervisor
50# Initialize monitoring supervisor
51monitoring_supervisor = MonitoringSupervisor()
54def cleanup_monitoring() -> None:
55 if monitoring_supervisor.is_running:
56 from contextlib import suppress
58 with suppress(RuntimeError):
59 asyncio.create_task(monitoring_supervisor.stop())
62async def startup_initialization() -> None:
63 """Initialize canvas server and monitoring on startup"""
64 logger.info("Starting Excalidraw MCP Server...")
65 # Initialize components
66 process_manager = get_process_manager()
67 monitoring_supervisor = get_monitoring_supervisor()
69 # Start canvas server
70 await process_manager.start()
72 # Start monitoring
73 monitoring_supervisor.start_monitoring()
75 logger.info("Excalidraw MCP Server started successfully")
78def main() -> None:
79 """Main entry point for the CLI"""
81 async def shutdown() -> None:
82 """Graceful shutdown procedure."""
83 logger.info("Starting graceful shutdown...")
84 process_manager = get_process_manager()
85 monitoring_supervisor = get_monitoring_supervisor()
87 # Stop monitoring first
88 monitoring_supervisor.stop_monitoring()
90 # Stop canvas server
91 await process_manager.stop()
93 logger.info("Graceful shutdown completed")
95 # Set up signal handlers for graceful shutdown
96 signal.signal(signal.SIGTERM, lambda signum, frame: asyncio.create_task(shutdown()))
97 signal.signal(signal.SIGINT, lambda signum, frame: asyncio.create_task(shutdown()))
99 try:
100 logger.info("Starting Excalidraw MCP Server...")
101 asyncio.run(startup_initialization())
102 except KeyboardInterrupt:
103 logger.info("Server interrupted by user")
104 except Exception as e:
105 logger.error(f"Server error: {e}")
106 raise
109if __name__ == "__main__":
110 main()