Skip to main content
Glama

run_drc_check

Perform Design Rule Check on KiCad PCB files to validate manufacturing compliance and identify potential layout issues before production.

Instructions

Run a Design Rule Check on a KiCad PCB file.

Args: project_path: Path to the KiCad project file (.kicad_pro) ctx: MCP context for progress reporting

Returns: Dictionary with DRC results and statistics

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_pathYes
ctxYes

Implementation Reference

  • The primary handler for the 'run_drc_check' tool. Orchestrates the DRC process by locating the PCB file, invoking the CLI helper, saving results to history, comparing with previous runs, and reporting progress.
    @mcp.tool() async def run_drc_check(project_path: str, ctx: Context | None) -> Dict[str, Any]: """Run a Design Rule Check on a KiCad PCB file. Args: project_path: Path to the KiCad project file (.kicad_pro) ctx: MCP context for progress reporting Returns: Dictionary with DRC results and statistics """ print(f"Running DRC check for project: {project_path}") if not os.path.exists(project_path): print(f"Project not found: {project_path}") return {"success": False, "error": f"Project not found: {project_path}"} # Get PCB file from project files = get_project_files(project_path) if "pcb" not in files: print("PCB file not found in project") return {"success": False, "error": "PCB file not found in project"} pcb_file = files["pcb"] print(f"Found PCB file: {pcb_file}") # Report progress to user if ctx: await ctx.report_progress(10, 100) ctx.info(f"Starting DRC check on {os.path.basename(pcb_file)}") # Run DRC using the appropriate approach drc_results = None print("Using kicad-cli for DRC") if ctx: ctx.info("Using KiCad CLI for DRC check...") # logging.info(f"[DRC] Calling run_drc_via_cli for {pcb_file}") # <-- Remove log drc_results = await run_drc_via_cli(pcb_file, ctx) # logging.info(f"[DRC] run_drc_via_cli finished for {pcb_file}") # <-- Remove log # Process and save results if successful if drc_results and drc_results.get("success", False): # logging.info(f"[DRC] DRC check successful for {pcb_file}. Saving results.") # <-- Remove log # Save results to history save_drc_result(project_path, drc_results) # Add comparison with previous run comparison = compare_with_previous(project_path, drc_results) if comparison: drc_results["comparison"] = comparison if ctx: if comparison["change"] < 0: ctx.info(f"Great progress! You've fixed {abs(comparison['change'])} DRC violations since the last check.") elif comparison["change"] > 0: ctx.info(f"Found {comparison['change']} new DRC violations since the last check.") else: ctx.info(f"No change in the number of DRC violations since the last check.") elif drc_results: # logging.warning(f"[DRC] DRC check reported failure for {pcb_file}: {drc_results.get('error')}") # <-- Remove log # Pass or print a warning if needed pass else: # logging.error(f"[DRC] DRC check returned None for {pcb_file}") # <-- Remove log # Pass or print an error if needed pass # Complete progress if ctx: await ctx.report_progress(100, 100) return drc_results or { "success": False, "error": "DRC check failed with an unknown error" }
  • Core helper function that executes the kicad-cli 'pcb drc' command with JSON output, parses the results, categorizes violations by type, and returns structured data.
    async def run_drc_via_cli(pcb_file: str, ctx: Context | None) -> Dict[str, Any]: """Run DRC using KiCad command line tools. Args: pcb_file: Path to the PCB file (.kicad_pcb) ctx: MCP context for progress reporting Returns: Dictionary with DRC results """ results = { "success": False, "method": "cli", "pcb_file": pcb_file } try: # Create a temporary directory for the output with tempfile.TemporaryDirectory() as temp_dir: # Output file for DRC report output_file = os.path.join(temp_dir, "drc_report.json") # Find kicad-cli executable kicad_cli = find_kicad_cli() if not kicad_cli: print("kicad-cli not found in PATH or common installation locations") results["error"] = "kicad-cli not found. Please ensure KiCad 9.0+ is installed and kicad-cli is available." return results # Report progress if ctx: await ctx.report_progress(50, 100) ctx.info("Running DRC using KiCad CLI...") # Build the DRC command cmd = [ kicad_cli, "pcb", "drc", "--format", "json", "--output", output_file, pcb_file ] print(f"Running command: {' '.join(cmd)}") process = subprocess.run(cmd, capture_output=True, text=True) # Check if the command was successful if process.returncode != 0: print(f"DRC command failed with code {process.returncode}") print(f"Error output: {process.stderr}") results["error"] = f"DRC command failed: {process.stderr}" return results # Check if the output file was created if not os.path.exists(output_file): print("DRC report file not created") results["error"] = "DRC report file not created" return results # Read the DRC report with open(output_file, 'r') as f: try: drc_report = json.load(f) except json.JSONDecodeError: print("Failed to parse DRC report JSON") results["error"] = "Failed to parse DRC report JSON" return results # Process the DRC report violations = drc_report.get("violations", []) violation_count = len(violations) print(f"DRC completed with {violation_count} violations") if ctx: await ctx.report_progress(70, 100) ctx.info(f"DRC completed with {violation_count} violations") # Categorize violations by type error_types = {} for violation in violations: error_type = violation.get("message", "Unknown") if error_type not in error_types: error_types[error_type] = 0 error_types[error_type] += 1 # Create success response results = { "success": True, "method": "cli", "pcb_file": pcb_file, "total_violations": violation_count, "violation_categories": error_types, "violations": violations } if ctx: await ctx.report_progress(90, 100) return results except Exception as e: print(f"Error in CLI DRC: {str(e)}", exc_info=True) results["error"] = f"Error in CLI DRC: {str(e)}" return results
  • Registers the DRC tools module, which includes the run_drc_check tool, with the FastMCP server instance.
    register_drc_tools(mcp)
  • Utility function to locate the kicad-cli executable across different operating systems and common installation paths.
    def find_kicad_cli() -> Optional[str]: """Find the kicad-cli executable in the system PATH. Returns: Path to kicad-cli if found, None otherwise """ # Check if kicad-cli is in PATH try: if system == "Windows": # On Windows, check for kicad-cli.exe result = subprocess.run(["where", "kicad-cli.exe"], capture_output=True, text=True) if result.returncode == 0: return result.stdout.strip().split("\n")[0] else: # On Unix-like systems, use which result = subprocess.run(["which", "kicad-cli"], capture_output=True, text=True) if result.returncode == 0: return result.stdout.strip() except Exception as e: print(f"Error finding kicad-cli: {str(e)}") # If we get here, kicad-cli is not in PATH # Try common installation locations if system == "Windows": # Common Windows installation path potential_paths = [ r"C:\Program Files\KiCad\bin\kicad-cli.exe", r"C:\Program Files (x86)\KiCad\bin\kicad-cli.exe" ] elif system == "Darwin": # macOS # Common macOS installation paths potential_paths = [ "/Applications/KiCad/KiCad.app/Contents/MacOS/kicad-cli", "/Applications/KiCad/kicad-cli" ] else: # Linux and other Unix-like systems # Common Linux installation paths potential_paths = [ "/usr/bin/kicad-cli", "/usr/local/bin/kicad-cli", "/opt/kicad/bin/kicad-cli" ] # Check each potential path for path in potential_paths: if os.path.exists(path) and os.access(path, os.X_OK): return path # If still not found, return None return None

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lamaalrajih/kicad-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server