kicad-mcp/src/mckicad/config.py
Ryan Malloy ad7022916c
Some checks are pending
CI / Lint and Format (push) Waiting to run
CI / Test Python 3.11 on macos-latest (push) Waiting to run
CI / Test Python 3.12 on macos-latest (push) Waiting to run
CI / Test Python 3.13 on macos-latest (push) Waiting to run
CI / Test Python 3.10 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.11 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.12 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.13 on ubuntu-latest (push) Waiting to run
CI / Security Scan (push) Waiting to run
CI / Build Package (push) Blocked by required conditions
Add label auto-offset with per-connection stub_length and direction overrides
Default stub_length increased from 2.54mm to 7.62mm (3 grid units)
so labels clear component bodies. Per-connection stub_length and
direction overrides added for edge cases where auto-placement puts
labels in bad spots.
2026-03-08 23:58:03 -06:00

162 lines
4.4 KiB
Python

"""
Configuration for the mckicad MCP server.
All config is accessed via functions to avoid module-level os.environ.get()
race conditions with .env loading.
"""
import os
import platform
def get_system() -> str:
"""Get the current operating system name."""
return platform.system()
def get_kicad_user_dir() -> str:
"""Get KiCad user documents directory, respecting env override."""
env_val = os.environ.get("KICAD_USER_DIR")
if env_val:
return os.path.expanduser(env_val)
system = get_system()
if system == "Darwin" or system == "Windows":
return os.path.expanduser("~/Documents/KiCad")
elif system == "Linux":
return os.path.expanduser("~/KiCad")
return os.path.expanduser("~/Documents/KiCad")
def get_kicad_app_path() -> str:
"""Get KiCad application installation path, respecting env override."""
env_val = os.environ.get("KICAD_APP_PATH")
if env_val:
return env_val
_app_paths = {
"Darwin": "/Applications/KiCad/KiCad.app",
"Windows": r"C:\Program Files\KiCad",
"Linux": "/usr/share/kicad",
}
return _app_paths.get(get_system(), "/Applications/KiCad/KiCad.app")
def get_search_paths() -> list[str]:
"""Read KICAD_SEARCH_PATHS from env, expand ~, filter to existing dirs."""
paths: list[str] = []
env_val = os.environ.get("KICAD_SEARCH_PATHS", "")
if env_val:
for p in env_val.split(","):
expanded = os.path.expanduser(p.strip())
if os.path.isdir(expanded) and expanded not in paths:
paths.append(expanded)
# Auto-detect common project locations
default_locations = [
"~/Documents/PCB",
"~/PCB",
"~/Electronics",
"~/Projects/Electronics",
"~/Projects/PCB",
"~/Projects/KiCad",
]
for loc in default_locations:
expanded = os.path.expanduser(loc)
if os.path.isdir(expanded) and expanded not in paths:
paths.append(expanded)
return paths
# --- Static configuration (no env dependency) ---
KICAD_EXTENSIONS = {
"project": ".kicad_pro",
"pcb": ".kicad_pcb",
"schematic": ".kicad_sch",
"design_rules": ".kicad_dru",
"worksheet": ".kicad_wks",
"footprint": ".kicad_mod",
"netlist": "_netlist.net",
"kibot_config": ".kibot.yaml",
}
DATA_EXTENSIONS = [".csv", ".pos", ".net", ".zip", ".drl"]
INLINE_RESULT_THRESHOLD = 20
TIMEOUT_CONSTANTS = {
"kicad_cli_version_check": 10.0,
"kicad_cli_export": 30.0,
"application_open": 10.0,
"subprocess_default": 30.0,
}
COMMON_LIBRARIES = {
"basic": {
"resistor": {"library": "Device", "symbol": "R"},
"capacitor": {"library": "Device", "symbol": "C"},
"inductor": {"library": "Device", "symbol": "L"},
"led": {"library": "Device", "symbol": "LED"},
"diode": {"library": "Device", "symbol": "D"},
},
"power": {
"vcc": {"library": "power", "symbol": "VCC"},
"gnd": {"library": "power", "symbol": "GND"},
"+5v": {"library": "power", "symbol": "+5V"},
"+3v3": {"library": "power", "symbol": "+3V3"},
},
"connectors": {
"conn_2pin": {"library": "Connector", "symbol": "Conn_01x02_Male"},
"conn_4pin": {"library": "Connector_Generic", "symbol": "Conn_01x04"},
},
}
POWER_SYMBOL_DEFAULTS = {
"stub_length": 5.08,
"grid_snap": 2.54,
"fine_grid": 1.27,
}
DECOUPLING_DEFAULTS = {
"cols": 6,
"h_spacing": 12.7,
"v_spacing": 15.0,
"offset_below_ic": 20.0,
}
BATCH_LIMITS = {
"max_components": 500,
"max_wires": 1000,
"max_labels": 500,
"max_total_operations": 2000,
}
LABEL_DEFAULTS = {
"stub_length": 7.62, # 3 grid units (2.54mm each), clears component bodies
}
AUTOWIRE_DEFAULTS = {
"direct_wire_max_distance": 50.0,
"crossing_threshold": 2,
"high_fanout_threshold": 5,
"label_min_distance": 10.0,
}
DEFAULT_FOOTPRINTS = {
"R": [
"Resistor_SMD:R_0805_2012Metric",
"Resistor_SMD:R_0603_1608Metric",
"Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal",
],
"C": [
"Capacitor_SMD:C_0805_2012Metric",
"Capacitor_SMD:C_0603_1608Metric",
"Capacitor_THT:C_Disc_D5.0mm_W2.5mm_P5.00mm",
],
"LED": ["LED_SMD:LED_0805_2012Metric", "LED_THT:LED_D5.0mm"],
"D": ["Diode_SMD:D_SOD-123", "Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal"],
}