kcaa 0.2.2__tar.gz → 0.2.4__tar.gz
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-0.2.2 → kcaa-0.2.4}/.gitignore +1 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/PKG-INFO +8 -8
- {kcaa-0.2.2 → kcaa-0.2.4}/README.md +7 -7
- {kcaa-0.2.2 → kcaa-0.2.4}/README_CN.md +7 -7
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/server.py +14 -8
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/export_tools.py +0 -9
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/netlist_tools.py +0 -60
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/pattern_tools.py +0 -49
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/pcb_edit_tools.py +99 -26
- kcaa-0.2.4/kcaa/tools/pcb_library_tools.py +907 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/pcb_placement_tools.py +139 -72
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/pcb_query_tools.py +152 -93
- kcaa-0.2.4/kcaa/tools/project_tools.py +132 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/sheet_tools.py +33 -17
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/symbol_edit_tools.py +159 -88
- kcaa-0.2.4/kcaa/tools/version_tools.py +139 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/wire_edit_tools.py +79 -2
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/footprint_database.py +198 -59
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/footprint_index_manager.py +127 -23
- kcaa-0.2.4/kcaa/utils/fp_lib_table_utils.py +137 -0
- kcaa-0.2.4/kcaa/utils/pcb_footprint_utils.py +639 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/pcb_library_utils.py +1 -0
- kcaa-0.2.4/kcaa/utils/version_manager.py +250 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kicad_plugin/README.md +3 -3
- {kcaa-0.2.2 → kcaa-0.2.4}/pyproject.toml +1 -1
- kcaa-0.2.2/kcaa/tools/pcb_library_tools.py +0 -422
- kcaa-0.2.2/kcaa/tools/project_tools.py +0 -62
- kcaa-0.2.2/kcaa/tools/version_tools.py +0 -134
- kcaa-0.2.2/kcaa/utils/pcb_footprint_utils.py +0 -240
- kcaa-0.2.2/kcaa/utils/version_manager.py +0 -143
- {kcaa-0.2.2 → kcaa-0.2.4}/LICENSE +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/__init__.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/context.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/prompts/__init__.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/prompts/bom_prompts.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/prompts/drc_prompt.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/prompts/pattern_prompts.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/prompts/templates.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/resources/__init__.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/resources/bom_resources.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/resources/drc_resources.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/resources/files.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/resources/netlist_resources.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/resources/pattern_resources.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/resources/projects.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/router/__init__.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/router/a_star.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/router/grid_a_star.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/router/path_postprocess.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/router/router.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/router/via_check.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/router/visibility_graph.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/router/world_model.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/__init__.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/analysis_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/bom_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/drc_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/kipy_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/pcb_group_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/pcb_placement_helpers.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/pcb_routing_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/pcb_zone_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/placement_helpers.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/schematic_group_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/skill_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/symbol_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/tools/validation_tools.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/__init__.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/boundary_validator.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/component_utils.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/config.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/file_utils.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/ipc_drc.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/kicad_api_detection.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/kicad_cli.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/kicad_utils.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/kipy_reload.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/net_settings.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/netlist_parser.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/path_validator.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/pattern_recognition.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/pcb_board_utils.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/pcb_design_rules.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/pcb_sexp_utils.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/schematic_sexp_utils.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/secure_subprocess.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/skip_compat.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/skip_helpers.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/symbol_database.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/symbol_extractor.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/symbol_geometry.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/symbol_index_manager.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/symbol_index_reader.py +0 -0
- {kcaa-0.2.2 → kcaa-0.2.4}/kcaa/utils/temp_dir_manager.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: kcaa
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Model Context Protocol (MCP) server for KiCad electronic design automation (EDA) files
|
|
5
5
|
Project-URL: Homepage, https://github.com/paul356/KiCad-AI-Assistant
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/paul356/KiCad-AI-Assistant/issues
|
|
@@ -263,10 +263,8 @@ kcaa
|
|
|
263
263
|
| Tool | Description |
|
|
264
264
|
|------|-------------|
|
|
265
265
|
| `extract_schematic_netlist` | Extract netlist from a schematic |
|
|
266
|
-
| `extract_project_netlist` | Extract netlist for a whole project |
|
|
267
266
|
| `find_component_connections` | Find all connections for a component |
|
|
268
267
|
| `identify_circuit_patterns` | Identify common circuit patterns |
|
|
269
|
-
| `analyze_project_circuit_patterns` | Analyze circuit patterns in a project |
|
|
270
268
|
| `validate_project` | Basic validation of a KiCad project |
|
|
271
269
|
| `validate_project_boundaries` | Validate component boundaries |
|
|
272
270
|
| `generate_validation_report` | Generate a comprehensive validation report |
|
|
@@ -292,6 +290,9 @@ kcaa
|
|
|
292
290
|
| `list_footprint_libraries` | List all available footprint libraries |
|
|
293
291
|
| `search_footprints` | Search footprints by name, description, or tag |
|
|
294
292
|
| `get_footprint_details` | Get footprint details (pads, bounding box, etc.) |
|
|
293
|
+
| `find_footprints_not_in_libraries` | List board footprints missing from every indexed library |
|
|
294
|
+
| `create_footprint_library` | Create a global 3rdparty or project-local footprint library |
|
|
295
|
+
| `add_footprints_to_library` | Export explicitly named board footprints into a library |
|
|
295
296
|
|
|
296
297
|
### PCB Query
|
|
297
298
|
|
|
@@ -323,7 +324,7 @@ kcaa
|
|
|
323
324
|
|
|
324
325
|
| Tool | Description |
|
|
325
326
|
|------|-------------|
|
|
326
|
-
| `set_footprint_position` | Move and/or rotate
|
|
327
|
+
| `set_footprint_position` | Move and/or rotate one or more footprints (via `items`) |
|
|
327
328
|
| `flip_footprint` | Flip a footprint between top and bottom layer |
|
|
328
329
|
| `align_footprints` | Align footprints to the same axis |
|
|
329
330
|
| `distribute_footprints` | Distribute footprints evenly along an axis |
|
|
@@ -371,11 +372,10 @@ kcaa
|
|
|
371
372
|
|
|
372
373
|
| Tool | Description |
|
|
373
374
|
|------|-------------|
|
|
374
|
-
| `
|
|
375
|
-
| `
|
|
376
|
-
| `
|
|
375
|
+
| `save_project_version` | Save a project version archive (schematic+PCB+project file) |
|
|
376
|
+
| `list_project_versions` | List saved project version archives |
|
|
377
|
+
| `restore_project_version` | Restore project files together to a saved archive |
|
|
377
378
|
| `generate_pcb_thumbnail` | Render a PCB thumbnail image |
|
|
378
|
-
| `generate_project_thumbnail` | Render a project thumbnail |
|
|
379
379
|
|
|
380
380
|
### Skill System
|
|
381
381
|
|
|
@@ -224,10 +224,8 @@ kcaa
|
|
|
224
224
|
| Tool | Description |
|
|
225
225
|
|------|-------------|
|
|
226
226
|
| `extract_schematic_netlist` | Extract netlist from a schematic |
|
|
227
|
-
| `extract_project_netlist` | Extract netlist for a whole project |
|
|
228
227
|
| `find_component_connections` | Find all connections for a component |
|
|
229
228
|
| `identify_circuit_patterns` | Identify common circuit patterns |
|
|
230
|
-
| `analyze_project_circuit_patterns` | Analyze circuit patterns in a project |
|
|
231
229
|
| `validate_project` | Basic validation of a KiCad project |
|
|
232
230
|
| `validate_project_boundaries` | Validate component boundaries |
|
|
233
231
|
| `generate_validation_report` | Generate a comprehensive validation report |
|
|
@@ -253,6 +251,9 @@ kcaa
|
|
|
253
251
|
| `list_footprint_libraries` | List all available footprint libraries |
|
|
254
252
|
| `search_footprints` | Search footprints by name, description, or tag |
|
|
255
253
|
| `get_footprint_details` | Get footprint details (pads, bounding box, etc.) |
|
|
254
|
+
| `find_footprints_not_in_libraries` | List board footprints missing from every indexed library |
|
|
255
|
+
| `create_footprint_library` | Create a global 3rdparty or project-local footprint library |
|
|
256
|
+
| `add_footprints_to_library` | Export explicitly named board footprints into a library |
|
|
256
257
|
|
|
257
258
|
### PCB Query
|
|
258
259
|
|
|
@@ -284,7 +285,7 @@ kcaa
|
|
|
284
285
|
|
|
285
286
|
| Tool | Description |
|
|
286
287
|
|------|-------------|
|
|
287
|
-
| `set_footprint_position` | Move and/or rotate
|
|
288
|
+
| `set_footprint_position` | Move and/or rotate one or more footprints (via `items`) |
|
|
288
289
|
| `flip_footprint` | Flip a footprint between top and bottom layer |
|
|
289
290
|
| `align_footprints` | Align footprints to the same axis |
|
|
290
291
|
| `distribute_footprints` | Distribute footprints evenly along an axis |
|
|
@@ -332,11 +333,10 @@ kcaa
|
|
|
332
333
|
|
|
333
334
|
| Tool | Description |
|
|
334
335
|
|------|-------------|
|
|
335
|
-
| `
|
|
336
|
-
| `
|
|
337
|
-
| `
|
|
336
|
+
| `save_project_version` | Save a project version archive (schematic+PCB+project file) |
|
|
337
|
+
| `list_project_versions` | List saved project version archives |
|
|
338
|
+
| `restore_project_version` | Restore project files together to a saved archive |
|
|
338
339
|
| `generate_pcb_thumbnail` | Render a PCB thumbnail image |
|
|
339
|
-
| `generate_project_thumbnail` | Render a project thumbnail |
|
|
340
340
|
|
|
341
341
|
### Skill System
|
|
342
342
|
|
|
@@ -223,10 +223,8 @@ kcaa
|
|
|
223
223
|
| 工具 | 说明 |
|
|
224
224
|
|------|------|
|
|
225
225
|
| `extract_schematic_netlist` | 从原理图提取网表 |
|
|
226
|
-
| `extract_project_netlist` | 提取整个项目的网表 |
|
|
227
226
|
| `find_component_connections` | 查找元件的所有连接 |
|
|
228
227
|
| `identify_circuit_patterns` | 识别常见电路模式 |
|
|
229
|
-
| `analyze_project_circuit_patterns` | 分析项目中的电路模式 |
|
|
230
228
|
| `validate_project` | 项目基本验证 |
|
|
231
229
|
| `validate_project_boundaries` | 验证元件边界 |
|
|
232
230
|
| `generate_validation_report` | 生成综合验证报告 |
|
|
@@ -252,6 +250,9 @@ kcaa
|
|
|
252
250
|
| `list_footprint_libraries` | 列出所有可用封装库 |
|
|
253
251
|
| `search_footprints` | 按名称/描述/标签搜索封装 |
|
|
254
252
|
| `get_footprint_details` | 获取封装详情(焊盘、边界框等) |
|
|
253
|
+
| `find_footprints_not_in_libraries` | 列出板上缺失于所有已索引库的封装 |
|
|
254
|
+
| `create_footprint_library` | 创建全局 3rdparty 或项目级封装库 |
|
|
255
|
+
| `add_footprints_to_library` | 将显式指定的板载封装导出到库 |
|
|
255
256
|
|
|
256
257
|
### PCB 查询
|
|
257
258
|
|
|
@@ -283,7 +284,7 @@ kcaa
|
|
|
283
284
|
|
|
284
285
|
| 工具 | 说明 |
|
|
285
286
|
|------|------|
|
|
286
|
-
| `set_footprint_position` |
|
|
287
|
+
| `set_footprint_position` | 批量移动/旋转一个或多个封装 |
|
|
287
288
|
| `flip_footprint` | 将封装在顶层/底层之间翻转 |
|
|
288
289
|
| `align_footprints` | 将封装对齐到同一坐标轴 |
|
|
289
290
|
| `distribute_footprints` | 沿坐标轴等间距分布封装 |
|
|
@@ -331,11 +332,10 @@ kcaa
|
|
|
331
332
|
|
|
332
333
|
| 工具 | 说明 |
|
|
333
334
|
|------|------|
|
|
334
|
-
| `
|
|
335
|
-
| `
|
|
336
|
-
| `
|
|
335
|
+
| `save_project_version` | 保存项目版本归档(原理图+PCB+项目文件) |
|
|
336
|
+
| `list_project_versions` | 列出已保存的项目版本归档 |
|
|
337
|
+
| `restore_project_version` | 将项目文件一起恢复到已保存的归档 |
|
|
337
338
|
| `generate_pcb_thumbnail` | 渲染 PCB 缩略图 |
|
|
338
|
-
| `generate_project_thumbnail` | 渲染项目缩略图 |
|
|
339
339
|
|
|
340
340
|
### 技能系统
|
|
341
341
|
|
|
@@ -6,11 +6,12 @@ Two server profiles are supported, selected via the KICAD_MCP_PROFILE environmen
|
|
|
6
6
|
full (default) — registers all tools, resources, and prompts. Intended for
|
|
7
7
|
standalone MCP clients such as Claude Desktop.
|
|
8
8
|
|
|
9
|
-
plugin — registers
|
|
10
|
-
|
|
11
|
-
no prompts, no kicad-cli-dependent tools.
|
|
12
|
-
KiCad plugin integration where the
|
|
13
|
-
context directly and the LLM
|
|
9
|
+
plugin — registers the skip-based schematic/PCB editing tools
|
|
10
|
+
plus the ``get_project_structure`` query tool. No
|
|
11
|
+
resources, no prompts, no kicad-cli-dependent tools.
|
|
12
|
+
Intended for the KiCad plugin integration where the
|
|
13
|
+
plugin supplies project context directly and the LLM
|
|
14
|
+
drives editing via tool calls.
|
|
14
15
|
"""
|
|
15
16
|
|
|
16
17
|
import atexit
|
|
@@ -40,6 +41,7 @@ from kcaa.tools.pcb_query_tools import register_pcb_query_tools
|
|
|
40
41
|
from kcaa.tools.pcb_routing_tools import register_pcb_routing_tools
|
|
41
42
|
from kcaa.tools.pcb_zone_tools import register_pcb_zone_tools
|
|
42
43
|
from kcaa.tools.placement_helpers import register_placement_helpers
|
|
44
|
+
from kcaa.tools.project_tools import register_project_tools
|
|
43
45
|
from kcaa.tools.schematic_group_tools import register_schematic_group_tools
|
|
44
46
|
from kcaa.tools.sheet_tools import register_sheet_tools
|
|
45
47
|
from kcaa.tools.skill_tools import register_skill_tools
|
|
@@ -110,9 +112,12 @@ def register_signal_handlers(server: FastMCP) -> None:
|
|
|
110
112
|
|
|
111
113
|
|
|
112
114
|
def _register_plugin_profile(mcp: FastMCP) -> None:
|
|
113
|
-
"""Register
|
|
115
|
+
"""Register the skip-based schematic/PCB editing tools + IPC-based tools for the plugin profile."""
|
|
114
116
|
logging.info("Registering plugin profile: schematic + PCB tools")
|
|
115
117
|
register_netlist_tools(mcp)
|
|
118
|
+
# Project structure query for the plugin LLM; keep full-profile
|
|
119
|
+
# management tools (list_projects/open_project) out of this profile.
|
|
120
|
+
register_project_tools(mcp, tools=("get_project_structure",))
|
|
116
121
|
register_symbol_tools(mcp)
|
|
117
122
|
register_symbol_edit_tools(mcp)
|
|
118
123
|
register_sheet_tools(mcp)
|
|
@@ -205,8 +210,9 @@ def create_server(profile: ServerProfile = "full") -> FastMCP:
|
|
|
205
210
|
Args:
|
|
206
211
|
profile: Server capability profile.
|
|
207
212
|
"full" — all tools, resources, and prompts (default; for Claude Desktop etc.)
|
|
208
|
-
"plugin" — plugin-facing profile:
|
|
209
|
-
|
|
213
|
+
"plugin" — plugin-facing profile: skip-based schematic/PCB editing
|
|
214
|
+
tools plus the get_project_structure query tool; no
|
|
215
|
+
resources, no prompts, no kicad-cli-dependent tools.
|
|
210
216
|
Override via KICAD_MCP_PROFILE env var.
|
|
211
217
|
"""
|
|
212
218
|
# Allow env var to override the profile argument; strip whitespace/case variants
|
|
@@ -99,15 +99,6 @@ def register_export_tools(mcp: FastMCP) -> None:
|
|
|
99
99
|
await ctx.info(f"Error: {str(e)}")
|
|
100
100
|
return None
|
|
101
101
|
|
|
102
|
-
@mcp.tool()
|
|
103
|
-
async def generate_project_thumbnail(project_path: str, ctx: Context | None):
|
|
104
|
-
"""Generate a thumbnail of a KiCad project's PCB layout (Alias for generate_pcb_thumbnail)."""
|
|
105
|
-
# This function now just calls the main CLI-based thumbnail generator
|
|
106
|
-
print(
|
|
107
|
-
f"generate_project_thumbnail called, redirecting to generate_pcb_thumbnail for {project_path}"
|
|
108
|
-
)
|
|
109
|
-
return await generate_pcb_thumbnail(project_path, ctx)
|
|
110
|
-
|
|
111
102
|
|
|
112
103
|
# Helper functions for thumbnail generation
|
|
113
104
|
async def generate_thumbnail_with_cli(pcb_file: str, ctx: Context | None):
|
|
@@ -19,66 +19,6 @@ def register_netlist_tools(mcp: FastMCP) -> None:
|
|
|
19
19
|
mcp: The FastMCP server instance
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
@mcp.tool()
|
|
23
|
-
async def extract_project_netlist(project_path: str, ctx: Context | None) -> dict[str, Any]:
|
|
24
|
-
"""Extract netlist from a KiCad project's schematic.
|
|
25
|
-
|
|
26
|
-
This tool finds the schematic associated with a KiCad project
|
|
27
|
-
and extracts its netlist information.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
project_path: Path to the KiCad project file (.kicad_pro)
|
|
31
|
-
ctx: MCP context for progress reporting
|
|
32
|
-
|
|
33
|
-
Returns:
|
|
34
|
-
Dictionary with netlist information
|
|
35
|
-
"""
|
|
36
|
-
print(f"Extracting netlist for project: {project_path}")
|
|
37
|
-
|
|
38
|
-
if not os.path.exists(project_path):
|
|
39
|
-
print(f"Project not found: {project_path}")
|
|
40
|
-
if ctx:
|
|
41
|
-
ctx.info(f"Project not found: {project_path}")
|
|
42
|
-
return {"success": False, "error": f"Project not found: {project_path}"}
|
|
43
|
-
|
|
44
|
-
# Report progress
|
|
45
|
-
if ctx:
|
|
46
|
-
await ctx.report_progress(10, 100)
|
|
47
|
-
|
|
48
|
-
# Get the schematic file
|
|
49
|
-
try:
|
|
50
|
-
files = get_project_files(project_path)
|
|
51
|
-
|
|
52
|
-
if "schematic" not in files:
|
|
53
|
-
print("Schematic file not found in project")
|
|
54
|
-
if ctx:
|
|
55
|
-
ctx.info("Schematic file not found in project")
|
|
56
|
-
return {"success": False, "error": "Schematic file not found in project"}
|
|
57
|
-
|
|
58
|
-
schematic_path = files["schematic"]
|
|
59
|
-
print(f"Found schematic file: {schematic_path}")
|
|
60
|
-
if ctx:
|
|
61
|
-
ctx.info(f"Found schematic file: {os.path.basename(schematic_path)}")
|
|
62
|
-
|
|
63
|
-
# Extract netlist
|
|
64
|
-
if ctx:
|
|
65
|
-
await ctx.report_progress(20, 100)
|
|
66
|
-
|
|
67
|
-
# Call the schematic netlist extraction
|
|
68
|
-
result = await extract_schematic_netlist(schematic_path, ctx=ctx)
|
|
69
|
-
|
|
70
|
-
# Add project path to result
|
|
71
|
-
if "success" in result and result["success"]:
|
|
72
|
-
result["project_path"] = project_path
|
|
73
|
-
|
|
74
|
-
return result
|
|
75
|
-
|
|
76
|
-
except Exception as e:
|
|
77
|
-
print(f"Error extracting project netlist: {str(e)}")
|
|
78
|
-
if ctx:
|
|
79
|
-
ctx.info(f"Error extracting project netlist: {str(e)}")
|
|
80
|
-
return {"success": False, "error": str(e)}
|
|
81
|
-
|
|
82
22
|
@mcp.tool()
|
|
83
23
|
async def extract_schematic_netlist(
|
|
84
24
|
schematic_path: str,
|
|
@@ -7,7 +7,6 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from fastmcp import Context, FastMCP
|
|
9
9
|
|
|
10
|
-
from kcaa.utils.file_utils import get_project_files
|
|
11
10
|
from kcaa.utils.netlist_parser import extract_netlist
|
|
12
11
|
from kcaa.utils.pattern_recognition import (
|
|
13
12
|
identify_amplifiers,
|
|
@@ -155,51 +154,3 @@ def register_pattern_tools(mcp: FastMCP) -> None:
|
|
|
155
154
|
if ctx:
|
|
156
155
|
ctx.info(f"Error identifying circuit patterns: {str(e)}")
|
|
157
156
|
return {"success": False, "error": str(e)}
|
|
158
|
-
|
|
159
|
-
@mcp.tool()
|
|
160
|
-
async def analyze_project_circuit_patterns(
|
|
161
|
-
project_path: str, ctx: Context | None
|
|
162
|
-
) -> dict[str, Any]:
|
|
163
|
-
"""Identify circuit patterns in a KiCad project's schematic.
|
|
164
|
-
|
|
165
|
-
Args:
|
|
166
|
-
project_path: Path to the KiCad project file (.kicad_pro)
|
|
167
|
-
ctx: MCP context for progress reporting
|
|
168
|
-
|
|
169
|
-
Returns:
|
|
170
|
-
Dictionary with identified circuit patterns
|
|
171
|
-
"""
|
|
172
|
-
if not os.path.exists(project_path):
|
|
173
|
-
if ctx:
|
|
174
|
-
ctx.info(f"Project not found: {project_path}")
|
|
175
|
-
return {"success": False, "error": f"Project not found: {project_path}"}
|
|
176
|
-
|
|
177
|
-
# Report progress
|
|
178
|
-
if ctx:
|
|
179
|
-
await ctx.report_progress(10, 100)
|
|
180
|
-
|
|
181
|
-
# Get the schematic file
|
|
182
|
-
try:
|
|
183
|
-
files = get_project_files(project_path)
|
|
184
|
-
|
|
185
|
-
if "schematic" not in files:
|
|
186
|
-
if ctx:
|
|
187
|
-
ctx.info("Schematic file not found in project")
|
|
188
|
-
return {"success": False, "error": "Schematic file not found in project"}
|
|
189
|
-
|
|
190
|
-
schematic_path = files["schematic"]
|
|
191
|
-
if ctx:
|
|
192
|
-
ctx.info(f"Found schematic file: {os.path.basename(schematic_path)}")
|
|
193
|
-
|
|
194
|
-
# Identify patterns in the schematic
|
|
195
|
-
result = await identify_circuit_patterns(schematic_path, ctx)
|
|
196
|
-
|
|
197
|
-
# Add project path to result
|
|
198
|
-
if "success" in result and result["success"]:
|
|
199
|
-
result["project_path"] = project_path
|
|
200
|
-
|
|
201
|
-
return result
|
|
202
|
-
|
|
203
|
-
except Exception as e:
|
|
204
|
-
ctx.info(f"Error analyzing project circuit patterns: {str(e)}")
|
|
205
|
-
return {"success": False, "error": str(e)}
|
|
@@ -309,47 +309,120 @@ def register_pcb_edit_tools(mcp: FastMCP) -> None:
|
|
|
309
309
|
@mcp.tool()
|
|
310
310
|
async def set_footprint_property(
|
|
311
311
|
pcb_path: str,
|
|
312
|
-
|
|
313
|
-
property_name: str,
|
|
314
|
-
value: str,
|
|
312
|
+
items: list[dict[str, Any]],
|
|
315
313
|
ctx: Context | None,
|
|
316
|
-
) -> dict[str,
|
|
317
|
-
"""Update a property
|
|
314
|
+
) -> dict[str, Any]:
|
|
315
|
+
"""Update a property on footprints of the PCB board.
|
|
318
316
|
|
|
319
317
|
Common property names: ``Reference``, ``Value``, ``Datasheet``,
|
|
320
318
|
``Description``. Custom user fields are also supported.
|
|
321
319
|
|
|
320
|
+
Each item in *items* carries its own property and value
|
|
321
|
+
(``{"reference": ..., "property_name": ..., "value": ...}``).
|
|
322
|
+
All items are processed in one parse + one save (single ``.bak``).
|
|
323
|
+
Partial-apply: a footprint that cannot be found or lacks the
|
|
324
|
+
property keeps its own error in ``results`` while the remaining
|
|
325
|
+
footprints are still applied and saved. Empty, duplicate, or
|
|
326
|
+
malformed items are rejected up front.
|
|
327
|
+
|
|
322
328
|
A .kicad_pcb.bak backup is created before writing.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
pcb_path: Absolute path to the .kicad_pcb file.
|
|
332
|
+
items: List of per-footprint specs, e.g. ``[{"reference":
|
|
333
|
+
"R1", "property_name": "Value", "value": "22k"}]``.
|
|
334
|
+
Keys: ``reference`` (str, required, unique),
|
|
335
|
+
``property_name`` (str, required),
|
|
336
|
+
``value`` (str, required).
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
dict with: results (per-footprint {reference, property_name,
|
|
340
|
+
previous_value, new_value} or {reference, error}),
|
|
341
|
+
success (all applied), count, applied_count, failure_count,
|
|
342
|
+
backup_path, pcb_path.
|
|
323
343
|
"""
|
|
344
|
+
_ITEM_KEYS = {"reference", "property_name", "value"}
|
|
345
|
+
if not items:
|
|
346
|
+
return {"error": "items must not be empty"}
|
|
347
|
+
for item in items:
|
|
348
|
+
if not isinstance(item, dict):
|
|
349
|
+
return {"error": "each item must be a dict with reference, property_name, value"}
|
|
350
|
+
unknown = set(item) - _ITEM_KEYS
|
|
351
|
+
if unknown:
|
|
352
|
+
return {
|
|
353
|
+
"error": f"Unknown item fields: {sorted(unknown)}. Valid: {sorted(_ITEM_KEYS)}"
|
|
354
|
+
}
|
|
355
|
+
ref = item.get("reference")
|
|
356
|
+
if not isinstance(ref, str) or not ref:
|
|
357
|
+
return {"error": "items must not contain empty or missing references"}
|
|
358
|
+
if not isinstance(item.get("property_name"), str) or not item["property_name"]:
|
|
359
|
+
return {"error": "items must contain a non-empty property_name"}
|
|
360
|
+
if not isinstance(item.get("value"), str):
|
|
361
|
+
return {"error": "items must contain a string value"}
|
|
362
|
+
refs = [item["reference"] for item in items]
|
|
363
|
+
if len(set(refs)) != len(refs):
|
|
364
|
+
return {"error": "items must not contain duplicate references"}
|
|
365
|
+
|
|
324
366
|
data = load_pcb(pcb_path)
|
|
325
|
-
try:
|
|
326
|
-
fp = find_footprint(data, reference)
|
|
327
|
-
except KeyError as exc:
|
|
328
|
-
return {"error": str(exc)}
|
|
329
367
|
|
|
330
|
-
|
|
331
|
-
|
|
368
|
+
def apply_one(item: dict[str, Any]) -> dict[str, Any]:
|
|
369
|
+
ref = item["reference"]
|
|
370
|
+
name = item["property_name"]
|
|
371
|
+
val = item["value"]
|
|
372
|
+
try:
|
|
373
|
+
fp = find_footprint(data, ref)
|
|
374
|
+
except KeyError as exc:
|
|
375
|
+
return {"error": str(exc), "reference": ref}
|
|
376
|
+
|
|
377
|
+
old_value = get_fp_property(fp, name)
|
|
378
|
+
if old_value is None:
|
|
379
|
+
return {
|
|
380
|
+
"error": (
|
|
381
|
+
f"Property '{name}' not found on footprint '{ref}'. "
|
|
382
|
+
f"Use get_footprint to see available properties."
|
|
383
|
+
),
|
|
384
|
+
"reference": ref,
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
updated = set_fp_property(fp, name, val)
|
|
388
|
+
if not updated:
|
|
389
|
+
return {
|
|
390
|
+
"error": f"Failed to update property '{name}' on '{ref}'.",
|
|
391
|
+
"reference": ref,
|
|
392
|
+
}
|
|
393
|
+
|
|
332
394
|
return {
|
|
333
|
-
"
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
395
|
+
"success": True,
|
|
396
|
+
"reference": ref,
|
|
397
|
+
"property_name": name,
|
|
398
|
+
"previous_value": old_value,
|
|
399
|
+
"new_value": val,
|
|
337
400
|
}
|
|
338
401
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
402
|
+
results: list[dict[str, Any]] = []
|
|
403
|
+
for item in items:
|
|
404
|
+
ref = item["reference"]
|
|
405
|
+
try:
|
|
406
|
+
results.append(apply_one(item))
|
|
407
|
+
except Exception as exc:
|
|
408
|
+
log.warning("set_footprint_property: reference %r failed: %s", ref, exc)
|
|
409
|
+
results.append({"error": f"{ref}: {exc}", "reference": ref})
|
|
342
410
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
411
|
+
applied_count = sum(1 for r in results if r.get("success"))
|
|
412
|
+
|
|
413
|
+
backup_path: str | None = None
|
|
414
|
+
if applied_count > 0:
|
|
415
|
+
try:
|
|
416
|
+
backup_path = save_pcb(pcb_path, data)
|
|
417
|
+
except OSError as exc:
|
|
418
|
+
return {"error": f"Failed to write PCB file: {exc}"}
|
|
347
419
|
|
|
348
420
|
return {
|
|
349
|
-
"
|
|
350
|
-
"
|
|
351
|
-
"
|
|
352
|
-
"
|
|
421
|
+
"success": applied_count == len(results) and len(results) > 0,
|
|
422
|
+
"results": results,
|
|
423
|
+
"count": len(results),
|
|
424
|
+
"applied_count": applied_count,
|
|
425
|
+
"failure_count": len(results) - applied_count,
|
|
353
426
|
"backup_path": backup_path,
|
|
354
427
|
"pcb_path": pcb_path,
|
|
355
428
|
}
|