|
5 | 5 | import os |
6 | 6 | import signal |
7 | 7 | import logging |
| 8 | +import functools |
8 | 9 | from typing import Callable |
9 | | -from mcp.server.fastmcp import FastMCP |
| 10 | +from fastmcp import FastMCP |
10 | 11 |
|
11 | 12 | # Import resource handlers |
12 | 13 | from kicad_mcp.resources.projects import register_project_resources |
@@ -127,9 +128,11 @@ def create_server() -> FastMCP: |
127 | 128 | # Always print this now, as we rely on CLI |
128 | 129 | logging.info(f"KiCad Python module setup removed; relying on kicad-cli for external operations.") |
129 | 130 |
|
| 131 | + # Build a lifespan callable with the kwarg baked in (FastMCP 2.x dropped lifespan_kwargs) |
| 132 | + lifespan_factory = functools.partial(kicad_lifespan, kicad_modules_available=kicad_modules_available) |
| 133 | + |
130 | 134 | # Initialize FastMCP server |
131 | | - # Pass the availability flag (always False now) to the lifespan context |
132 | | - mcp = FastMCP("KiCad", lifespan=kicad_lifespan, lifespan_kwargs={"kicad_modules_available": kicad_modules_available}) |
| 135 | + mcp = FastMCP("KiCad", lifespan=lifespan_factory) |
133 | 136 | logging.info(f"Created FastMCP server instance with lifespan management") |
134 | 137 |
|
135 | 138 | # Register resources |
@@ -186,3 +189,43 @@ def cleanup_temp_dirs(): |
186 | 189 |
|
187 | 190 | logging.info(f"Server initialization complete") |
188 | 191 | return mcp |
| 192 | + |
| 193 | + |
| 194 | +def setup_signal_handlers() -> None: |
| 195 | + """Setup signal handlers for graceful shutdown.""" |
| 196 | + # Signal handlers are set up in register_signal_handlers |
| 197 | + pass |
| 198 | + |
| 199 | + |
| 200 | +def cleanup_handler() -> None: |
| 201 | + """Handle cleanup during shutdown.""" |
| 202 | + run_cleanup_handlers() |
| 203 | + |
| 204 | + |
| 205 | +def setup_logging() -> None: |
| 206 | + """Configure logging for the server.""" |
| 207 | + logging.basicConfig( |
| 208 | + level=logging.INFO, |
| 209 | + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
| 210 | + ) |
| 211 | + |
| 212 | + |
| 213 | +def main() -> None: |
| 214 | + """Start the KiCad MCP server (blocking).""" |
| 215 | + setup_logging() |
| 216 | + logging.info("Starting KiCad MCP server...") |
| 217 | + |
| 218 | + server = create_server() |
| 219 | + |
| 220 | + try: |
| 221 | + server.run() # FastMCP manages its own event loop |
| 222 | + except KeyboardInterrupt: |
| 223 | + logging.info("Server interrupted by user") |
| 224 | + except Exception as e: |
| 225 | + logging.error(f"Server error: {e}") |
| 226 | + finally: |
| 227 | + logging.info("Server shutdown complete") |
| 228 | + |
| 229 | + |
| 230 | +if __name__ == "__main__": |
| 231 | + main() |
0 commit comments