kicad-mcp/kicad_mcp/tools/advanced_drc_tools.py
Ryan Malloy 995dfd57c1 Add comprehensive advanced KiCad features and fix MCP compatibility issues
- Implement 3D model analysis and mechanical constraints checking
- Add advanced DRC rule customization for HDI, RF, and automotive applications
- Create symbol library management with analysis and validation tools
- Implement PCB layer stack-up analysis with impedance calculations
- Fix Context parameter validation errors causing client failures
- Add enhanced tool annotations with examples for better LLM compatibility
- Include comprehensive test coverage improvements (22.21% coverage)
- Add CLAUDE.md documentation for development guidance

New Advanced Tools:
• 3D model analysis: analyze_3d_models, check_mechanical_constraints
• Advanced DRC: create_drc_rule_set, analyze_pcb_drc_violations
• Symbol management: analyze_symbol_library, validate_symbol_library
• Layer analysis: analyze_pcb_stackup, calculate_trace_impedance

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 15:57:46 -06:00

446 lines
17 KiB
Python

"""
Advanced DRC Tools for KiCad MCP Server.
Provides MCP tools for advanced Design Rule Check (DRC) functionality including
custom rule creation, specialized rule sets, and manufacturing constraint validation.
"""
import json
from typing import Any, Dict, List
from fastmcp import FastMCP
from kicad_mcp.utils.advanced_drc import (
create_drc_manager,
AdvancedDRCManager,
DRCRule,
RuleType,
RuleSeverity
)
from kicad_mcp.utils.path_validator import validate_kicad_file
def register_advanced_drc_tools(mcp: FastMCP) -> None:
"""Register advanced DRC tools with the MCP server."""
@mcp.tool()
def create_drc_rule_set(name: str, technology: str = "standard",
description: str = "") -> Dict[str, Any]:
"""
Create a new DRC rule set for a specific technology or application.
Generates optimized rule sets for different PCB technologies including
standard PCB, HDI, RF/microwave, and automotive applications.
Args:
name: Name for the rule set (e.g., "MyProject_Rules")
technology: Technology type - one of: "standard", "hdi", "rf", "automotive"
description: Optional description of the rule set
Returns:
Dictionary containing the created rule set information with rules list
Examples:
create_drc_rule_set("RF_Design", "rf", "Rules for RF circuit board")
create_drc_rule_set("Auto_ECU", "automotive", "Automotive ECU design rules")
"""
try:
manager = create_drc_manager()
# Create rule set based on technology
if technology.lower() == "hdi":
rule_set = manager.create_high_density_rules()
elif technology.lower() == "rf":
rule_set = manager.create_rf_rules()
elif technology.lower() == "automotive":
rule_set = manager.create_automotive_rules()
else:
# Create standard rules with custom name
rule_set = manager.rule_sets["standard"]
rule_set.name = name
rule_set.description = description or f"Standard PCB rules for {name}"
if name:
rule_set.name = name
if description:
rule_set.description = description
manager.add_rule_set(rule_set)
return {
"success": True,
"rule_set_name": rule_set.name,
"technology": technology,
"rule_count": len(rule_set.rules),
"description": rule_set.description,
"rules": [
{
"name": rule.name,
"type": rule.rule_type.value,
"severity": rule.severity.value,
"constraint": rule.constraint,
"enabled": rule.enabled
}
for rule in rule_set.rules
]
}
except Exception as e:
return {
"success": False,
"error": str(e),
"rule_set_name": name
}
@mcp.tool()
def create_custom_drc_rule(rule_name: str, rule_type: str, constraint: Dict[str, Any],
severity: str = "error", condition: str = None,
description: str = None) -> Dict[str, Any]:
"""
Create a custom DRC rule with specific constraints and conditions.
Allows creation of specialized DRC rules for unique design requirements
beyond standard manufacturing constraints.
Args:
rule_name: Name for the new rule
rule_type: Type of rule (clearance, track_width, via_size, etc.)
constraint: Dictionary of constraint parameters
severity: Rule severity (error, warning, info, ignore)
condition: Optional condition expression for when rule applies
description: Optional description of the rule
Returns:
Dictionary containing the created rule information and validation results
"""
try:
manager = create_drc_manager()
# Convert string enums
try:
rule_type_enum = RuleType(rule_type.lower())
except ValueError:
return {
"success": False,
"error": f"Invalid rule type: {rule_type}. Valid types: {[rt.value for rt in RuleType]}"
}
try:
severity_enum = RuleSeverity(severity.lower())
except ValueError:
return {
"success": False,
"error": f"Invalid severity: {severity}. Valid severities: {[s.value for s in RuleSeverity]}"
}
# Create the rule
rule = manager.create_custom_rule(
name=rule_name,
rule_type=rule_type_enum,
constraint=constraint,
severity=severity_enum,
condition=condition,
description=description
)
# Validate rule syntax
validation_errors = manager.validate_rule_syntax(rule)
return {
"success": True,
"rule": {
"name": rule.name,
"type": rule.rule_type.value,
"severity": rule.severity.value,
"constraint": rule.constraint,
"condition": rule.condition,
"description": rule.description,
"enabled": rule.enabled
},
"validation": {
"valid": len(validation_errors) == 0,
"errors": validation_errors
}
}
except Exception as e:
return {
"success": False,
"error": str(e),
"rule_name": rule_name
}
@mcp.tool()
def export_kicad_drc_rules(rule_set_name: str = "standard") -> Dict[str, Any]:
"""
Export DRC rules in KiCad-compatible format.
Converts internal rule set to KiCad DRC rule format that can be
imported into KiCad projects for automated checking.
Args:
rule_set_name: Name of the rule set to export (default: standard)
Returns:
Dictionary containing exported rules and KiCad-compatible rule text
"""
try:
manager = create_drc_manager()
# Export to KiCad format
kicad_rules = manager.export_kicad_drc_rules(rule_set_name)
rule_set = manager.rule_sets[rule_set_name]
return {
"success": True,
"rule_set_name": rule_set_name,
"kicad_rules": kicad_rules,
"rule_count": len(rule_set.rules),
"active_rules": len([r for r in rule_set.rules if r.enabled]),
"export_info": {
"format": "KiCad DRC Rules",
"version": rule_set.version,
"technology": rule_set.technology or "General",
"usage": "Copy the kicad_rules text to your KiCad project's custom DRC rules"
}
}
except Exception as e:
return {
"success": False,
"error": str(e),
"rule_set_name": rule_set_name
}
@mcp.tool()
def analyze_pcb_drc_violations(pcb_file_path: str, rule_set_name: str = "standard") -> Dict[str, Any]:
"""
Analyze a PCB file against advanced DRC rules and report violations.
Performs comprehensive DRC analysis using custom rule sets to identify
design issues beyond basic KiCad DRC checking.
Args:
pcb_file_path: Full path to the .kicad_pcb file to analyze
rule_set_name: Name of rule set to use ("standard", "hdi", "rf", "automotive", or custom)
Returns:
Dictionary with violation details, severity levels, and recommendations
Examples:
analyze_pcb_drc_violations("/path/to/project.kicad_pcb", "rf")
analyze_pcb_drc_violations("/path/to/board.kicad_pcb") # uses standard rules
"""
try:
validated_path = validate_kicad_file(pcb_file_path, "pcb")
manager = create_drc_manager()
# Perform DRC analysis
analysis = manager.analyze_pcb_for_rule_violations(validated_path, rule_set_name)
# Get rule set info
rule_set = manager.rule_sets.get(rule_set_name)
return {
"success": True,
"pcb_file": validated_path,
"analysis": analysis,
"rule_set_info": {
"name": rule_set.name if rule_set else "Unknown",
"technology": rule_set.technology if rule_set else None,
"description": rule_set.description if rule_set else None,
"total_rules": len(rule_set.rules) if rule_set else 0
}
}
except Exception as e:
return {
"success": False,
"error": str(e),
"pcb_file": pcb_file_path
}
@mcp.tool()
def get_manufacturing_constraints(technology: str = "standard") -> Dict[str, Any]:
"""
Get manufacturing constraints for a specific PCB technology.
Provides manufacturing limits and guidelines for different PCB
technologies to help with design rule creation.
Args:
technology: Technology type (standard, hdi, rf, automotive)
Returns:
Dictionary containing manufacturing constraints and recommendations
"""
try:
manager = create_drc_manager()
constraints = manager.generate_manufacturing_constraints(technology)
# Add recommendations based on technology
recommendations = {
"standard": [
"Maintain 0.1mm minimum track width for cost-effective manufacturing",
"Use 0.2mm clearance for reliable production yields",
"Consider 6-layer maximum for standard processes"
],
"hdi": [
"Use microvias for high-density routing",
"Maintain controlled impedance for signal integrity",
"Consider sequential build-up for complex designs"
],
"rf": [
"Maintain consistent dielectric properties",
"Use ground via stitching for EMI control",
"Control trace geometry for impedance matching"
],
"automotive": [
"Design for extended temperature range operation",
"Increase clearances for vibration resistance",
"Use thermal management for high-power components"
]
}
return {
"success": True,
"technology": technology,
"constraints": constraints,
"recommendations": recommendations.get(technology, recommendations["standard"]),
"applicable_standards": {
"automotive": ["ISO 26262", "AEC-Q100"],
"rf": ["IPC-2221", "IPC-2141"],
"hdi": ["IPC-2226", "IPC-6016"],
"standard": ["IPC-2221", "IPC-2222"]
}.get(technology, [])
}
except Exception as e:
return {
"success": False,
"error": str(e),
"technology": technology
}
@mcp.tool()
def list_available_rule_sets() -> Dict[str, Any]:
"""
List all available DRC rule sets and their properties.
Provides information about built-in and custom rule sets available
for DRC analysis and export.
Returns:
Dictionary containing all available rule sets with their metadata
"""
try:
manager = create_drc_manager()
rule_set_names = manager.get_rule_set_names()
rule_sets_info = []
for name in rule_set_names:
rule_set = manager.rule_sets[name]
rule_sets_info.append({
"name": rule_set.name,
"key": name,
"version": rule_set.version,
"description": rule_set.description,
"technology": rule_set.technology,
"rule_count": len(rule_set.rules),
"active_rules": len([r for r in rule_set.rules if r.enabled]),
"rule_types": list(set(r.rule_type.value for r in rule_set.rules))
})
return {
"success": True,
"rule_sets": rule_sets_info,
"total_rule_sets": len(rule_set_names),
"active_rule_set": manager.active_rule_set,
"supported_technologies": ["standard", "hdi", "rf", "automotive"]
}
except Exception as e:
return {
"success": False,
"error": str(e)
}
@mcp.tool()
def validate_drc_rule_syntax(rule_definition: Dict[str, Any]) -> Dict[str, Any]:
"""
Validate the syntax and parameters of a DRC rule definition.
Checks rule definition for proper syntax, valid constraints,
and logical consistency before rule creation.
Args:
rule_definition: Dictionary containing rule parameters to validate
Returns:
Dictionary containing validation results and error details
"""
try:
manager = create_drc_manager()
# Extract rule parameters
rule_name = rule_definition.get("name", "")
rule_type = rule_definition.get("type", "")
constraint = rule_definition.get("constraint", {})
severity = rule_definition.get("severity", "error")
condition = rule_definition.get("condition")
description = rule_definition.get("description")
# Validate required fields
validation_errors = []
if not rule_name:
validation_errors.append("Rule name is required")
if not rule_type:
validation_errors.append("Rule type is required")
elif rule_type not in [rt.value for rt in RuleType]:
validation_errors.append(f"Invalid rule type: {rule_type}")
if not constraint:
validation_errors.append("Constraint parameters are required")
if severity not in [s.value for s in RuleSeverity]:
validation_errors.append(f"Invalid severity: {severity}")
# If basic validation passes, create temporary rule for detailed validation
if not validation_errors:
try:
temp_rule = manager.create_custom_rule(
name=rule_name,
rule_type=RuleType(rule_type),
constraint=constraint,
severity=RuleSeverity(severity),
condition=condition,
description=description
)
# Validate rule syntax
syntax_errors = manager.validate_rule_syntax(temp_rule)
validation_errors.extend(syntax_errors)
except Exception as e:
validation_errors.append(f"Rule creation failed: {str(e)}")
return {
"success": True,
"valid": len(validation_errors) == 0,
"errors": validation_errors,
"rule_definition": rule_definition,
"validation_summary": {
"total_errors": len(validation_errors),
"critical_errors": len([e for e in validation_errors if "required" in e.lower()]),
"syntax_errors": len([e for e in validation_errors if "syntax" in e.lower() or "condition" in e.lower()])
}
}
except Exception as e:
return {
"success": False,
"error": str(e),
"rule_definition": rule_definition
}