Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions kicad_mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -186,3 +189,43 @@ def cleanup_temp_dirs():

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()
8 changes: 4 additions & 4 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

# 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 ---
Expand Down Expand Up @@ -70,10 +70,10 @@
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
27 changes: 19 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
[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",
"Programming Language :: Python :: 3.11",
"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"
"Bug Tracker" = "https://github.com/lamaalrajih/kicad-mcp/issues"
"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 = ["."]
Expand Down