kcaa 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kcaa/__init__.py +29 -0
- kcaa/config.py +328 -0
- kcaa/context.py +85 -0
- kcaa/prompts/__init__.py +3 -0
- kcaa/prompts/bom_prompts.py +117 -0
- kcaa/prompts/drc_prompt.py +49 -0
- kcaa/prompts/pattern_prompts.py +145 -0
- kcaa/prompts/templates.py +59 -0
- kcaa/resources/__init__.py +3 -0
- kcaa/resources/bom_resources.py +281 -0
- kcaa/resources/drc_resources.py +255 -0
- kcaa/resources/files.py +46 -0
- kcaa/resources/netlist_resources.py +253 -0
- kcaa/resources/pattern_resources.py +294 -0
- kcaa/resources/projects.py +51 -0
- kcaa/server.py +304 -0
- kcaa/tools/__init__.py +9 -0
- kcaa/tools/analysis_tools.py +51 -0
- kcaa/tools/bom_tools.py +787 -0
- kcaa/tools/component_edit_tools.py +2037 -0
- kcaa/tools/drc_impl/__init__.py +3 -0
- kcaa/tools/drc_impl/cli_drc.py +168 -0
- kcaa/tools/drc_tools.py +140 -0
- kcaa/tools/export_tools.py +227 -0
- kcaa/tools/kipy_tools.py +280 -0
- kcaa/tools/netlist_tools.py +486 -0
- kcaa/tools/pattern_tools.py +196 -0
- kcaa/tools/pcb_edit_tools.py +443 -0
- kcaa/tools/pcb_group_tools.py +1541 -0
- kcaa/tools/pcb_library_tools.py +413 -0
- kcaa/tools/pcb_placement_helpers.py +1361 -0
- kcaa/tools/pcb_placement_tools.py +456 -0
- kcaa/tools/pcb_query_tools.py +850 -0
- kcaa/tools/pcb_zone_tools.py +492 -0
- kcaa/tools/placement_helpers.py +379 -0
- kcaa/tools/project_tools.py +59 -0
- kcaa/tools/symbol_tools.py +603 -0
- kcaa/tools/validation_tools.py +298 -0
- kcaa/tools/version_tools.py +133 -0
- kcaa/tools/wire_edit_tools.py +1410 -0
- kcaa/utils/__init__.py +3 -0
- kcaa/utils/boundary_validator.py +365 -0
- kcaa/utils/component_utils.py +433 -0
- kcaa/utils/drc_history.py +181 -0
- kcaa/utils/env.py +121 -0
- kcaa/utils/file_utils.py +71 -0
- kcaa/utils/footprint_database.py +464 -0
- kcaa/utils/footprint_index_manager.py +351 -0
- kcaa/utils/kicad_api_detection.py +70 -0
- kcaa/utils/kicad_cli.py +241 -0
- kcaa/utils/kicad_utils.py +122 -0
- kcaa/utils/kipy_reload.py +136 -0
- kcaa/utils/netlist_parser.py +539 -0
- kcaa/utils/path_validator.py +226 -0
- kcaa/utils/pattern_recognition.py +859 -0
- kcaa/utils/pcb_board_utils.py +422 -0
- kcaa/utils/pcb_footprint_utils.py +237 -0
- kcaa/utils/pcb_library_utils.py +351 -0
- kcaa/utils/pcb_sexp_utils.py +72 -0
- kcaa/utils/schematic_sexp_utils.py +28 -0
- kcaa/utils/secure_subprocess.py +294 -0
- kcaa/utils/skip_helpers.py +158 -0
- kcaa/utils/symbol_database.py +500 -0
- kcaa/utils/symbol_extractor.py +196 -0
- kcaa/utils/symbol_geometry.py +463 -0
- kcaa/utils/symbol_index_manager.py +490 -0
- kcaa/utils/symbol_index_reader.py +137 -0
- kcaa/utils/temp_dir_manager.py +24 -0
- kcaa/utils/version_manager.py +143 -0
- kcaa-0.1.0.dist-info/METADATA +291 -0
- kcaa-0.1.0.dist-info/RECORD +74 -0
- kcaa-0.1.0.dist-info/WHEEL +4 -0
- kcaa-0.1.0.dist-info/entry_points.txt +2 -0
- kcaa-0.1.0.dist-info/licenses/LICENSE +21 -0
kcaa/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
KiCad MCP Server.
|
|
3
|
+
|
|
4
|
+
A Model Context Protocol (MCP) server for KiCad electronic design automation (EDA) files.
|
|
5
|
+
"""
|
|
6
|
+
from .server import *
|
|
7
|
+
from .config import *
|
|
8
|
+
from .context import *
|
|
9
|
+
|
|
10
|
+
__version__ = "0.1.0"
|
|
11
|
+
__author__ = "Lama Al Rajih"
|
|
12
|
+
__description__ = "Model Context Protocol server for KiCad on Mac, Windows, and Linux"
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
# Package metadata
|
|
16
|
+
"__version__",
|
|
17
|
+
"__author__",
|
|
18
|
+
"__description__",
|
|
19
|
+
|
|
20
|
+
# Server creation / shutdown helpers
|
|
21
|
+
"create_server",
|
|
22
|
+
"add_cleanup_handler",
|
|
23
|
+
"run_cleanup_handlers",
|
|
24
|
+
"shutdown_server",
|
|
25
|
+
|
|
26
|
+
# Lifespan / context helpers
|
|
27
|
+
"kicad_lifespan",
|
|
28
|
+
"KiCadAppContext",
|
|
29
|
+
]
|
kcaa/config.py
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration settings for the KiCad MCP server.
|
|
3
|
+
|
|
4
|
+
This module provides platform-specific configuration for KiCad integration,
|
|
5
|
+
including file paths, extensions, component libraries, and operational constants.
|
|
6
|
+
All settings are determined at import time based on the operating system.
|
|
7
|
+
|
|
8
|
+
Module Variables:
|
|
9
|
+
system (str): Operating system name from platform.system()
|
|
10
|
+
KICAD_VERSION (str): KiCad version string used to construct versioned paths
|
|
11
|
+
KICAD_USER_DIR (str): User's KiCad documents directory
|
|
12
|
+
KICAD_APP_PATH (str): KiCad application installation path
|
|
13
|
+
ADDITIONAL_SEARCH_PATHS (List[str]): Additional project search locations
|
|
14
|
+
DEFAULT_PROJECT_LOCATIONS (List[str]): Common project directory patterns
|
|
15
|
+
KICAD_PYTHON_BASE (str): KiCad Python framework base path (macOS only)
|
|
16
|
+
KICAD_EXTENSIONS (Dict[str, str]): KiCad file extension mappings
|
|
17
|
+
DATA_EXTENSIONS (List[str]): Recognized data file extensions
|
|
18
|
+
CIRCUIT_DEFAULTS (Dict[str, Union[float, List[float]]]): Default circuit parameters
|
|
19
|
+
COMMON_LIBRARIES (Dict[str, Dict[str, Dict[str, str]]]): Component library mappings
|
|
20
|
+
DEFAULT_FOOTPRINTS (Dict[str, List[str]]): Default footprint suggestions per component
|
|
21
|
+
TIMEOUT_CONSTANTS (Dict[str, float]): Operation timeout values in seconds
|
|
22
|
+
PROGRESS_CONSTANTS (Dict[str, int]): Progress reporting percentage values
|
|
23
|
+
DISPLAY_CONSTANTS (Dict[str, int]): UI display configuration values
|
|
24
|
+
LibraryPathConfig: Configuration class for symbol library paths and settings
|
|
25
|
+
|
|
26
|
+
Platform Support:
|
|
27
|
+
- macOS (Darwin): Full support with application bundle paths
|
|
28
|
+
- Windows: Standard installation paths
|
|
29
|
+
- Linux: System package paths
|
|
30
|
+
- Unknown: Defaults to macOS paths for compatibility
|
|
31
|
+
|
|
32
|
+
Dependencies:
|
|
33
|
+
- os: File system operations and environment variables
|
|
34
|
+
- platform: Operating system detection
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
import logging
|
|
38
|
+
import os
|
|
39
|
+
import platform
|
|
40
|
+
|
|
41
|
+
log = logging.getLogger(__name__)
|
|
42
|
+
|
|
43
|
+
# Determine operating system for platform-specific configuration
|
|
44
|
+
# Returns 'Darwin' (macOS), 'Windows', 'Linux', or other
|
|
45
|
+
system = platform.system()
|
|
46
|
+
|
|
47
|
+
# Platform-specific KiCad installation and user directory paths
|
|
48
|
+
# These paths are used for finding KiCad resources and user projects
|
|
49
|
+
if system == "Darwin": # macOS
|
|
50
|
+
KICAD_USER_DIR = os.path.expanduser("~/Documents/KiCad")
|
|
51
|
+
KICAD_APP_PATH = "/Applications/KiCad/KiCad.app"
|
|
52
|
+
elif system == "Windows":
|
|
53
|
+
KICAD_USER_DIR = os.path.expanduser("~/Documents/KiCad")
|
|
54
|
+
KICAD_APP_PATH = r"C:\Program Files\KiCad"
|
|
55
|
+
elif system == "Linux":
|
|
56
|
+
KICAD_USER_DIR = os.path.expanduser("~/KiCad")
|
|
57
|
+
KICAD_APP_PATH = "/usr/share/kicad"
|
|
58
|
+
else:
|
|
59
|
+
# Default to macOS paths if system is unknown for maximum compatibility
|
|
60
|
+
# This ensures the server can start even on unrecognized platforms
|
|
61
|
+
KICAD_USER_DIR = os.path.expanduser("~/Documents/KiCad")
|
|
62
|
+
KICAD_APP_PATH = "/Applications/KiCad/KiCad.app"
|
|
63
|
+
|
|
64
|
+
# Additional search paths from environment variable KICAD_SEARCH_PATHS
|
|
65
|
+
# Users can specify custom project locations as comma-separated paths
|
|
66
|
+
ADDITIONAL_SEARCH_PATHS = []
|
|
67
|
+
env_search_paths = os.environ.get("KICAD_SEARCH_PATHS", "")
|
|
68
|
+
if env_search_paths:
|
|
69
|
+
for path in env_search_paths.split(","):
|
|
70
|
+
expanded_path = os.path.expanduser(path.strip()) # Expand ~ and variables
|
|
71
|
+
if os.path.exists(expanded_path): # Only add existing directories
|
|
72
|
+
ADDITIONAL_SEARCH_PATHS.append(expanded_path)
|
|
73
|
+
|
|
74
|
+
# Auto-detect common project locations for convenient project discovery
|
|
75
|
+
# These are typical directory names users create for electronics projects
|
|
76
|
+
DEFAULT_PROJECT_LOCATIONS = [
|
|
77
|
+
"~/Documents/PCB", # Common Windows/macOS location
|
|
78
|
+
"~/PCB", # Simple home directory structure
|
|
79
|
+
"~/Electronics", # Generic electronics projects
|
|
80
|
+
"~/Projects/Electronics", # Organized project structure
|
|
81
|
+
"~/Projects/PCB", # PCB-specific project directory
|
|
82
|
+
"~/Projects/KiCad", # KiCad-specific project directory
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
# Add existing default locations to search paths
|
|
86
|
+
# Avoids duplicates and only includes directories that actually exist
|
|
87
|
+
for location in DEFAULT_PROJECT_LOCATIONS:
|
|
88
|
+
expanded_path = os.path.expanduser(location)
|
|
89
|
+
if os.path.exists(expanded_path) and expanded_path not in ADDITIONAL_SEARCH_PATHS:
|
|
90
|
+
ADDITIONAL_SEARCH_PATHS.append(expanded_path)
|
|
91
|
+
|
|
92
|
+
# Base path to KiCad's Python framework for API access
|
|
93
|
+
# macOS bundles Python framework within the application
|
|
94
|
+
if system == "Darwin": # macOS
|
|
95
|
+
KICAD_PYTHON_BASE = os.path.join(
|
|
96
|
+
KICAD_APP_PATH, "Contents/Frameworks/Python.framework/Versions"
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
# Linux/Windows use system Python or require dynamic detection
|
|
100
|
+
KICAD_PYTHON_BASE = "" # Will be determined dynamically in python_path.py
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# KiCad file extension mappings for project file identification
|
|
104
|
+
# Used by file discovery and validation functions
|
|
105
|
+
KICAD_EXTENSIONS = {
|
|
106
|
+
"project": ".kicad_pro",
|
|
107
|
+
"pcb": ".kicad_pcb",
|
|
108
|
+
"schematic": ".kicad_sch",
|
|
109
|
+
"design_rules": ".kicad_dru",
|
|
110
|
+
"worksheet": ".kicad_wks",
|
|
111
|
+
"footprint": ".kicad_mod",
|
|
112
|
+
"netlist": "_netlist.net",
|
|
113
|
+
"kibot_config": ".kibot.yaml",
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# Additional data file extensions that may be part of KiCad projects
|
|
117
|
+
# Includes manufacturing files, component data, and export formats
|
|
118
|
+
DATA_EXTENSIONS = [
|
|
119
|
+
".csv", # BOM or other data
|
|
120
|
+
".pos", # Component position file
|
|
121
|
+
".net", # Netlist files
|
|
122
|
+
".zip", # Gerber files and other archives
|
|
123
|
+
".drl", # Drill files
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
# Default parameters for circuit creation and component placement
|
|
127
|
+
# Values in mm unless otherwise specified, following KiCad conventions
|
|
128
|
+
CIRCUIT_DEFAULTS = {
|
|
129
|
+
"grid_spacing": 1.0, # Default grid spacing in mm for user coordinates
|
|
130
|
+
"component_spacing": 10.16, # Default component spacing in mm
|
|
131
|
+
"wire_width": 6, # Default wire width in KiCad units (0.006 inch)
|
|
132
|
+
"text_size": [1.27, 1.27], # Default text size in mm
|
|
133
|
+
"pin_length": 2.54, # Default pin length in mm
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Predefined component library mappings for quick circuit creation
|
|
137
|
+
# Maps common component types to their KiCad library and symbol names
|
|
138
|
+
# Organized by functional categories: basic, power, connectors
|
|
139
|
+
COMMON_LIBRARIES = {
|
|
140
|
+
"basic": {
|
|
141
|
+
"resistor": {"library": "Device", "symbol": "R"},
|
|
142
|
+
"capacitor": {"library": "Device", "symbol": "C"},
|
|
143
|
+
"inductor": {"library": "Device", "symbol": "L"},
|
|
144
|
+
"led": {"library": "Device", "symbol": "LED"},
|
|
145
|
+
"diode": {"library": "Device", "symbol": "D"},
|
|
146
|
+
},
|
|
147
|
+
"power": {
|
|
148
|
+
"vcc": {"library": "power", "symbol": "VCC"},
|
|
149
|
+
"gnd": {"library": "power", "symbol": "GND"},
|
|
150
|
+
"+5v": {"library": "power", "symbol": "+5V"},
|
|
151
|
+
"+3v3": {"library": "power", "symbol": "+3V3"},
|
|
152
|
+
"+12v": {"library": "power", "symbol": "+12V"},
|
|
153
|
+
"-12v": {"library": "power", "symbol": "-12V"},
|
|
154
|
+
},
|
|
155
|
+
"connectors": {
|
|
156
|
+
"conn_2pin": {"library": "Connector", "symbol": "Conn_01x02_Male"},
|
|
157
|
+
"conn_4pin": {"library": "Connector_Generic", "symbol": "Conn_01x04"},
|
|
158
|
+
"conn_8pin": {"library": "Connector_Generic", "symbol": "Conn_01x08"},
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Suggested footprints for common components, ordered by preference
|
|
163
|
+
# SMD variants listed first, followed by through-hole alternatives
|
|
164
|
+
DEFAULT_FOOTPRINTS = {
|
|
165
|
+
"R": [
|
|
166
|
+
"Resistor_SMD:R_0805_2012Metric",
|
|
167
|
+
"Resistor_SMD:R_0603_1608Metric",
|
|
168
|
+
"Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal",
|
|
169
|
+
],
|
|
170
|
+
"C": [
|
|
171
|
+
"Capacitor_SMD:C_0805_2012Metric",
|
|
172
|
+
"Capacitor_SMD:C_0603_1608Metric",
|
|
173
|
+
"Capacitor_THT:C_Disc_D5.0mm_W2.5mm_P5.00mm",
|
|
174
|
+
],
|
|
175
|
+
"LED": ["LED_SMD:LED_0805_2012Metric", "LED_THT:LED_D5.0mm"],
|
|
176
|
+
"D": ["Diode_SMD:D_SOD-123", "Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal"],
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Operation timeout values in seconds for external process management
|
|
180
|
+
# Prevents hanging operations and provides user feedback
|
|
181
|
+
TIMEOUT_CONSTANTS = {
|
|
182
|
+
"kicad_cli_version_check": 10.0, # Timeout for KiCad CLI version checks
|
|
183
|
+
"kicad_cli_export": 30.0, # Timeout for KiCad CLI export operations
|
|
184
|
+
"application_open": 10.0, # Timeout for opening applications (e.g., KiCad)
|
|
185
|
+
"subprocess_default": 30.0, # Default timeout for subprocess operations
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Progress percentage milestones for long-running operations
|
|
189
|
+
# Provides consistent progress reporting across different tools
|
|
190
|
+
PROGRESS_CONSTANTS = {
|
|
191
|
+
"start": 10, # Initial progress percentage
|
|
192
|
+
"detection": 20, # Progress after CLI detection
|
|
193
|
+
"setup": 30, # Progress after setup complete
|
|
194
|
+
"processing": 50, # Progress during processing
|
|
195
|
+
"finishing": 70, # Progress when finishing up
|
|
196
|
+
"validation": 90, # Progress during validation
|
|
197
|
+
"complete": 100, # Progress when complete
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# User interface display configuration values
|
|
201
|
+
# Controls how much information is shown in previews and summaries
|
|
202
|
+
DISPLAY_CONSTANTS = {
|
|
203
|
+
"bom_preview_limit": 20, # Maximum number of BOM items to show in preview
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# KiCad version string — fallback used when KICAD_VERSION env var is not set
|
|
207
|
+
KICAD_VERSION = "9.0"
|
|
208
|
+
|
|
209
|
+
class LibraryPathConfig:
|
|
210
|
+
"""
|
|
211
|
+
KiCad symbol library path configuration.
|
|
212
|
+
|
|
213
|
+
Reads KICAD_VERSION and each path from the corresponding environment
|
|
214
|
+
variable; if a variable is absent the built-in default is used. The
|
|
215
|
+
resolved values are collected into ``self._env_vars`` so they can be
|
|
216
|
+
injected into subprocess environments that expand ``${VAR}`` URI
|
|
217
|
+
references.
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
@staticmethod
|
|
221
|
+
def _default_symbol_dir(kicad_app_path: str) -> str:
|
|
222
|
+
"""Return the platform-specific default KiCad system symbols directory."""
|
|
223
|
+
if system == "Darwin":
|
|
224
|
+
return os.path.join(kicad_app_path, "Contents", "SharedSupport", "symbols")
|
|
225
|
+
elif system == "Windows":
|
|
226
|
+
return os.path.join(kicad_app_path, "share", "kicad", "symbols")
|
|
227
|
+
else:
|
|
228
|
+
return os.path.join(kicad_app_path, "symbols")
|
|
229
|
+
|
|
230
|
+
@staticmethod
|
|
231
|
+
def _default_footprint_dir(kicad_app_path: str) -> str:
|
|
232
|
+
"""Return the platform-specific default KiCad system footprints directory."""
|
|
233
|
+
if system == "Darwin":
|
|
234
|
+
return os.path.join(kicad_app_path, "Contents", "SharedSupport", "footprints")
|
|
235
|
+
elif system == "Windows":
|
|
236
|
+
return os.path.join(kicad_app_path, "share", "kicad", "footprints")
|
|
237
|
+
else:
|
|
238
|
+
return os.path.join(kicad_app_path, "footprints")
|
|
239
|
+
|
|
240
|
+
@staticmethod
|
|
241
|
+
def _default_config_dir(kicad_version: str) -> str:
|
|
242
|
+
"""Return the platform-specific default KiCad configuration directory."""
|
|
243
|
+
if system == "Darwin":
|
|
244
|
+
return os.path.expanduser(f"~/Library/Preferences/kicad/{kicad_version}")
|
|
245
|
+
elif system == "Windows":
|
|
246
|
+
appdata = os.environ.get("APPDATA", os.path.expanduser("~"))
|
|
247
|
+
return os.path.join(appdata, "kicad", kicad_version)
|
|
248
|
+
else:
|
|
249
|
+
return os.path.expanduser(f"~/.config/kicad/{kicad_version}")
|
|
250
|
+
|
|
251
|
+
@staticmethod
|
|
252
|
+
def _default_3rd_party(kicad_version: str) -> str:
|
|
253
|
+
"""Return the platform-specific default KiCad 3rd-party packages directory."""
|
|
254
|
+
if system == "Darwin":
|
|
255
|
+
return os.path.expanduser(f"~/Library/Application Support/kicad/{kicad_version}/3rdparty")
|
|
256
|
+
elif system == "Windows":
|
|
257
|
+
appdata = os.environ.get("APPDATA", os.path.expanduser("~"))
|
|
258
|
+
return os.path.join(appdata, "kicad", kicad_version, "3rdparty")
|
|
259
|
+
else:
|
|
260
|
+
return os.path.expanduser(f"~/.local/share/kicad/{kicad_version}/3rdparty")
|
|
261
|
+
|
|
262
|
+
@staticmethod
|
|
263
|
+
def _default_template_dir(kicad_app_path: str, kicad_version: str) -> str:
|
|
264
|
+
"""Return the platform-specific default KiCad templates directory."""
|
|
265
|
+
if system == "Darwin":
|
|
266
|
+
return os.path.join(kicad_app_path, "Contents", "SharedSupport", "template")
|
|
267
|
+
elif system == "Windows":
|
|
268
|
+
return os.path.join(kicad_app_path, "share", "kicad", "template")
|
|
269
|
+
else:
|
|
270
|
+
return os.path.join(kicad_app_path, "template")
|
|
271
|
+
|
|
272
|
+
def __init__(self):
|
|
273
|
+
kicad_version = os.environ.get("KICAD_VERSION") or KICAD_VERSION
|
|
274
|
+
_ver_tag = kicad_version.split(".")[0]
|
|
275
|
+
|
|
276
|
+
# KICAD_APP_PATH must be set in the environment (typically via .env)
|
|
277
|
+
# for AppImage / non-standard installs. If the resolved path doesn't
|
|
278
|
+
# exist we log a clear warning rather than silently falling back —
|
|
279
|
+
# otherwise sym/fp-lib-table entries that reference
|
|
280
|
+
# ${KICAD{N}_TEMPLATE_DIR}/... etc. would be silently dropped.
|
|
281
|
+
kicad_app_path = os.environ.get("KICAD_APP_PATH") or KICAD_APP_PATH
|
|
282
|
+
if not os.path.isdir(kicad_app_path):
|
|
283
|
+
log.warning(
|
|
284
|
+
"KiCad application path does not exist: %s. "
|
|
285
|
+
"System symbol/footprint/template libraries will be unresolvable. "
|
|
286
|
+
"Set KICAD_APP_PATH in your .env file (e.g. for an AppImage, "
|
|
287
|
+
"the path under /tmp/.mount_kicad*/share/kicad while KiCad is "
|
|
288
|
+
"running).",
|
|
289
|
+
kicad_app_path,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
self._kicad_config_dir = os.path.expanduser(
|
|
293
|
+
os.environ.get("KICAD_CONFIG_DIR")
|
|
294
|
+
or self._default_config_dir(kicad_version)
|
|
295
|
+
)
|
|
296
|
+
self._kicad_symbol_dir = os.path.expanduser(
|
|
297
|
+
os.environ.get("KICAD_SYMBOL_DIR")
|
|
298
|
+
or self._default_symbol_dir(kicad_app_path)
|
|
299
|
+
)
|
|
300
|
+
self._kicad_footprint_dir = os.path.expanduser(
|
|
301
|
+
os.environ.get("KICAD_FOOTPRINT_DIR")
|
|
302
|
+
or self._default_footprint_dir(kicad_app_path)
|
|
303
|
+
)
|
|
304
|
+
self._kicad_3rd_party = os.path.expanduser(
|
|
305
|
+
os.environ.get("KICAD_3RD_PARTY")
|
|
306
|
+
or self._default_3rd_party(kicad_version)
|
|
307
|
+
)
|
|
308
|
+
self._kicad_template_dir = os.path.expanduser(
|
|
309
|
+
os.environ.get("KICAD_TEMPLATE_DIR")
|
|
310
|
+
or self._default_template_dir(kicad_app_path, kicad_version)
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
# Env vars to inject into subprocesses that expand ${VAR} placeholders in library URIs
|
|
314
|
+
self._env_vars = {
|
|
315
|
+
f"KICAD{_ver_tag}_SYMBOL_DIR": self._kicad_symbol_dir,
|
|
316
|
+
f"KICAD{_ver_tag}_FOOTPRINT_DIR": self._kicad_footprint_dir,
|
|
317
|
+
f"KICAD{_ver_tag}_3RD_PARTY": self._kicad_3rd_party,
|
|
318
|
+
f"KICAD{_ver_tag}_TEMPLATE_DIR": self._kicad_template_dir,
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
@property
|
|
322
|
+
def symbol_table_file(self) -> str:
|
|
323
|
+
"""Path to the sym-lib-table file."""
|
|
324
|
+
return self._kicad_config_dir + "/sym-lib-table"
|
|
325
|
+
|
|
326
|
+
def get_env_vars(self):
|
|
327
|
+
"""Get the complete environment variables dictionary."""
|
|
328
|
+
return self._env_vars.copy()
|
kcaa/context.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lifespan context management for KiCad MCP Server.
|
|
3
|
+
"""
|
|
4
|
+
from contextlib import asynccontextmanager
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import AsyncIterator, Dict, Any
|
|
7
|
+
import logging # Import logging
|
|
8
|
+
import os # Added for PID
|
|
9
|
+
|
|
10
|
+
from fastmcp import FastMCP
|
|
11
|
+
|
|
12
|
+
# Get PID for logging
|
|
13
|
+
# _PID = os.getpid()
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class KiCadAppContext:
|
|
17
|
+
"""Type-safe context for KiCad MCP server."""
|
|
18
|
+
kicad_modules_available: bool
|
|
19
|
+
|
|
20
|
+
# Optional cache for expensive operations
|
|
21
|
+
cache: Dict[str, Any]
|
|
22
|
+
|
|
23
|
+
@asynccontextmanager
|
|
24
|
+
async def kicad_lifespan(server: FastMCP, kicad_modules_available: bool = False) -> AsyncIterator[KiCadAppContext]:
|
|
25
|
+
"""Manage KiCad MCP server lifecycle with type-safe context.
|
|
26
|
+
|
|
27
|
+
This function handles:
|
|
28
|
+
1. Initializing shared resources when the server starts
|
|
29
|
+
2. Providing a typed context object to all request handlers
|
|
30
|
+
3. Properly cleaning up resources when the server shuts down
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
server: The FastMCP server instance
|
|
34
|
+
kicad_modules_available: Flag indicating if Python modules were found (passed from create_server)
|
|
35
|
+
|
|
36
|
+
Yields:
|
|
37
|
+
KiCadAppContext: A typed context object shared across all handlers
|
|
38
|
+
"""
|
|
39
|
+
logging.info(f"Starting KiCad MCP server initialization")
|
|
40
|
+
|
|
41
|
+
# Resources initialization - Python path setup removed
|
|
42
|
+
# print("Setting up KiCad Python modules")
|
|
43
|
+
# kicad_modules_available = setup_kicad_python_path() # Now passed as arg
|
|
44
|
+
logging.info(f"KiCad Python module availability: {kicad_modules_available} (Setup logic removed)")
|
|
45
|
+
|
|
46
|
+
# Create in-memory cache for expensive operations
|
|
47
|
+
cache: Dict[str, Any] = {}
|
|
48
|
+
|
|
49
|
+
# Initialize any other resources that need cleanup later
|
|
50
|
+
created_temp_dirs = [] # Assuming this is managed elsewhere or not needed for now
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
# --- Removed Python module preloading section ---
|
|
54
|
+
# if kicad_modules_available:
|
|
55
|
+
# try:
|
|
56
|
+
# print("Preloading KiCad Python modules")
|
|
57
|
+
# ...
|
|
58
|
+
# except ImportError as e:
|
|
59
|
+
# print(f"Failed to preload some KiCad modules: {str(e)}")
|
|
60
|
+
|
|
61
|
+
# Yield the context to the server - server runs during this time
|
|
62
|
+
logging.info(f"KiCad MCP server initialization complete")
|
|
63
|
+
yield KiCadAppContext(
|
|
64
|
+
kicad_modules_available=kicad_modules_available, # Pass the flag through
|
|
65
|
+
cache=cache
|
|
66
|
+
)
|
|
67
|
+
finally:
|
|
68
|
+
# Clean up resources when server shuts down
|
|
69
|
+
logging.info(f"Shutting down KiCad MCP server")
|
|
70
|
+
|
|
71
|
+
# Clear the cache
|
|
72
|
+
if cache:
|
|
73
|
+
logging.info(f"Clearing cache with {len(cache)} entries")
|
|
74
|
+
cache.clear()
|
|
75
|
+
|
|
76
|
+
# Clean up any temporary directories
|
|
77
|
+
import shutil
|
|
78
|
+
for temp_dir in created_temp_dirs:
|
|
79
|
+
try:
|
|
80
|
+
logging.info(f"Removing temporary directory: {temp_dir}")
|
|
81
|
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
logging.error(f"Error cleaning up temporary directory {temp_dir}: {str(e)}")
|
|
84
|
+
|
|
85
|
+
logging.info(f"KiCad MCP server shutdown complete")
|
kcaa/prompts/__init__.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BOM-related prompt templates for KiCad.
|
|
3
|
+
"""
|
|
4
|
+
from fastmcp import FastMCP
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def register_bom_prompts(mcp: FastMCP) -> None:
|
|
8
|
+
"""Register BOM-related prompt templates with the MCP server.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
mcp: The FastMCP server instance
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@mcp.prompt()
|
|
15
|
+
def analyze_components() -> str:
|
|
16
|
+
"""Prompt for analyzing a KiCad project's components."""
|
|
17
|
+
prompt = """
|
|
18
|
+
I'd like to analyze the components used in my KiCad PCB design. Can you help me with:
|
|
19
|
+
|
|
20
|
+
1. Identifying all the components in my design
|
|
21
|
+
2. Analyzing the distribution of component types
|
|
22
|
+
3. Checking for any potential issues or opportunities for optimization
|
|
23
|
+
4. Suggesting any alternatives for hard-to-find or expensive components
|
|
24
|
+
|
|
25
|
+
My KiCad project is located at:
|
|
26
|
+
[Enter the full path to your .kicad_pro file here]
|
|
27
|
+
|
|
28
|
+
Please use the BOM analysis tools to help me understand my component usage.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
return prompt
|
|
32
|
+
|
|
33
|
+
@mcp.prompt()
|
|
34
|
+
def cost_estimation() -> str:
|
|
35
|
+
"""Prompt for estimating project costs based on BOM."""
|
|
36
|
+
prompt = """
|
|
37
|
+
I need to estimate the cost of my KiCad PCB project for:
|
|
38
|
+
|
|
39
|
+
1. A prototype run (1-5 boards)
|
|
40
|
+
2. A small production run (10-100 boards)
|
|
41
|
+
3. Larger scale production (500+ boards)
|
|
42
|
+
|
|
43
|
+
My KiCad project is located at:
|
|
44
|
+
[Enter the full path to your .kicad_pro file here]
|
|
45
|
+
|
|
46
|
+
Please analyze my BOM to help estimate component costs, and provide guidance on:
|
|
47
|
+
|
|
48
|
+
- Which components contribute most to the overall cost
|
|
49
|
+
- Where I might find cost savings
|
|
50
|
+
- Potential volume discounts for larger runs
|
|
51
|
+
- Suggestions for alternative components that could reduce costs
|
|
52
|
+
- Estimated PCB fabrication costs based on board size and complexity
|
|
53
|
+
|
|
54
|
+
If my BOM doesn't include cost data, please suggest how I might find pricing information for my components.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
return prompt
|
|
58
|
+
|
|
59
|
+
@mcp.prompt()
|
|
60
|
+
def bom_export_help() -> str:
|
|
61
|
+
"""Prompt for assistance with exporting BOMs from KiCad."""
|
|
62
|
+
prompt = """
|
|
63
|
+
I need help exporting a Bill of Materials (BOM) from my KiCad project. I'm interested in:
|
|
64
|
+
|
|
65
|
+
1. Understanding the different BOM export options in KiCad
|
|
66
|
+
2. Exporting a BOM with specific fields (reference, value, footprint, etc.)
|
|
67
|
+
3. Generating a BOM in a format compatible with my preferred supplier
|
|
68
|
+
4. Adding custom fields to my components that will appear in the BOM
|
|
69
|
+
|
|
70
|
+
My KiCad project is located at:
|
|
71
|
+
[Enter the full path to your .kicad_pro file here]
|
|
72
|
+
|
|
73
|
+
Please guide me through the process of creating a well-structured BOM for my project.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
return prompt
|
|
77
|
+
|
|
78
|
+
@mcp.prompt()
|
|
79
|
+
def component_sourcing() -> str:
|
|
80
|
+
"""Prompt for help with component sourcing."""
|
|
81
|
+
prompt = """
|
|
82
|
+
I need help sourcing components for my KiCad PCB project. Specifically, I need assistance with:
|
|
83
|
+
|
|
84
|
+
1. Identifying reliable suppliers for my components
|
|
85
|
+
2. Finding alternatives for any hard-to-find or obsolete parts
|
|
86
|
+
3. Understanding lead times and availability constraints
|
|
87
|
+
4. Balancing cost versus quality considerations
|
|
88
|
+
|
|
89
|
+
My KiCad project is located at:
|
|
90
|
+
[Enter the full path to your .kicad_pro file here]
|
|
91
|
+
|
|
92
|
+
Please analyze my BOM and provide guidance on sourcing these components efficiently.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
return prompt
|
|
96
|
+
|
|
97
|
+
@mcp.prompt()
|
|
98
|
+
def bom_comparison() -> str:
|
|
99
|
+
"""Prompt for comparing BOMs between two design revisions."""
|
|
100
|
+
prompt = """
|
|
101
|
+
I have two versions of a KiCad project and I'd like to compare the changes between their Bills of Materials. I need to understand:
|
|
102
|
+
|
|
103
|
+
1. Which components were added or removed
|
|
104
|
+
2. Which component values or footprints changed
|
|
105
|
+
3. The impact of these changes on the overall design
|
|
106
|
+
4. Any potential issues introduced by these changes
|
|
107
|
+
|
|
108
|
+
My original KiCad project is located at:
|
|
109
|
+
[Enter the full path to your first .kicad_pro file here]
|
|
110
|
+
|
|
111
|
+
My revised KiCad project is located at:
|
|
112
|
+
[Enter the full path to your second .kicad_pro file here]
|
|
113
|
+
|
|
114
|
+
Please analyze the BOMs from both projects and help me understand the differences between them.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
return prompt
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DRC prompt templates for KiCad PCB design.
|
|
3
|
+
"""
|
|
4
|
+
from fastmcp import FastMCP
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def register_drc_prompts(mcp: FastMCP) -> None:
|
|
8
|
+
"""Register DRC prompt templates with the MCP server.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
mcp: The FastMCP server instance
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@mcp.prompt()
|
|
15
|
+
def fix_drc_violations() -> str:
|
|
16
|
+
"""Prompt for assistance with fixing DRC violations."""
|
|
17
|
+
return """
|
|
18
|
+
I'm trying to fix DRC (Design Rule Check) violations in my KiCad PCB design. I need help with:
|
|
19
|
+
|
|
20
|
+
1. Understanding what these DRC errors mean
|
|
21
|
+
2. Knowing how to fix each type of violation
|
|
22
|
+
3. Best practices for preventing DRC issues in future designs
|
|
23
|
+
|
|
24
|
+
Here are the specific DRC errors I'm seeing (please list errors from your DRC report, or use the kicad://drc/path_to_project resource to see your full DRC report):
|
|
25
|
+
|
|
26
|
+
[list your DRC errors here]
|
|
27
|
+
|
|
28
|
+
Please help me understand these errors and provide step-by-step guidance on fixing them.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@mcp.prompt()
|
|
32
|
+
def custom_design_rules() -> str:
|
|
33
|
+
"""Prompt for assistance with creating custom design rules."""
|
|
34
|
+
return """
|
|
35
|
+
I want to create custom design rules for my KiCad PCB. My project has the following requirements:
|
|
36
|
+
|
|
37
|
+
1. [Describe your project's specific requirements]
|
|
38
|
+
2. [List any special considerations like high voltage, high current, RF, etc.]
|
|
39
|
+
3. [Mention any manufacturing constraints]
|
|
40
|
+
|
|
41
|
+
Please help me set up appropriate design rules for my KiCad project, including:
|
|
42
|
+
|
|
43
|
+
- Minimum trace width and clearance settings
|
|
44
|
+
- Via size and drill constraints
|
|
45
|
+
- Layer stack considerations
|
|
46
|
+
- Other important design rules
|
|
47
|
+
|
|
48
|
+
Explain how to configure these rules in KiCad and how to verify they're being applied correctly.
|
|
49
|
+
"""
|