""" Project management tools for KiCad MCP server. Provides tools for discovering, inspecting, and opening KiCad projects on the local filesystem. """ import logging import os from typing import Any from mckicad.server import mcp from mckicad.utils.file_utils import get_project_files, load_project_json from mckicad.utils.kicad_utils import find_kicad_projects, open_kicad_project logger = logging.getLogger(__name__) @mcp.tool() def list_projects() -> dict[str, Any]: """Find and list all KiCad projects in configured search paths. Scans KICAD_SEARCH_PATHS and default project directories for .kicad_pro files. Returns project name, path, relative path, and last-modified timestamp for each discovered project. Returns: Dictionary with success status, project list, and count. """ logger.info("Scanning for KiCad projects") try: projects = find_kicad_projects() logger.info("Found %d KiCad project(s)", len(projects)) return { "success": True, "data": projects, "count": len(projects), "error": None, } except Exception as e: logger.error("Failed to list projects: %s", e) return { "success": False, "data": [], "count": 0, "error": str(e), } @mcp.tool() def get_project_structure(project_path: str) -> dict[str, Any]: """Get the file structure and metadata of a KiCad project. Enumerates all files associated with a .kicad_pro project file (schematic, PCB, netlist, BOM exports, etc.) and loads project metadata from the JSON project file. Args: project_path: Absolute path to the .kicad_pro file. Returns: Dictionary with project name, directory, file map, and metadata. """ logger.info("Getting project structure for: %s", project_path) if not os.path.exists(project_path): logger.warning("Project file not found: %s", project_path) return { "success": False, "data": None, "error": f"Project not found: {project_path}", } try: project_dir = os.path.dirname(project_path) # Strip .kicad_pro extension to get the project name basename = os.path.basename(project_path) project_name = basename.rsplit(".kicad_pro", 1)[0] if basename.endswith(".kicad_pro") else basename files = get_project_files(project_path) metadata = {} project_data = load_project_json(project_path) if project_data and "metadata" in project_data: metadata = project_data["metadata"] logger.info( "Project '%s' has %d associated file(s)", project_name, len(files) ) return { "success": True, "data": { "name": project_name, "path": project_path, "directory": project_dir, "files": files, "metadata": metadata, }, "error": None, } except Exception as e: logger.error("Failed to get project structure for %s: %s", project_path, e) return { "success": False, "data": None, "error": str(e), } @mcp.tool() def open_project(project_path: str) -> dict[str, Any]: """Open a KiCad project in the KiCad application. Launches KiCad (or the system default handler) with the specified .kicad_pro file. Uses platform-appropriate open commands (open on macOS, xdg-open on Linux). Args: project_path: Absolute path to the .kicad_pro file. Returns: Dictionary with success status and any error output. """ logger.info("Opening project: %s", project_path) result = open_kicad_project(project_path) if result.get("success"): logger.info("Project opened successfully: %s", project_path) else: logger.warning("Failed to open project: %s", result.get("error")) return result