diff --git a/kicad_mcp/server.py b/kicad_mcp/server.py index b1d9289..5c5de67 100644 --- a/kicad_mcp/server.py +++ b/kicad_mcp/server.py @@ -5,8 +5,9 @@ import atexit import os import signal import logging +import functools from typing import Callable -from mcp.server.fastmcp import FastMCP +from fastmcp import FastMCP # Import resource handlers from kicad_mcp.resources.projects import register_project_resources @@ -127,9 +128,11 @@ def create_server() -> FastMCP: # Always print this now, as we rely on CLI logging.info(f"KiCad Python module setup removed; relying on kicad-cli for external operations.") + # Build a lifespan callable with the kwarg baked in (FastMCP 2.x dropped lifespan_kwargs) + lifespan_factory = functools.partial(kicad_lifespan, kicad_modules_available=kicad_modules_available) + # Initialize FastMCP server - # Pass the availability flag (always False now) to the lifespan context - mcp = FastMCP("KiCad", lifespan=kicad_lifespan, lifespan_kwargs={"kicad_modules_available": kicad_modules_available}) + mcp = FastMCP("KiCad", lifespan=lifespan_factory) logging.info(f"Created FastMCP server instance with lifespan management") # Register resources @@ -186,3 +189,43 @@ def create_server() -> FastMCP: logging.info(f"Server initialization complete") return mcp + + +def setup_signal_handlers() -> None: + """Setup signal handlers for graceful shutdown.""" + # Signal handlers are set up in register_signal_handlers + pass + + +def cleanup_handler() -> None: + """Handle cleanup during shutdown.""" + run_cleanup_handlers() + + +def setup_logging() -> None: + """Configure logging for the server.""" + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' + ) + + +def main() -> None: + """Start the KiCad MCP server (blocking).""" + setup_logging() + logging.info("Starting KiCad MCP server...") + + server = create_server() + + try: + server.run() # FastMCP manages its own event loop + except KeyboardInterrupt: + logging.info("Server interrupted by user") + except Exception as e: + logging.error(f"Server error: {e}") + finally: + logging.info("Server shutdown complete") + + +if __name__ == "__main__": + main() diff --git a/main.py b/main.py index 3be66b8..6860fe0 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,7 @@ import logging # Import logging module # Must import config BEFORE env potentially overrides it via os.environ from kicad_mcp.config import KICAD_USER_DIR, ADDITIONAL_SEARCH_PATHS -from kicad_mcp.server import create_server +from kicad_mcp.server import main as server_main from kicad_mcp.utils.env import load_dotenv # --- Setup Logging --- @@ -70,10 +70,10 @@ if __name__ == "__main__": else: logging.info(f"No additional search paths configured") # Changed print to logging - # Create and run server - server = create_server() + # Run server logging.info(f"Running server with stdio transport") # Changed print to logging - server.run(transport='stdio') + import asyncio + asyncio.run(server_main()) except Exception as e: logging.exception(f"Unhandled exception in main") # Log exception details raise diff --git a/pyproject.toml b/pyproject.toml index 3d45ff5..a58d2ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,22 @@ [build-system] -requires = ["setuptools>=61.0", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["hatchling"] +build-backend = "hatchling.build" [project] name = "kicad-mcp" version = "0.1.0" -authors = [{ name = "Lama Al Rajih" }] -description = "Model Context Protocol server for KiCad on Mac, Windows, and Linux" -license = { text = "MIT" } +description = "Model Context Protocol (MCP) server for KiCad electronic design automation (EDA) files" readme = "README.md" +license = { text = "MIT" } +authors = [ + { name = "KiCad MCP Contributors" } +] requires-python = ">=3.10" +dependencies = [ + "mcp[cli]>=1.0.0", + "fastmcp>=0.1.0", + "pandas>=2.0.0", +] classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", @@ -17,12 +24,10 @@ classifiers = [ "Programming Language :: Python :: 3.12", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", - "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", ] -dependencies = ["mcp[cli]>=1.11.0", "pandas>=2.3.1", "pytest>=8.4.1"] [project.urls] "Homepage" = "https://github.com/lamaalrajih/kicad-mcp" @@ -30,7 +35,13 @@ dependencies = ["mcp[cli]>=1.11.0", "pandas>=2.3.1", "pytest>=8.4.1"] "Documentation" = "https://github.com/lamaalrajih/kicad-mcp#readme" [project.scripts] -kicad-mcp = "kicad_mcp.main:main" +kicad-mcp = "kicad_mcp.server:main" + +[dependency-groups] +dev = [ + "pytest>=7.0.0", + "pytest-asyncio>=0.23.0", +] [tool.setuptools.packages.find] where = ["."]