style: apply Prettier formatting to TS/JS/JSON/MD files
Add Prettier as a dev dependency with .prettierrc.json config and .prettierignore. Hook added via mirrors-prettier in pre-commit config. All TypeScript, JSON, Markdown, and YAML files auto-formatted. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@@ -2,9 +2,9 @@ name: CI/CD Pipeline
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main, develop ]
|
branches: [main, develop]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main, develop ]
|
branches: [main, develop]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# TypeScript/Node.js tests
|
# TypeScript/Node.js tests
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'npm'
|
cache: "npm"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-24.04, ubuntu-22.04]
|
os: [ubuntu-24.04, ubuntu-22.04]
|
||||||
python-version: ['3.10', '3.11', '3.12']
|
python-version: ["3.10", "3.11", "3.12"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
cache: 'pip'
|
cache: "pip"
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -96,14 +96,14 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: "20.x"
|
||||||
cache: 'npm'
|
cache: "npm"
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.12'
|
python-version: "3.12"
|
||||||
cache: 'pip'
|
cache: "pip"
|
||||||
|
|
||||||
- name: Add KiCAD PPA and Install KiCAD 9.0
|
- name: Add KiCAD PPA and Install KiCAD 9.0
|
||||||
run: |
|
run: |
|
||||||
@@ -158,7 +158,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20.x'
|
node-version: "20.x"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ repos:
|
|||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: check-json
|
- id: check-json
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
args: ['--maxkb=500']
|
args: ["--maxkb=500"]
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
@@ -22,3 +22,9 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
args: [--settings-path=pyproject.toml]
|
args: [--settings-path=pyproject.toml]
|
||||||
|
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
|
rev: v4.0.0-alpha.8
|
||||||
|
hooks:
|
||||||
|
- id: prettier
|
||||||
|
exclude: ^(dist/|package-lock\.json|\.venv/|python/)
|
||||||
|
|||||||
9
.prettierignore
Normal file
9
.prettierignore
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
|
coverage.xml
|
||||||
|
htmlcov/
|
||||||
|
data/
|
||||||
|
*.kicad_*
|
||||||
|
python/
|
||||||
|
package-lock.json
|
||||||
|
.venv/
|
||||||
7
.prettierrc.json
Normal file
7
.prettierrc.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"singleQuote": false,
|
||||||
|
"printWidth": 100,
|
||||||
|
"tabWidth": 2
|
||||||
|
}
|
||||||
58
CHANGELOG.md
58
CHANGELOG.md
@@ -71,6 +71,7 @@ enable developer features:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**What it does:**
|
**What it does:**
|
||||||
|
|
||||||
- `export_gerber` automatically copies the current MCP session log into the project's
|
- `export_gerber` automatically copies the current MCP session log into the project's
|
||||||
`logs/` subdirectory as `mcp_log_<timestamp>.txt`.
|
`logs/` subdirectory as `mcp_log_<timestamp>.txt`.
|
||||||
- `snapshot_project` copies the MCP session log into `logs/` at every checkpoint as
|
- `snapshot_project` copies the MCP session log into `logs/` at every checkpoint as
|
||||||
@@ -142,9 +143,10 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
The comments (`;; PASSIVES`, `;; SEMICONDUCTORS`, `;; INTEGRATED CIRCUITS`, `;; CONNECTORS`,
|
The comments (`;; PASSIVES`, `;; SEMICONDUCTORS`, `;; INTEGRATED CIRCUITS`, `;; CONNECTORS`,
|
||||||
`;; POWER/REGULATORS`, `;; MISC`, `;; TEMPLATE INSTANCES (...)`) caused KiCAD 9 to reject
|
`;; POWER/REGULATORS`, `;; MISC`, `;; TEMPLATE INSTANCES (...)`) caused KiCAD 9 to reject
|
||||||
every schematic created from this template with a hard parse error:
|
every schematic created from this template with a hard parse error:
|
||||||
|
|
||||||
> `Expecting '(' in <file>.kicad_sch, line 8, offset 5`
|
> `Expecting '(' in <file>.kicad_sch, line 8, offset 5`
|
||||||
**Action required for existing projects:** delete every line beginning with `;;` from any
|
> **Action required for existing projects:** delete every line beginning with `;;` from any
|
||||||
`.kicad_sch` file created between upstream commit `b98c94b` and this fix.
|
> `.kicad_sch` file created between upstream commit `b98c94b` and this fix.
|
||||||
|
|
||||||
- `add_schematic_component` / `inject_symbol_into_schematic`: symbol definition in
|
- `add_schematic_component` / `inject_symbol_into_schematic`: symbol definition in
|
||||||
`lib_symbols` was never refreshed after editing via `create_symbol` / `edit_symbol`.
|
`lib_symbols` was never refreshed after editing via `create_symbol` / `edit_symbol`.
|
||||||
@@ -214,6 +216,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### New MCP Tools (TypeScript layer – previously Python-only)
|
### New MCP Tools (TypeScript layer – previously Python-only)
|
||||||
|
|
||||||
**Routing tools:**
|
**Routing tools:**
|
||||||
|
|
||||||
- `delete_trace` - Delete traces by UUID, position or net name
|
- `delete_trace` - Delete traces by UUID, position or net name
|
||||||
- `query_traces` - Query/filter traces on the board
|
- `query_traces` - Query/filter traces on the board
|
||||||
- `get_nets_list` - List all nets with net code and class
|
- `get_nets_list` - List all nets with net code and class
|
||||||
@@ -223,6 +226,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- `refill_zones` - Refill all copper zones ⚠️ SWIG segfault risk, prefer IPC/UI
|
- `refill_zones` - Refill all copper zones ⚠️ SWIG segfault risk, prefer IPC/UI
|
||||||
|
|
||||||
**Component tools:**
|
**Component tools:**
|
||||||
|
|
||||||
- `get_component_pads` - Get all pad data for a component
|
- `get_component_pads` - Get all pad data for a component
|
||||||
- `get_component_list` - List all components on the board
|
- `get_component_list` - List all components on the board
|
||||||
- `get_pad_position` - Get absolute position of a specific pad
|
- `get_pad_position` - Get absolute position of a specific pad
|
||||||
@@ -246,6 +250,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### New MCP Tools (cont.)
|
### New MCP Tools (cont.)
|
||||||
|
|
||||||
**Datasheet tools:**
|
**Datasheet tools:**
|
||||||
|
|
||||||
- `get_datasheet_url` - Return LCSC datasheet PDF URL and product page URL for a given
|
- `get_datasheet_url` - Return LCSC datasheet PDF URL and product page URL for a given
|
||||||
LCSC number (e.g. `C179739` → `https://www.lcsc.com/datasheet/C179739.pdf`).
|
LCSC number (e.g. `C179739` → `https://www.lcsc.com/datasheet/C179739.pdf`).
|
||||||
No API key required – URL is constructed directly from the LCSC number.
|
No API key required – URL is constructed directly from the LCSC number.
|
||||||
@@ -257,6 +262,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
Implementation: `python/commands/datasheet_manager.py` (text-based, no `skip` writes)
|
Implementation: `python/commands/datasheet_manager.py` (text-based, no `skip` writes)
|
||||||
|
|
||||||
**Schematic tools:**
|
**Schematic tools:**
|
||||||
|
|
||||||
- `delete_schematic_component` - Remove a placed symbol from a `.kicad_sch` file by
|
- `delete_schematic_component` - Remove a placed symbol from a `.kicad_sch` file by
|
||||||
reference designator (e.g. `R1`, `U3`).
|
reference designator (e.g. `R1`, `U3`).
|
||||||
|
|
||||||
@@ -280,7 +286,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
direct text manipulation (parenthesis-depth tracking, same approach as PR #40).
|
direct text manipulation (parenthesis-depth tracking, same approach as PR #40).
|
||||||
Does not call `component_schematic.py::remove_component()` at all.
|
Does not call `component_schematic.py::remove_component()` at all.
|
||||||
- Error message explicitly guides the user when the wrong tool is used:
|
- Error message explicitly guides the user when the wrong tool is used:
|
||||||
*"note: this tool removes schematic symbols, use delete_component for PCB footprints"*
|
_"note: this tool removes schematic symbols, use delete_component for PCB footprints"_
|
||||||
|
|
||||||
### Additional Bug Fixes
|
### Additional Bug Fixes
|
||||||
|
|
||||||
@@ -310,6 +316,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Phase 1: Intelligent Schematic Wiring System - Core Infrastructure
|
### Phase 1: Intelligent Schematic Wiring System - Core Infrastructure
|
||||||
|
|
||||||
**Major Features:**
|
**Major Features:**
|
||||||
|
|
||||||
- Automatic pin location discovery with rotation support
|
- Automatic pin location discovery with rotation support
|
||||||
- Smart wire routing (direct, orthogonal horizontal/vertical)
|
- Smart wire routing (direct, orthogonal horizontal/vertical)
|
||||||
- Net label management (local, global, hierarchical)
|
- Net label management (local, global, hierarchical)
|
||||||
@@ -317,24 +324,28 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- Professional right-angle routing
|
- Professional right-angle routing
|
||||||
|
|
||||||
**New Components:**
|
**New Components:**
|
||||||
|
|
||||||
- `python/commands/wire_manager.py` - S-expression wire creation engine
|
- `python/commands/wire_manager.py` - S-expression wire creation engine
|
||||||
- `python/commands/pin_locator.py` - Intelligent pin discovery with rotation
|
- `python/commands/pin_locator.py` - Intelligent pin discovery with rotation
|
||||||
- Updated `python/commands/connection_schematic.py` - High-level connection API
|
- Updated `python/commands/connection_schematic.py` - High-level connection API
|
||||||
- `docs/SCHEMATIC_WIRING_PLAN.md` - Implementation roadmap
|
- `docs/SCHEMATIC_WIRING_PLAN.md` - Implementation roadmap
|
||||||
|
|
||||||
**MCP Tools Enhanced:**
|
**MCP Tools Enhanced:**
|
||||||
|
|
||||||
- `add_schematic_wire` - Create wires with stroke customization
|
- `add_schematic_wire` - Create wires with stroke customization
|
||||||
- `add_schematic_connection` - Auto-connect pins with routing options (NEW)
|
- `add_schematic_connection` - Auto-connect pins with routing options (NEW)
|
||||||
- `add_schematic_net_label` - Add labels with type and orientation control (NEW)
|
- `add_schematic_net_label` - Add labels with type and orientation control (NEW)
|
||||||
- `connect_to_net` - Connect pins to named nets (ENHANCED)
|
- `connect_to_net` - Connect pins to named nets (ENHANCED)
|
||||||
|
|
||||||
**Technical Implementation:**
|
**Technical Implementation:**
|
||||||
|
|
||||||
- Rotation transformation matrix for pin coordinates
|
- Rotation transformation matrix for pin coordinates
|
||||||
- S-expression injection for guaranteed format compliance
|
- S-expression injection for guaranteed format compliance
|
||||||
- Pin definition caching for performance
|
- Pin definition caching for performance
|
||||||
- Orthogonal path generation for professional schematics
|
- Orthogonal path generation for professional schematics
|
||||||
|
|
||||||
**Testing:**
|
**Testing:**
|
||||||
|
|
||||||
- End-to-end integration test: 100% passing
|
- End-to-end integration test: 100% passing
|
||||||
- MCP handler integration test: 100% passing
|
- MCP handler integration test: 100% passing
|
||||||
- Pin discovery with rotation: Verified working
|
- Pin discovery with rotation: Verified working
|
||||||
@@ -345,6 +356,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Phase 2: Power Nets & Wire Connectivity - COMPLETE
|
### Phase 2: Power Nets & Wire Connectivity - COMPLETE
|
||||||
|
|
||||||
**Major Features:**
|
**Major Features:**
|
||||||
|
|
||||||
- Power symbol support (VCC, GND, +3V3, +5V, etc.) via dynamic loading
|
- Power symbol support (VCC, GND, +3V3, +5V, etc.) via dynamic loading
|
||||||
- Wire graph analysis for net connectivity tracking
|
- Wire graph analysis for net connectivity tracking
|
||||||
- Geometric wire tracing with tolerance-based point matching
|
- Geometric wire tracing with tolerance-based point matching
|
||||||
@@ -352,6 +364,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- Critical template mapping bug fixes
|
- Critical template mapping bug fixes
|
||||||
|
|
||||||
**Updates:**
|
**Updates:**
|
||||||
|
|
||||||
- `connect_to_net()` - Migrated to WireManager + PinLocator
|
- `connect_to_net()` - Migrated to WireManager + PinLocator
|
||||||
- `get_net_connections()` - Complete rewrite with geometric wire tracing
|
- `get_net_connections()` - Complete rewrite with geometric wire tracing
|
||||||
- `generate_netlist()` - Now uses wire graph analysis for connectivity
|
- `generate_netlist()` - Now uses wire graph analysis for connectivity
|
||||||
@@ -359,12 +372,14 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- `add_component()` - Fixed template lookup with symbol iteration
|
- `add_component()` - Fixed template lookup with symbol iteration
|
||||||
|
|
||||||
**Bug Fixes:**
|
**Bug Fixes:**
|
||||||
|
|
||||||
- CRITICAL: Template mapping after dynamic symbol loading
|
- CRITICAL: Template mapping after dynamic symbol loading
|
||||||
- Special character handling in symbol names (+ prefix in +3V3, +5V)
|
- Special character handling in symbol names (+ prefix in +3V3, +5V)
|
||||||
- Schematic reload synchronization after S-expression injection
|
- Schematic reload synchronization after S-expression injection
|
||||||
- Multi-format template reference detection
|
- Multi-format template reference detection
|
||||||
|
|
||||||
**Wire Graph Analysis Algorithm:**
|
**Wire Graph Analysis Algorithm:**
|
||||||
|
|
||||||
1. Find all labels matching target net name
|
1. Find all labels matching target net name
|
||||||
2. Trace wires connected to label positions (point coincidence)
|
2. Trace wires connected to label positions (point coincidence)
|
||||||
3. Collect all wire endpoints and polyline segments
|
3. Collect all wire endpoints and polyline segments
|
||||||
@@ -372,6 +387,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
5. Return accurate component/pin connection pairs
|
5. Return accurate component/pin connection pairs
|
||||||
|
|
||||||
**Technical Implementation:**
|
**Technical Implementation:**
|
||||||
|
|
||||||
- Tolerance-based point matching (0.5mm for grid alignment)
|
- Tolerance-based point matching (0.5mm for grid alignment)
|
||||||
- Multi-segment wire (polyline) support
|
- Multi-segment wire (polyline) support
|
||||||
- Rotation-aware pin location matching via PinLocator
|
- Rotation-aware pin location matching via PinLocator
|
||||||
@@ -379,6 +395,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- Template existence checking via symbol iteration (handles special characters)
|
- Template existence checking via symbol iteration (handles special characters)
|
||||||
|
|
||||||
**Testing:**
|
**Testing:**
|
||||||
|
|
||||||
- Power symbols: 4/4 loaded (VCC, GND, +3V3, +5V)
|
- Power symbols: 4/4 loaded (VCC, GND, +3V3, +5V)
|
||||||
- Components: 4/4 placed
|
- Components: 4/4 placed
|
||||||
- Connections: 8/8 created successfully
|
- Connections: 8/8 created successfully
|
||||||
@@ -387,11 +404,13 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- Comprehensive integration test: 100% PASSING
|
- Comprehensive integration test: 100% PASSING
|
||||||
|
|
||||||
**Commits:**
|
**Commits:**
|
||||||
|
|
||||||
- `c67f400` - Updated connect_to_net to use WireManager
|
- `c67f400` - Updated connect_to_net to use WireManager
|
||||||
- `b77f008` - Fixed template mapping bug (critical)
|
- `b77f008` - Fixed template mapping bug (critical)
|
||||||
- `a5a542b` - Implemented wire graph analysis
|
- `a5a542b` - Implemented wire graph analysis
|
||||||
|
|
||||||
**Addresses:**
|
**Addresses:**
|
||||||
|
|
||||||
- Issue #26 - Schematic workflow wiring functionality (Phase 2)
|
- Issue #26 - Schematic workflow wiring functionality (Phase 2)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -399,6 +418,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Phase 2: JLCPCB Integration Complete
|
### Phase 2: JLCPCB Integration Complete
|
||||||
|
|
||||||
**Major Features:**
|
**Major Features:**
|
||||||
|
|
||||||
- ✅ Complete JLCPCB parts integration via JLCSearch public API
|
- ✅ Complete JLCPCB parts integration via JLCSearch public API
|
||||||
- ✅ Access to ~100k JLCPCB parts catalog
|
- ✅ Access to ~100k JLCPCB parts catalog
|
||||||
- ✅ Real-time stock and pricing data
|
- ✅ Real-time stock and pricing data
|
||||||
@@ -408,11 +428,13 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- ✅ Alternative part suggestions
|
- ✅ Alternative part suggestions
|
||||||
|
|
||||||
**New Components:**
|
**New Components:**
|
||||||
|
|
||||||
- `python/commands/jlcsearch.py` - JLCSearch API client (no auth required)
|
- `python/commands/jlcsearch.py` - JLCSearch API client (no auth required)
|
||||||
- `python/commands/jlcpcb_parts.py` - Enhanced with `import_jlcsearch_parts()`
|
- `python/commands/jlcpcb_parts.py` - Enhanced with `import_jlcsearch_parts()`
|
||||||
- `docs/JLCPCB_INTEGRATION.md` - Comprehensive integration guide
|
- `docs/JLCPCB_INTEGRATION.md` - Comprehensive integration guide
|
||||||
|
|
||||||
**MCP Tools Available:**
|
**MCP Tools Available:**
|
||||||
|
|
||||||
- `download_jlcpcb_database` - Download full parts catalog
|
- `download_jlcpcb_database` - Download full parts catalog
|
||||||
- `search_jlcpcb_parts` - Parametric search with filters
|
- `search_jlcpcb_parts` - Parametric search with filters
|
||||||
- `get_jlcpcb_part` - Part details + footprint suggestions
|
- `get_jlcpcb_part` - Part details + footprint suggestions
|
||||||
@@ -420,18 +442,21 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- `suggest_jlcpcb_alternatives` - Find similar/cheaper parts
|
- `suggest_jlcpcb_alternatives` - Find similar/cheaper parts
|
||||||
|
|
||||||
**Technical Improvements:**
|
**Technical Improvements:**
|
||||||
|
|
||||||
- SQLite database with full-text search (FTS5)
|
- SQLite database with full-text search (FTS5)
|
||||||
- Package-to-footprint mapping for standard SMD packages
|
- Package-to-footprint mapping for standard SMD packages
|
||||||
- Price comparison and cost optimization algorithms
|
- Price comparison and cost optimization algorithms
|
||||||
- HMAC-SHA256 authentication support (for official JLCPCB API)
|
- HMAC-SHA256 authentication support (for official JLCPCB API)
|
||||||
|
|
||||||
**Testing:**
|
**Testing:**
|
||||||
|
|
||||||
- All integration tests passing
|
- All integration tests passing
|
||||||
- Database operations validated
|
- Database operations validated
|
||||||
- Live API connectivity confirmed
|
- Live API connectivity confirmed
|
||||||
- End-to-end MCP tool testing complete
|
- End-to-end MCP tool testing complete
|
||||||
|
|
||||||
**Documentation:**
|
**Documentation:**
|
||||||
|
|
||||||
- Complete API reference with examples
|
- Complete API reference with examples
|
||||||
- Package mapping tables (0402, 0603, 0805, SOT-23, etc.)
|
- Package mapping tables (0402, 0603, 0805, SOT-23, etc.)
|
||||||
- Best practices guide
|
- Best practices guide
|
||||||
@@ -444,30 +469,36 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Phase 1: Schematic Workflow Fix
|
### Phase 1: Schematic Workflow Fix
|
||||||
|
|
||||||
**Critical Bug Fix:**
|
**Critical Bug Fix:**
|
||||||
|
|
||||||
- ✅ Fixed completely broken schematic workflow (Issue #26)
|
- ✅ Fixed completely broken schematic workflow (Issue #26)
|
||||||
- Created template-based symbol cloning approach
|
- Created template-based symbol cloning approach
|
||||||
- All schematic tests now passing
|
- All schematic tests now passing
|
||||||
|
|
||||||
**Root Cause:**
|
**Root Cause:**
|
||||||
|
|
||||||
- kicad-skip library limitation: cannot create symbols from scratch, only clone existing ones
|
- kicad-skip library limitation: cannot create symbols from scratch, only clone existing ones
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
- Template schematic with cloneable R, C, LED symbols
|
- Template schematic with cloneable R, C, LED symbols
|
||||||
- Updated `create_project` to create both PCB and schematic
|
- Updated `create_project` to create both PCB and schematic
|
||||||
- Rewrote `add_schematic_component` to use `clone()` API
|
- Rewrote `add_schematic_component` to use `clone()` API
|
||||||
- Proper UUID generation and position setting
|
- Proper UUID generation and position setting
|
||||||
|
|
||||||
**Files Modified:**
|
**Files Modified:**
|
||||||
|
|
||||||
- `python/commands/project.py` - Now creates schematic files
|
- `python/commands/project.py` - Now creates schematic files
|
||||||
- `python/commands/schematic.py` - Uses template approach
|
- `python/commands/schematic.py` - Uses template approach
|
||||||
- `python/commands/component_schematic.py` - Complete rewrite
|
- `python/commands/component_schematic.py` - Complete rewrite
|
||||||
|
|
||||||
**Files Created:**
|
**Files Created:**
|
||||||
|
|
||||||
- `python/templates/template_with_symbols.kicad_sch`
|
- `python/templates/template_with_symbols.kicad_sch`
|
||||||
- `python/templates/empty.kicad_sch`
|
- `python/templates/empty.kicad_sch`
|
||||||
- `docs/SCHEMATIC_WORKFLOW_FIX.md`
|
- `docs/SCHEMATIC_WORKFLOW_FIX.md`
|
||||||
|
|
||||||
**Testing:**
|
**Testing:**
|
||||||
|
|
||||||
- Created comprehensive test suite
|
- Created comprehensive test suite
|
||||||
- All 7 tests passing
|
- All 7 tests passing
|
||||||
- KiCad CLI validation successful
|
- KiCad CLI validation successful
|
||||||
@@ -479,17 +510,20 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Router Pattern & Tool Organization
|
### Router Pattern & Tool Organization
|
||||||
|
|
||||||
**Major Architecture Change:**
|
**Major Architecture Change:**
|
||||||
|
|
||||||
- Implemented tool router pattern (70% context reduction)
|
- Implemented tool router pattern (70% context reduction)
|
||||||
- 12 direct tools, 47 routed tools in 7 categories
|
- 12 direct tools, 47 routed tools in 7 categories
|
||||||
- Smart tool discovery system
|
- Smart tool discovery system
|
||||||
|
|
||||||
**New Router Tools:**
|
**New Router Tools:**
|
||||||
|
|
||||||
- `list_tool_categories` - Browse available categories
|
- `list_tool_categories` - Browse available categories
|
||||||
- `get_category_tools` - View tools in category
|
- `get_category_tools` - View tools in category
|
||||||
- `search_tools` - Find tools by keyword
|
- `search_tools` - Find tools by keyword
|
||||||
- `execute_tool` - Run any routed tool
|
- `execute_tool` - Run any routed tool
|
||||||
|
|
||||||
**Benefits:**
|
**Benefits:**
|
||||||
|
|
||||||
- Dramatically reduced AI context usage
|
- Dramatically reduced AI context usage
|
||||||
- Maintained full functionality (64 tools)
|
- Maintained full functionality (64 tools)
|
||||||
- Improved tool discoverability
|
- Improved tool discoverability
|
||||||
@@ -502,18 +536,21 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### IPC Backend Integration
|
### IPC Backend Integration
|
||||||
|
|
||||||
**Experimental Feature:**
|
**Experimental Feature:**
|
||||||
|
|
||||||
- KiCad 9.0 IPC API integration for real-time UI sync
|
- KiCad 9.0 IPC API integration for real-time UI sync
|
||||||
- Changes appear immediately in KiCad (no manual reload)
|
- Changes appear immediately in KiCad (no manual reload)
|
||||||
- Hybrid backend: IPC + SWIG fallback
|
- Hybrid backend: IPC + SWIG fallback
|
||||||
- 20+ commands with IPC support
|
- 20+ commands with IPC support
|
||||||
|
|
||||||
**Implementation:**
|
**Implementation:**
|
||||||
|
|
||||||
- Routing operations (interactive push-and-shove)
|
- Routing operations (interactive push-and-shove)
|
||||||
- Component placement and modification
|
- Component placement and modification
|
||||||
- Zone operations and fills
|
- Zone operations and fills
|
||||||
- DRC and verification
|
- DRC and verification
|
||||||
|
|
||||||
**Status:**
|
**Status:**
|
||||||
|
|
||||||
- Under active development
|
- Under active development
|
||||||
- Enable via KiCad: Preferences > Plugins > Enable IPC API Server
|
- Enable via KiCad: Preferences > Plugins > Enable IPC API Server
|
||||||
- Automatic fallback to SWIG when IPC unavailable
|
- Automatic fallback to SWIG when IPC unavailable
|
||||||
@@ -525,14 +562,17 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Initial JLCPCB Integration (Local Libraries)
|
### Initial JLCPCB Integration (Local Libraries)
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
|
|
||||||
- Local JLCPCB symbol library search
|
- Local JLCPCB symbol library search
|
||||||
- Integration with KiCad Plugin and Content Manager
|
- Integration with KiCad Plugin and Content Manager
|
||||||
- Search by LCSC part number, manufacturer, description
|
- Search by LCSC part number, manufacturer, description
|
||||||
|
|
||||||
**Credit:**
|
**Credit:**
|
||||||
|
|
||||||
- Contributed by [@l3wi](https://github.com/l3wi)
|
- Contributed by [@l3wi](https://github.com/l3wi)
|
||||||
|
|
||||||
**Components:**
|
**Components:**
|
||||||
|
|
||||||
- `python/commands/symbol_library.py`
|
- `python/commands/symbol_library.py`
|
||||||
- Basic library search functionality
|
- Basic library search functionality
|
||||||
|
|
||||||
@@ -543,6 +583,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Initial Release
|
### Initial Release
|
||||||
|
|
||||||
**Core Features:**
|
**Core Features:**
|
||||||
|
|
||||||
- 64 fully-documented MCP tools
|
- 64 fully-documented MCP tools
|
||||||
- JSON Schema validation for all tools
|
- JSON Schema validation for all tools
|
||||||
- 8 dynamic resources for project state
|
- 8 dynamic resources for project state
|
||||||
@@ -551,6 +592,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- Detailed logging
|
- Detailed logging
|
||||||
|
|
||||||
**Tool Categories:**
|
**Tool Categories:**
|
||||||
|
|
||||||
- Project Management (4 tools)
|
- Project Management (4 tools)
|
||||||
- Board Operations (9 tools)
|
- Board Operations (9 tools)
|
||||||
- Component Management (8 tools)
|
- Component Management (8 tools)
|
||||||
@@ -562,11 +604,13 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
- JLCPCB Integration (5 tools)
|
- JLCPCB Integration (5 tools)
|
||||||
|
|
||||||
**Platform Support:**
|
**Platform Support:**
|
||||||
|
|
||||||
- Linux (KiCad 7.x, 8.x, 9.x)
|
- Linux (KiCad 7.x, 8.x, 9.x)
|
||||||
- Windows (KiCad 9.x)
|
- Windows (KiCad 9.x)
|
||||||
- macOS (KiCad 9.x)
|
- macOS (KiCad 9.x)
|
||||||
|
|
||||||
**Documentation:**
|
**Documentation:**
|
||||||
|
|
||||||
- Complete README with setup instructions
|
- Complete README with setup instructions
|
||||||
- Platform-specific guides
|
- Platform-specific guides
|
||||||
- Tool reference documentation
|
- Tool reference documentation
|
||||||
@@ -583,9 +627,11 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
## Breaking Changes
|
## Breaking Changes
|
||||||
|
|
||||||
### 2.1.0-alpha
|
### 2.1.0-alpha
|
||||||
|
|
||||||
- None (additive changes only)
|
- None (additive changes only)
|
||||||
|
|
||||||
### 2.0.0-alpha
|
### 2.0.0-alpha
|
||||||
|
|
||||||
- Tool execution now requires router for 47 tools
|
- Tool execution now requires router for 47 tools
|
||||||
- Direct tool access limited to 12 high-frequency tools
|
- Direct tool access limited to 12 high-frequency tools
|
||||||
- Schema validation stricter (catches errors earlier)
|
- Schema validation stricter (catches errors earlier)
|
||||||
@@ -593,6 +639,7 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
## Deprecations
|
## Deprecations
|
||||||
|
|
||||||
### 2.1.0-alpha
|
### 2.1.0-alpha
|
||||||
|
|
||||||
- `docs/JLCPCB_USAGE_GUIDE.md` - Superseded by `docs/JLCPCB_INTEGRATION.md`
|
- `docs/JLCPCB_USAGE_GUIDE.md` - Superseded by `docs/JLCPCB_INTEGRATION.md`
|
||||||
- `docs/JLCPCB_INTEGRATION_PLAN.md` - Implementation complete
|
- `docs/JLCPCB_INTEGRATION_PLAN.md` - Implementation complete
|
||||||
|
|
||||||
@@ -601,15 +648,18 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Upgrading to 2.1.0-alpha from 2.0.0-alpha
|
### Upgrading to 2.1.0-alpha from 2.0.0-alpha
|
||||||
|
|
||||||
**New Dependencies:**
|
**New Dependencies:**
|
||||||
|
|
||||||
- No new system dependencies
|
- No new system dependencies
|
||||||
- Python packages: `requests` (already in requirements.txt)
|
- Python packages: `requests` (already in requirements.txt)
|
||||||
|
|
||||||
**Database Setup:**
|
**Database Setup:**
|
||||||
|
|
||||||
1. Run `download_jlcpcb_database` tool (one-time, ~5-10 minutes)
|
1. Run `download_jlcpcb_database` tool (one-time, ~5-10 minutes)
|
||||||
2. Database created at `data/jlcpcb_parts.db`
|
2. Database created at `data/jlcpcb_parts.db`
|
||||||
3. Subsequent searches use local database (instant)
|
3. Subsequent searches use local database (instant)
|
||||||
|
|
||||||
**API Changes:**
|
**API Changes:**
|
||||||
|
|
||||||
- All existing tools remain compatible
|
- All existing tools remain compatible
|
||||||
- 5 new JLCPCB tools available
|
- 5 new JLCPCB tools available
|
||||||
- No breaking changes to existing functionality
|
- No breaking changes to existing functionality
|
||||||
@@ -617,11 +667,13 @@ automatically retains a traceable record of which tools were called and in what
|
|||||||
### Upgrading to 2.0.0-alpha from 1.0.0
|
### Upgrading to 2.0.0-alpha from 1.0.0
|
||||||
|
|
||||||
**Router Pattern:**
|
**Router Pattern:**
|
||||||
|
|
||||||
- Some tools now accessed via `execute_tool` instead of direct calls
|
- Some tools now accessed via `execute_tool` instead of direct calls
|
||||||
- Use `list_tool_categories` to discover available tools
|
- Use `list_tool_categories` to discover available tools
|
||||||
- Search with `search_tools` to find specific functionality
|
- Search with `search_tools` to find specific functionality
|
||||||
|
|
||||||
**IPC Backend (Optional):**
|
**IPC Backend (Optional):**
|
||||||
|
|
||||||
- Enable in KiCad: Preferences > Plugins > Enable IPC API Server
|
- Enable in KiCad: Preferences > Plugins > Enable IPC API Server
|
||||||
- Set `KICAD_BACKEND=ipc` environment variable
|
- Set `KICAD_BACKEND=ipc` environment variable
|
||||||
- Falls back to SWIG if unavailable
|
- Falls back to SWIG if unavailable
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ git commit -m "feat: Add your feature description"
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Commit Message Convention:**
|
**Commit Message Convention:**
|
||||||
|
|
||||||
- `feat:` - New feature
|
- `feat:` - New feature
|
||||||
- `fix:` - Bug fix
|
- `fix:` - Bug fix
|
||||||
- `docs:` - Documentation changes
|
- `docs:` - Documentation changes
|
||||||
@@ -302,6 +303,7 @@ pylint python/
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Python Style Guidelines:**
|
**Python Style Guidelines:**
|
||||||
|
|
||||||
- Use type hints for all function signatures
|
- Use type hints for all function signatures
|
||||||
- Use pathlib.Path for file paths (not os.path)
|
- Use pathlib.Path for file paths (not os.path)
|
||||||
- Use descriptive variable names
|
- Use descriptive variable names
|
||||||
@@ -309,6 +311,7 @@ pylint python/
|
|||||||
- Follow PEP 8
|
- Follow PEP 8
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
@@ -345,6 +348,7 @@ npx eslint src/
|
|||||||
```
|
```
|
||||||
|
|
||||||
**TypeScript Style Guidelines:**
|
**TypeScript Style Guidelines:**
|
||||||
|
|
||||||
- Use interfaces for data structures
|
- Use interfaces for data structures
|
||||||
- Use async/await for asynchronous code
|
- Use async/await for asynchronous code
|
||||||
- Use descriptive variable names
|
- Use descriptive variable names
|
||||||
|
|||||||
103
README.md
103
README.md
@@ -1,6 +1,6 @@
|
|||||||
# Discussions. Get in here.
|
# Discussions. Get in here.
|
||||||
https://github.com/mixelpixx/KiCAD-MCP-Server/discussions/73
|
|
||||||
|
|
||||||
|
https://github.com/mixelpixx/KiCAD-MCP-Server/discussions/73
|
||||||
|
|
||||||
# KiCAD MCP Server
|
# KiCAD MCP Server
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ A Model Context Protocol (MCP) server that enables AI assistants like Claude to
|
|||||||
The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard from Anthropic that allows AI assistants to securely connect to external tools and data sources. This implementation provides a standardized bridge between AI assistants and KiCAD, enabling natural language control of PCB design operations.
|
The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard from Anthropic that allows AI assistants to securely connect to external tools and data sources. This implementation provides a standardized bridge between AI assistants and KiCAD, enabling natural language control of PCB design operations.
|
||||||
|
|
||||||
**Key Capabilities:**
|
**Key Capabilities:**
|
||||||
|
|
||||||
- 122 tools across 16 categories with JSON Schema validation
|
- 122 tools across 16 categories with JSON Schema validation
|
||||||
- Smart tool discovery with router pattern (reduces AI context by 70%)
|
- Smart tool discovery with router pattern (reduces AI context by 70%)
|
||||||
- 8 dynamic resources exposing project state
|
- 8 dynamic resources exposing project state
|
||||||
@@ -24,15 +25,10 @@ The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standa
|
|||||||
- Real-time KiCAD UI integration via IPC API (experimental)
|
- Real-time KiCAD UI integration via IPC API (experimental)
|
||||||
- Comprehensive error handling and logging
|
- Comprehensive error handling and logging
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Try out Arduino MCP - now you can get Claude to help in the IDE, real time!:
|
## Try out Arduino MCP - now you can get Claude to help in the IDE, real time!:
|
||||||
|
|
||||||
https://github.com/mixelpixx/arduino-ide
|
https://github.com/mixelpixx/arduino-ide
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## What's New in v2.2.3
|
## What's New in v2.2.3
|
||||||
|
|
||||||
### New Tools: FFC/Ribbon Cable Passthrough Workflow
|
### New Tools: FFC/Ribbon Cable Passthrough Workflow
|
||||||
@@ -80,9 +76,11 @@ See [CHANGELOG](CHANGELOG.md) for the full list of changes in this release.
|
|||||||
## What's New in v2.1.0
|
## What's New in v2.1.0
|
||||||
|
|
||||||
### Critical Schematic Workflow Fix + Complete Wiring System (Issue #26)
|
### Critical Schematic Workflow Fix + Complete Wiring System (Issue #26)
|
||||||
|
|
||||||
The schematic workflow was completely broken in previous versions - **this is now fixed AND dramatically enhanced!**
|
The schematic workflow was completely broken in previous versions - **this is now fixed AND dramatically enhanced!**
|
||||||
|
|
||||||
**What was broken:**
|
**What was broken:**
|
||||||
|
|
||||||
- `create_project` only created PCB files, no schematics
|
- `create_project` only created PCB files, no schematics
|
||||||
- `add_schematic_component` called non-existent API methods
|
- `add_schematic_component` called non-existent API methods
|
||||||
- Schematics couldn't be created or edited at all
|
- Schematics couldn't be created or edited at all
|
||||||
@@ -92,24 +90,27 @@ The schematic workflow was completely broken in previous versions - **this is no
|
|||||||
**Complete Implementation (3 Phases):**
|
**Complete Implementation (3 Phases):**
|
||||||
|
|
||||||
**Phase 1: Component Placement Foundation**
|
**Phase 1: Component Placement Foundation**
|
||||||
- `create_project` now creates both .kicad_pcb and .kicad_sch files
|
|
||||||
- Added pre-configured template schematics with 13 common component types
|
- `create_project` now creates both .kicad_pcb and .kicad_sch files
|
||||||
- Rewrote component placement to use proper `clone()` API
|
- Added pre-configured template schematics with 13 common component types
|
||||||
|
- Rewrote component placement to use proper `clone()` API
|
||||||
|
|
||||||
**Phase 2: Dynamic Symbol Loading (BREAKTHROUGH!)**
|
**Phase 2: Dynamic Symbol Loading (BREAKTHROUGH!)**
|
||||||
- **Access to ALL ~10,000 KiCad symbols** from standard libraries
|
|
||||||
- Automatic detection and dynamic loading from `.kicad_sym` library files
|
- **Access to ALL ~10,000 KiCad symbols** from standard libraries
|
||||||
- Zero configuration required - just specify library and symbol name
|
- Automatic detection and dynamic loading from `.kicad_sym` library files
|
||||||
- Seamless integration with existing MCP tools
|
- Zero configuration required - just specify library and symbol name
|
||||||
- Full S-expression parsing and injection system
|
- Seamless integration with existing MCP tools
|
||||||
|
- Full S-expression parsing and injection system
|
||||||
|
|
||||||
**Phase 3: Intelligent Wiring System (NEW in v2.1.0)**
|
**Phase 3: Intelligent Wiring System (NEW in v2.1.0)**
|
||||||
- **Automatic pin location discovery** with rotation support (0°, 90°, 180°, 270°)
|
|
||||||
- **Smart wire routing** (direct, orthogonal horizontal-first, orthogonal vertical-first)
|
- **Automatic pin location discovery** with rotation support (0°, 90°, 180°, 270°)
|
||||||
- **Power symbol support** (VCC, GND, +3V3, +5V, etc.)
|
- **Smart wire routing** (direct, orthogonal horizontal-first, orthogonal vertical-first)
|
||||||
- **Wire graph analysis** - geometric tracing for net connectivity
|
- **Power symbol support** (VCC, GND, +3V3, +5V, etc.)
|
||||||
- **Net label management** (local, global, hierarchical labels)
|
- **Wire graph analysis** - geometric tracing for net connectivity
|
||||||
- **Netlist generation** with accurate component/pin connections
|
- **Net label management** (local, global, hierarchical labels)
|
||||||
|
- **Netlist generation** with accurate component/pin connections
|
||||||
|
|
||||||
**Technical Architecture:**
|
**Technical Architecture:**
|
||||||
The kicad-skip library cannot create symbols or wires from scratch. We implemented a comprehensive solution:
|
The kicad-skip library cannot create symbols or wires from scratch. We implemented a comprehensive solution:
|
||||||
@@ -126,6 +127,7 @@ The kicad-skip library cannot create symbols or wires from scratch. We implement
|
|||||||
5. **Connectivity Analysis:** Geometric wire tracing to build net connection graphs
|
5. **Connectivity Analysis:** Geometric wire tracing to build net connection graphs
|
||||||
|
|
||||||
**Example - Complete Circuit Creation:**
|
**Example - Complete Circuit Creation:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Load power symbols dynamically
|
# Load power symbols dynamically
|
||||||
loader.load_symbol_dynamically(sch_path, "power", "VCC")
|
loader.load_symbol_dynamically(sch_path, "power", "VCC")
|
||||||
@@ -150,6 +152,7 @@ connections = ConnectionManager.get_net_connections(sch, "VCC", sch_path)
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Test Results:**
|
**Test Results:**
|
||||||
|
|
||||||
- Component placement: 100% passing
|
- Component placement: 100% passing
|
||||||
- Dynamic symbol loading: 10,000+ symbols accessible
|
- Dynamic symbol loading: 10,000+ symbols accessible
|
||||||
- Wire creation: 100% passing (8/8 connections in test circuit)
|
- Wire creation: 100% passing (8/8 connections in test circuit)
|
||||||
@@ -160,7 +163,9 @@ connections = ConnectionManager.get_net_connections(sch, "VCC", sch_path)
|
|||||||
See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for the complete schematic tool documentation.
|
See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for the complete schematic tool documentation.
|
||||||
|
|
||||||
### IPC Backend (Experimental)
|
### IPC Backend (Experimental)
|
||||||
|
|
||||||
We are currently implementing and testing the KiCAD 9.0 IPC API for real-time UI synchronization:
|
We are currently implementing and testing the KiCAD 9.0 IPC API for real-time UI synchronization:
|
||||||
|
|
||||||
- Changes made via MCP tools appear immediately in the KiCAD UI
|
- Changes made via MCP tools appear immediately in the KiCAD UI
|
||||||
- No manual reload required when IPC is active
|
- No manual reload required when IPC is active
|
||||||
- Hybrid backend: uses IPC when available, falls back to SWIG API
|
- Hybrid backend: uses IPC when available, falls back to SWIG API
|
||||||
@@ -169,7 +174,9 @@ We are currently implementing and testing the KiCAD 9.0 IPC API for real-time UI
|
|||||||
Note: IPC features are under active development and testing. Enable IPC in KiCAD via Preferences > Plugins > Enable IPC API Server.
|
Note: IPC features are under active development and testing. Enable IPC in KiCAD via Preferences > Plugins > Enable IPC API Server.
|
||||||
|
|
||||||
### Tool Discovery & Router Pattern
|
### Tool Discovery & Router Pattern
|
||||||
|
|
||||||
We've implemented an intelligent tool router to keep AI context efficient while maintaining full functionality:
|
We've implemented an intelligent tool router to keep AI context efficient while maintaining full functionality:
|
||||||
|
|
||||||
- **18 direct tools** always visible for high-frequency operations
|
- **18 direct tools** always visible for high-frequency operations
|
||||||
- **65 routed tools** organized into 8 categories (board, component, export, drc, schematic, library, routing, autoroute)
|
- **65 routed tools** organized into 8 categories (board, component, export, drc, schematic, library, routing, autoroute)
|
||||||
- **35 additional tools** always visible (symbol/footprint creators, JLCPCB, datasheet, advanced routing)
|
- **35 additional tools** always visible (symbol/footprint creators, JLCPCB, datasheet, advanced routing)
|
||||||
@@ -183,16 +190,19 @@ We've implemented an intelligent tool router to keep AI context efficient while
|
|||||||
|
|
||||||
**Usage is seamless:** Just ask naturally - "export gerber files" or "add mounting holes" - and Claude will discover and execute the appropriate tools automatically.
|
**Usage is seamless:** Just ask naturally - "export gerber files" or "add mounting holes" - and Claude will discover and execute the appropriate tools automatically.
|
||||||
|
|
||||||
|
|
||||||
### NEEDS TESTING - REPORT ISSUES
|
### NEEDS TESTING - REPORT ISSUES
|
||||||
|
|
||||||
### JLCPCB Parts Integration (New!)
|
### JLCPCB Parts Integration (New!)
|
||||||
|
|
||||||
Complete integration with JLCPCB's parts catalog, providing two complementary approaches for component selection:
|
Complete integration with JLCPCB's parts catalog, providing two complementary approaches for component selection:
|
||||||
|
|
||||||
**Dual-Mode Architecture:**
|
**Dual-Mode Architecture:**
|
||||||
|
|
||||||
1. **Local Symbol Libraries** - Search JLCPCB libraries installed via KiCAD Plugin and Content Manager (contributed by [@l3wi](https://github.com/l3wi))
|
1. **Local Symbol Libraries** - Search JLCPCB libraries installed via KiCAD Plugin and Content Manager (contributed by [@l3wi](https://github.com/l3wi))
|
||||||
2. **JLCPCB API Integration** - Access the complete 2.5M+ parts catalog with real-time pricing and stock data
|
2. **JLCPCB API Integration** - Access the complete 2.5M+ parts catalog with real-time pricing and stock data
|
||||||
|
|
||||||
**Key Features:**
|
**Key Features:**
|
||||||
|
|
||||||
- Real-time pricing with quantity breaks (1+, 10+, 100+, 1000+)
|
- Real-time pricing with quantity breaks (1+, 10+, 100+, 1000+)
|
||||||
- Stock availability checking
|
- Stock availability checking
|
||||||
- Basic vs Extended library type identification (Basic = free assembly)
|
- Basic vs Extended library type identification (Basic = free assembly)
|
||||||
@@ -207,7 +217,9 @@ Complete integration with JLCPCB's parts catalog, providing two complementary ap
|
|||||||
See [JLCPCB Usage Guide](docs/JLCPCB_USAGE_GUIDE.md) for detailed setup and usage instructions.
|
See [JLCPCB Usage Guide](docs/JLCPCB_USAGE_GUIDE.md) for detailed setup and usage instructions.
|
||||||
|
|
||||||
### Comprehensive Tool Schemas
|
### Comprehensive Tool Schemas
|
||||||
|
|
||||||
Every tool now includes complete JSON Schema definitions with:
|
Every tool now includes complete JSON Schema definitions with:
|
||||||
|
|
||||||
- Detailed parameter descriptions and constraints
|
- Detailed parameter descriptions and constraints
|
||||||
- Input validation with type checking
|
- Input validation with type checking
|
||||||
- Required vs. optional parameter specifications
|
- Required vs. optional parameter specifications
|
||||||
@@ -215,7 +227,9 @@ Every tool now includes complete JSON Schema definitions with:
|
|||||||
- Clear documentation of what each tool does
|
- Clear documentation of what each tool does
|
||||||
|
|
||||||
### Resources Capability
|
### Resources Capability
|
||||||
|
|
||||||
Access project state without executing tools:
|
Access project state without executing tools:
|
||||||
|
|
||||||
- `kicad://project/current/info` - Project metadata
|
- `kicad://project/current/info` - Project metadata
|
||||||
- `kicad://project/current/board` - Board properties
|
- `kicad://project/current/board` - Board properties
|
||||||
- `kicad://project/current/components` - Component list (JSON)
|
- `kicad://project/current/components` - Component list (JSON)
|
||||||
@@ -226,6 +240,7 @@ Access project state without executing tools:
|
|||||||
- `kicad://board/preview.png` - Board visualization (PNG)
|
- `kicad://board/preview.png` - Board visualization (PNG)
|
||||||
|
|
||||||
### Protocol Compliance
|
### Protocol Compliance
|
||||||
|
|
||||||
- Updated to MCP SDK 1.21.0 (latest)
|
- Updated to MCP SDK 1.21.0 (latest)
|
||||||
- Full JSON-RPC 2.0 support
|
- Full JSON-RPC 2.0 support
|
||||||
- Proper capability negotiation
|
- Proper capability negotiation
|
||||||
@@ -238,6 +253,7 @@ The server provides **122 tools** organized into 16 functional categories. With
|
|||||||
For the complete tool reference with access types (direct/routed/additional), see [Tool Inventory](docs/TOOL_INVENTORY.md).
|
For the complete tool reference with access types (direct/routed/additional), see [Tool Inventory](docs/TOOL_INVENTORY.md).
|
||||||
|
|
||||||
### Project Management (5 tools)
|
### Project Management (5 tools)
|
||||||
|
|
||||||
- `create_project` - Initialize new KiCAD projects
|
- `create_project` - Initialize new KiCAD projects
|
||||||
- `open_project` - Load existing project files
|
- `open_project` - Load existing project files
|
||||||
- `save_project` - Save current project state
|
- `save_project` - Save current project state
|
||||||
@@ -245,6 +261,7 @@ For the complete tool reference with access types (direct/routed/additional), se
|
|||||||
- `snapshot_project` - Save named checkpoint snapshot
|
- `snapshot_project` - Save named checkpoint snapshot
|
||||||
|
|
||||||
### Board Operations (12 tools)
|
### Board Operations (12 tools)
|
||||||
|
|
||||||
- `set_board_size` - Configure PCB dimensions
|
- `set_board_size` - Configure PCB dimensions
|
||||||
- `add_board_outline` - Create board edge (rectangle, circle, polygon, rounded rectangle)
|
- `add_board_outline` - Create board edge (rectangle, circle, polygon, rounded rectangle)
|
||||||
- `add_layer` - Add custom layers to stack
|
- `add_layer` - Add custom layers to stack
|
||||||
@@ -259,6 +276,7 @@ For the complete tool reference with access types (direct/routed/additional), se
|
|||||||
- `import_svg_logo` - Import SVG file as PCB silkscreen polygons
|
- `import_svg_logo` - Import SVG file as PCB silkscreen polygons
|
||||||
|
|
||||||
### Component Management (16 tools)
|
### Component Management (16 tools)
|
||||||
|
|
||||||
- `place_component` - Place single component with footprint
|
- `place_component` - Place single component with footprint
|
||||||
- `move_component` - Reposition existing component
|
- `move_component` - Reposition existing component
|
||||||
- `rotate_component` - Rotate component by angle
|
- `rotate_component` - Rotate component by angle
|
||||||
@@ -277,6 +295,7 @@ For the complete tool reference with access types (direct/routed/additional), se
|
|||||||
- `duplicate_component` - Copy existing component
|
- `duplicate_component` - Copy existing component
|
||||||
|
|
||||||
### Routing (13 tools)
|
### Routing (13 tools)
|
||||||
|
|
||||||
- `add_net` - Create electrical net
|
- `add_net` - Create electrical net
|
||||||
- `route_trace` - Route copper traces between XY points
|
- `route_trace` - Route copper traces between XY points
|
||||||
- `route_pad_to_pad` - Route between pads with auto-via insertion
|
- `route_pad_to_pad` - Route between pads with auto-via insertion
|
||||||
@@ -292,9 +311,11 @@ For the complete tool reference with access types (direct/routed/additional), se
|
|||||||
- `copy_routing_pattern` - Replicate routing between component groups
|
- `copy_routing_pattern` - Replicate routing between component groups
|
||||||
|
|
||||||
### Schematic (27 tools)
|
### Schematic (27 tools)
|
||||||
|
|
||||||
Complete schematic workflow with dynamic symbol loading (~10,000 symbols) and intelligent wiring.
|
Complete schematic workflow with dynamic symbol loading (~10,000 symbols) and intelligent wiring.
|
||||||
|
|
||||||
**Component Operations:**
|
**Component Operations:**
|
||||||
|
|
||||||
- `add_schematic_component` - Place symbols from any KiCad library
|
- `add_schematic_component` - Place symbols from any KiCad library
|
||||||
- `delete_schematic_component` - Remove component
|
- `delete_schematic_component` - Remove component
|
||||||
- `edit_schematic_component` - Edit properties and fields
|
- `edit_schematic_component` - Edit properties and fields
|
||||||
@@ -305,6 +326,7 @@ Complete schematic workflow with dynamic symbol loading (~10,000 symbols) and in
|
|||||||
- `annotate_schematic` - Auto-assign reference designators
|
- `annotate_schematic` - Auto-assign reference designators
|
||||||
|
|
||||||
**Wiring and Connections:**
|
**Wiring and Connections:**
|
||||||
|
|
||||||
- `add_wire` - Create wire between points
|
- `add_wire` - Create wire between points
|
||||||
- `delete_schematic_wire` - Remove wire segment
|
- `delete_schematic_wire` - Remove wire segment
|
||||||
- `add_schematic_connection` - Auto-connect pins with routing
|
- `add_schematic_connection` - Auto-connect pins with routing
|
||||||
@@ -315,6 +337,7 @@ Complete schematic workflow with dynamic symbol loading (~10,000 symbols) and in
|
|||||||
- `get_schematic_pin_locations` - Get pin locations for component
|
- `get_schematic_pin_locations` - Get pin locations for component
|
||||||
|
|
||||||
**Analysis and Export:**
|
**Analysis and Export:**
|
||||||
|
|
||||||
- `get_net_connections` - Trace net connectivity
|
- `get_net_connections` - Trace net connectivity
|
||||||
- `list_schematic_nets` / `list_schematic_wires` / `list_schematic_labels`
|
- `list_schematic_nets` / `list_schematic_wires` / `list_schematic_labels`
|
||||||
- `create_schematic` - Create new schematic file
|
- `create_schematic` - Create new schematic file
|
||||||
@@ -327,6 +350,7 @@ Complete schematic workflow with dynamic symbol loading (~10,000 symbols) and in
|
|||||||
See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for details and examples.
|
See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for details and examples.
|
||||||
|
|
||||||
### Design Rules / DRC (8 tools)
|
### Design Rules / DRC (8 tools)
|
||||||
|
|
||||||
- `set_design_rules` / `get_design_rules` - Configure and inspect rules
|
- `set_design_rules` / `get_design_rules` - Configure and inspect rules
|
||||||
- `run_drc` - Execute design rule check
|
- `run_drc` - Execute design rule check
|
||||||
- `get_drc_violations` - Get violation list by severity
|
- `get_drc_violations` - Get violation list by severity
|
||||||
@@ -334,6 +358,7 @@ See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for details a
|
|||||||
- `set_layer_constraints` / `check_clearance` - Layer and clearance rules
|
- `set_layer_constraints` / `check_clearance` - Layer and clearance rules
|
||||||
|
|
||||||
### Export (8 tools)
|
### Export (8 tools)
|
||||||
|
|
||||||
- `export_gerber` - Gerber fabrication files
|
- `export_gerber` - Gerber fabrication files
|
||||||
- `export_pdf` / `export_svg` - Documentation and vector graphics
|
- `export_pdf` / `export_svg` - Documentation and vector graphics
|
||||||
- `export_3d` - 3D models (STEP, STL, VRML, OBJ)
|
- `export_3d` - 3D models (STEP, STL, VRML, OBJ)
|
||||||
@@ -343,13 +368,16 @@ See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for details a
|
|||||||
- `export_vrml` - VRML 3D model
|
- `export_vrml` - VRML 3D model
|
||||||
|
|
||||||
### Footprint Libraries (4 tools) and Symbol Libraries (4 tools)
|
### Footprint Libraries (4 tools) and Symbol Libraries (4 tools)
|
||||||
|
|
||||||
- `list_libraries` / `list_symbol_libraries` - Browse available libraries
|
- `list_libraries` / `list_symbol_libraries` - Browse available libraries
|
||||||
- `search_footprints` / `search_symbols` - Search across all libraries
|
- `search_footprints` / `search_symbols` - Search across all libraries
|
||||||
- `list_library_footprints` / `list_library_symbols` - Browse specific library
|
- `list_library_footprints` / `list_library_symbols` - Browse specific library
|
||||||
- `get_footprint_info` / `get_symbol_info` - Detailed information
|
- `get_footprint_info` / `get_symbol_info` - Detailed information
|
||||||
|
|
||||||
### Footprint Creator (4 tools) and Symbol Creator (4 tools)
|
### Footprint Creator (4 tools) and Symbol Creator (4 tools)
|
||||||
|
|
||||||
Create custom components when existing libraries do not have what you need.
|
Create custom components when existing libraries do not have what you need.
|
||||||
|
|
||||||
- `create_footprint` / `create_symbol` - Build from scratch with pads/pins
|
- `create_footprint` / `create_symbol` - Build from scratch with pads/pins
|
||||||
- `edit_footprint_pad` - Modify pad properties
|
- `edit_footprint_pad` - Modify pad properties
|
||||||
- `register_footprint_library` / `register_symbol_library` - Register in lib-table
|
- `register_footprint_library` / `register_symbol_library` - Register in lib-table
|
||||||
@@ -359,10 +387,12 @@ Create custom components when existing libraries do not have what you need.
|
|||||||
See [Footprint and Symbol Creator Guide](docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md) for details.
|
See [Footprint and Symbol Creator Guide](docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md) for details.
|
||||||
|
|
||||||
### Datasheet Tools (2 tools)
|
### Datasheet Tools (2 tools)
|
||||||
|
|
||||||
- `enrich_datasheets` - Auto-populate datasheet URLs using LCSC part numbers
|
- `enrich_datasheets` - Auto-populate datasheet URLs using LCSC part numbers
|
||||||
- `get_datasheet_url` - Get LCSC datasheet URL for a component
|
- `get_datasheet_url` - Get LCSC datasheet URL for a component
|
||||||
|
|
||||||
### JLCPCB Integration (5 tools)
|
### JLCPCB Integration (5 tools)
|
||||||
|
|
||||||
- `download_jlcpcb_database` - Download 2.5M+ parts catalog (one-time setup)
|
- `download_jlcpcb_database` - Download 2.5M+ parts catalog (one-time setup)
|
||||||
- `search_jlcpcb_parts` - Search with parametric filters
|
- `search_jlcpcb_parts` - Search with parametric filters
|
||||||
- `get_jlcpcb_part` - Detailed part info with pricing
|
- `get_jlcpcb_part` - Detailed part info with pricing
|
||||||
@@ -370,6 +400,7 @@ See [Footprint and Symbol Creator Guide](docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md)
|
|||||||
- `suggest_jlcpcb_alternatives` - Find cheaper or in-stock alternatives
|
- `suggest_jlcpcb_alternatives` - Find cheaper or in-stock alternatives
|
||||||
|
|
||||||
### Freerouting Autorouter (4 tools)
|
### Freerouting Autorouter (4 tools)
|
||||||
|
|
||||||
- `autoroute` - Run Freerouting autorouter (DSN export, route, SES import)
|
- `autoroute` - Run Freerouting autorouter (DSN export, route, SES import)
|
||||||
- `export_dsn` / `import_ses` - Manual Specctra DSN/SES workflow
|
- `export_dsn` / `import_ses` - Manual Specctra DSN/SES workflow
|
||||||
- `check_freerouting` - Verify Java and Freerouting availability
|
- `check_freerouting` - Verify Java and Freerouting availability
|
||||||
@@ -377,6 +408,7 @@ See [Footprint and Symbol Creator Guide](docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md)
|
|||||||
See [Freerouting Guide](docs/FREEROUTING_GUIDE.md) for setup and usage.
|
See [Freerouting Guide](docs/FREEROUTING_GUIDE.md) for setup and usage.
|
||||||
|
|
||||||
### UI Management (2 tools)
|
### UI Management (2 tools)
|
||||||
|
|
||||||
- `check_kicad_ui` - Check if KiCAD is running
|
- `check_kicad_ui` - Check if KiCAD is running
|
||||||
- `launch_kicad_ui` - Launch KiCAD application
|
- `launch_kicad_ui` - Launch KiCAD application
|
||||||
|
|
||||||
@@ -385,6 +417,7 @@ See [Freerouting Guide](docs/FREEROUTING_GUIDE.md) for setup and usage.
|
|||||||
### Required Software
|
### Required Software
|
||||||
|
|
||||||
**KiCAD 9.0 or Higher**
|
**KiCAD 9.0 or Higher**
|
||||||
|
|
||||||
- Download from [kicad.org/download](https://www.kicad.org/download/)
|
- Download from [kicad.org/download](https://www.kicad.org/download/)
|
||||||
- Must include Python module (pcbnew)
|
- Must include Python module (pcbnew)
|
||||||
- Verify installation:
|
- Verify installation:
|
||||||
@@ -393,10 +426,12 @@ See [Freerouting Guide](docs/FREEROUTING_GUIDE.md) for setup and usage.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Node.js 18 or Higher**
|
**Node.js 18 or Higher**
|
||||||
|
|
||||||
- Download from [nodejs.org](https://nodejs.org/)
|
- Download from [nodejs.org](https://nodejs.org/)
|
||||||
- Verify: `node --version` and `npm --version`
|
- Verify: `node --version` and `npm --version`
|
||||||
|
|
||||||
**Python 3.10 or Higher**
|
**Python 3.10 or Higher**
|
||||||
|
|
||||||
- Usually included with KiCAD
|
- Usually included with KiCAD
|
||||||
- Required packages (auto-installed):
|
- Required packages (auto-installed):
|
||||||
- kicad-python (kipy) >= 0.5.0 (IPC API support, optional but recommended)
|
- kicad-python (kipy) >= 0.5.0 (IPC API support, optional but recommended)
|
||||||
@@ -410,11 +445,13 @@ See [Freerouting Guide](docs/FREEROUTING_GUIDE.md) for setup and usage.
|
|||||||
|
|
||||||
**MCP Client**
|
**MCP Client**
|
||||||
Choose one:
|
Choose one:
|
||||||
|
|
||||||
- [Claude Desktop](https://claude.ai/download) - Official Anthropic desktop app
|
- [Claude Desktop](https://claude.ai/download) - Official Anthropic desktop app
|
||||||
- [Claude Code](https://docs.claude.com/claude-code) - Official CLI tool
|
- [Claude Code](https://docs.claude.com/claude-code) - Official CLI tool
|
||||||
- [Cline](https://github.com/cline/cline) - VSCode extension
|
- [Cline](https://github.com/cline/cline) - VSCode extension
|
||||||
|
|
||||||
### Supported Platforms
|
### Supported Platforms
|
||||||
|
|
||||||
- **Linux** (Ubuntu 22.04+, Fedora, Arch) - Primary platform, fully tested
|
- **Linux** (Ubuntu 22.04+, Fedora, Arch) - Primary platform, fully tested
|
||||||
- **Windows 10/11** - Fully supported with automated setup
|
- **Windows 10/11** - Fully supported with automated setup
|
||||||
- **macOS** - Experimental support
|
- **macOS** - Experimental support
|
||||||
@@ -447,6 +484,7 @@ python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
|||||||
### Windows 10/11
|
### Windows 10/11
|
||||||
|
|
||||||
**Automated Setup (Recommended):**
|
**Automated Setup (Recommended):**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git
|
git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git
|
||||||
cd KiCAD-MCP-Server
|
cd KiCAD-MCP-Server
|
||||||
@@ -454,6 +492,7 @@ cd KiCAD-MCP-Server
|
|||||||
```
|
```
|
||||||
|
|
||||||
The script will:
|
The script will:
|
||||||
|
|
||||||
- Detect KiCAD installation
|
- Detect KiCAD installation
|
||||||
- Verify prerequisites
|
- Verify prerequisites
|
||||||
- Install dependencies
|
- Install dependencies
|
||||||
@@ -497,10 +536,12 @@ npm run build
|
|||||||
### Claude Desktop
|
### Claude Desktop
|
||||||
|
|
||||||
Edit configuration file:
|
Edit configuration file:
|
||||||
|
|
||||||
- **Linux/macOS:** `~/.config/Claude/claude_desktop_config.json`
|
- **Linux/macOS:** `~/.config/Claude/claude_desktop_config.json`
|
||||||
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
||||||
|
|
||||||
**Configuration:**
|
**Configuration:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
@@ -517,6 +558,7 @@ Edit configuration file:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Platform-specific PYTHONPATH:**
|
**Platform-specific PYTHONPATH:**
|
||||||
|
|
||||||
- **Linux:** `/usr/lib/kicad/lib/python3/dist-packages`
|
- **Linux:** `/usr/lib/kicad/lib/python3/dist-packages`
|
||||||
- **Windows:** `C:\Program Files\KiCad\9.0\lib\python3\dist-packages`
|
- **Windows:** `C:\Program Files\KiCad\9.0\lib\python3\dist-packages`
|
||||||
- **macOS:** `/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages`
|
- **macOS:** `/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages`
|
||||||
@@ -553,6 +595,7 @@ If you see "Python executable not found: python3", you can manually specify the
|
|||||||
```
|
```
|
||||||
|
|
||||||
To find your Python path:
|
To find your Python path:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
which python3 # Example output: /usr/bin/python3
|
which python3 # Example output: /usr/bin/python3
|
||||||
python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" # Verify pcbnew access
|
python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" # Verify pcbnew access
|
||||||
@@ -575,12 +618,14 @@ The JLCPCB integration provides two modes that can be used independently or toge
|
|||||||
**Mode 1: JLCSearch Public API (Recommended - No Setup Required)**
|
**Mode 1: JLCSearch Public API (Recommended - No Setup Required)**
|
||||||
|
|
||||||
The easiest way to access JLCPCB's parts catalog:
|
The easiest way to access JLCPCB's parts catalog:
|
||||||
|
|
||||||
- No API credentials needed
|
- No API credentials needed
|
||||||
- No JLCPCB account required
|
- No JLCPCB account required
|
||||||
- Access to 2.5M+ parts with pricing and stock data
|
- Access to 2.5M+ parts with pricing and stock data
|
||||||
- Download time: 40-60 minutes for full catalog (100-part batches due to API limit)
|
- Download time: 40-60 minutes for full catalog (100-part batches due to API limit)
|
||||||
|
|
||||||
To download the database:
|
To download the database:
|
||||||
|
|
||||||
```
|
```
|
||||||
Ask Claude: "Download the JLCPCB parts database"
|
Ask Claude: "Download the JLCPCB parts database"
|
||||||
```
|
```
|
||||||
@@ -590,6 +635,7 @@ This creates a local SQLite database at `data/jlcpcb_parts.db` (3-5 GB for full
|
|||||||
**Mode 2: Local Symbol Libraries (No Setup Required)**
|
**Mode 2: Local Symbol Libraries (No Setup Required)**
|
||||||
|
|
||||||
Install JLCPCB libraries via KiCAD's Plugin and Content Manager:
|
Install JLCPCB libraries via KiCAD's Plugin and Content Manager:
|
||||||
|
|
||||||
1. Open KiCAD
|
1. Open KiCAD
|
||||||
2. Go to Tools > Plugin and Content Manager
|
2. Go to Tools > Plugin and Content Manager
|
||||||
3. Search for "JLCPCB" or "JLC"
|
3. Search for "JLCPCB" or "JLC"
|
||||||
@@ -609,12 +655,14 @@ For users with JLCPCB enterprise accounts and order history:
|
|||||||
2. **Configure Environment Variables**
|
2. **Configure Environment Variables**
|
||||||
|
|
||||||
Add to your shell profile (`~/.bashrc`, `~/.zshrc`, or `~/.profile`):
|
Add to your shell profile (`~/.bashrc`, `~/.zshrc`, or `~/.profile`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export JLCPCB_API_KEY="your_app_key_here"
|
export JLCPCB_API_KEY="your_app_key_here"
|
||||||
export JLCPCB_API_SECRET="your_app_secret_here"
|
export JLCPCB_API_SECRET="your_app_secret_here"
|
||||||
```
|
```
|
||||||
|
|
||||||
Or create a `.env` file in the project root:
|
Or create a `.env` file in the project root:
|
||||||
|
|
||||||
```
|
```
|
||||||
JLCPCB_API_KEY=your_app_key_here
|
JLCPCB_API_KEY=your_app_key_here
|
||||||
JLCPCB_API_SECRET=your_app_secret_here
|
JLCPCB_API_SECRET=your_app_secret_here
|
||||||
@@ -753,6 +801,7 @@ How many Basic parts are available?
|
|||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### MCP Protocol Layer
|
### MCP Protocol Layer
|
||||||
|
|
||||||
- **JSON-RPC 2.0 Transport:** Bi-directional communication via STDIO
|
- **JSON-RPC 2.0 Transport:** Bi-directional communication via STDIO
|
||||||
- **Protocol Version:** MCP 2025-06-18
|
- **Protocol Version:** MCP 2025-06-18
|
||||||
- **Capabilities:** Tools (122), Resources (8)
|
- **Capabilities:** Tools (122), Resources (8)
|
||||||
@@ -760,6 +809,7 @@ How many Basic parts are available?
|
|||||||
- **Error Handling:** Standard JSON-RPC error codes
|
- **Error Handling:** Standard JSON-RPC error codes
|
||||||
|
|
||||||
### TypeScript Server (`src/`)
|
### TypeScript Server (`src/`)
|
||||||
|
|
||||||
- Implements MCP protocol specification
|
- Implements MCP protocol specification
|
||||||
- Manages Python subprocess lifecycle
|
- Manages Python subprocess lifecycle
|
||||||
- Handles message routing and validation
|
- Handles message routing and validation
|
||||||
@@ -770,6 +820,7 @@ How many Basic parts are available?
|
|||||||
- Reduces AI context usage by 70% while maintaining full functionality
|
- Reduces AI context usage by 70% while maintaining full functionality
|
||||||
|
|
||||||
### Python Interface (`python/`)
|
### Python Interface (`python/`)
|
||||||
|
|
||||||
- **kicad_interface.py:** Main entry point, MCP message handler, command routing
|
- **kicad_interface.py:** Main entry point, MCP message handler, command routing
|
||||||
- **kicad_api/:** Backend implementations
|
- **kicad_api/:** Backend implementations
|
||||||
- `base.py` - Abstract base classes for backends
|
- `base.py` - Abstract base classes for backends
|
||||||
@@ -792,6 +843,7 @@ How many Basic parts are available?
|
|||||||
- `jlcpcb_parts.py` - JLCPCB parts database manager
|
- `jlcpcb_parts.py` - JLCPCB parts database manager
|
||||||
|
|
||||||
### KiCAD Integration
|
### KiCAD Integration
|
||||||
|
|
||||||
- **pcbnew API (SWIG):** Direct Python bindings to KiCAD for file operations
|
- **pcbnew API (SWIG):** Direct Python bindings to KiCAD for file operations
|
||||||
- **IPC API (kipy):** Real-time communication with running KiCAD instance (experimental)
|
- **IPC API (kipy):** Real-time communication with running KiCAD instance (experimental)
|
||||||
- **Hybrid Backend:** Automatically uses IPC when available, falls back to SWIG
|
- **Hybrid Backend:** Automatically uses IPC when available, falls back to SWIG
|
||||||
@@ -845,6 +897,7 @@ npm run format
|
|||||||
**Symptoms:** MCP server doesn't show up in Claude Desktop or Cline
|
**Symptoms:** MCP server doesn't show up in Claude Desktop or Cline
|
||||||
|
|
||||||
**Solutions:**
|
**Solutions:**
|
||||||
|
|
||||||
1. Verify build completed: `ls dist/index.js`
|
1. Verify build completed: `ls dist/index.js`
|
||||||
2. Check configuration paths are absolute
|
2. Check configuration paths are absolute
|
||||||
3. Restart MCP client completely
|
3. Restart MCP client completely
|
||||||
@@ -855,6 +908,7 @@ npm run format
|
|||||||
**Symptoms:** `ModuleNotFoundError: No module named 'pcbnew'`
|
**Symptoms:** `ModuleNotFoundError: No module named 'pcbnew'`
|
||||||
|
|
||||||
**Solutions:**
|
**Solutions:**
|
||||||
|
|
||||||
1. Verify KiCAD installation: `python3 -c "import pcbnew"`
|
1. Verify KiCAD installation: `python3 -c "import pcbnew"`
|
||||||
2. Check PYTHONPATH in configuration matches your KiCAD installation
|
2. Check PYTHONPATH in configuration matches your KiCAD installation
|
||||||
3. Ensure KiCAD was installed with Python support
|
3. Ensure KiCAD was installed with Python support
|
||||||
@@ -864,6 +918,7 @@ npm run format
|
|||||||
**Symptoms:** Tools fail with unclear errors
|
**Symptoms:** Tools fail with unclear errors
|
||||||
|
|
||||||
**Solutions:**
|
**Solutions:**
|
||||||
|
|
||||||
1. Check server logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
1. Check server logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
||||||
2. Verify a project is loaded before running board operations
|
2. Verify a project is loaded before running board operations
|
||||||
3. Ensure file paths are absolute, not relative
|
3. Ensure file paths are absolute, not relative
|
||||||
@@ -874,6 +929,7 @@ npm run format
|
|||||||
**Symptoms:** Server fails to start on Windows
|
**Symptoms:** Server fails to start on Windows
|
||||||
|
|
||||||
**Solutions:**
|
**Solutions:**
|
||||||
|
|
||||||
1. Run automated diagnostics: `.\setup-windows.ps1`
|
1. Run automated diagnostics: `.\setup-windows.ps1`
|
||||||
2. Verify Python path uses double backslashes: `C:\\Program Files\\KiCad\\9.0`
|
2. Verify Python path uses double backslashes: `C:\\Program Files\\KiCad\\9.0`
|
||||||
3. Check Windows Event Viewer for Node.js errors
|
3. Check Windows Event Viewer for Node.js errors
|
||||||
@@ -897,6 +953,7 @@ npm run format
|
|||||||
See [STATUS_SUMMARY.md](docs/STATUS_SUMMARY.md) for the complete status matrix and [CHANGELOG.md](CHANGELOG.md) for detailed release notes.
|
See [STATUS_SUMMARY.md](docs/STATUS_SUMMARY.md) for the complete status matrix and [CHANGELOG.md](CHANGELOG.md) for detailed release notes.
|
||||||
|
|
||||||
**Working Features (122 tools):**
|
**Working Features (122 tools):**
|
||||||
|
|
||||||
- Project management with snapshot checkpointing
|
- Project management with snapshot checkpointing
|
||||||
- Complete board design (outline, layers, zones, mounting holes, text, SVG logos)
|
- Complete board design (outline, layers, zones, mounting holes, text, SVG logos)
|
||||||
- Component placement with arrays, alignment, and duplication
|
- Component placement with arrays, alignment, and duplication
|
||||||
@@ -915,6 +972,7 @@ See [STATUS_SUMMARY.md](docs/STATUS_SUMMARY.md) for the complete status matrix a
|
|||||||
- Full MCP 2025-06-18 protocol compliance
|
- Full MCP 2025-06-18 protocol compliance
|
||||||
|
|
||||||
**IPC Backend (Experimental):**
|
**IPC Backend (Experimental):**
|
||||||
|
|
||||||
- Real-time UI synchronization via KiCAD 9.0 IPC API
|
- Real-time UI synchronization via KiCAD 9.0 IPC API
|
||||||
- 21 IPC-enabled commands with automatic SWIG fallback
|
- 21 IPC-enabled commands with automatic SWIG fallback
|
||||||
- Hybrid footprint loading (SWIG for library access, IPC for placement)
|
- Hybrid footprint loading (SWIG for library access, IPC for placement)
|
||||||
@@ -929,6 +987,7 @@ See [ROADMAP.md](docs/ROADMAP.md) for planned features.
|
|||||||
We are actively developing new features. Your feedback directly shapes development priorities.
|
We are actively developing new features. Your feedback directly shapes development priorities.
|
||||||
|
|
||||||
**Share your ideas:**
|
**Share your ideas:**
|
||||||
|
|
||||||
1. [Open a feature request](https://github.com/mixelpixx/KiCAD-MCP-Server/issues/new?labels=enhancement&template=feature_request.md)
|
1. [Open a feature request](https://github.com/mixelpixx/KiCAD-MCP-Server/issues/new?labels=enhancement&template=feature_request.md)
|
||||||
2. [Join the discussion](https://github.com/mixelpixx/KiCAD-MCP-Server/discussions)
|
2. [Join the discussion](https://github.com/mixelpixx/KiCAD-MCP-Server/discussions)
|
||||||
3. Star the repo if you find it useful
|
3. Star the repo if you find it useful
|
||||||
|
|||||||
@@ -118,10 +118,12 @@ KiCAD-MCP-Server/
|
|||||||
### Tool Registration
|
### Tool Registration
|
||||||
|
|
||||||
Each tool file exports a `register*Tools(server, callKicadScript)` function that:
|
Each tool file exports a `register*Tools(server, callKicadScript)` function that:
|
||||||
|
|
||||||
- Defines tool name, description, and Zod schema for parameters
|
- Defines tool name, description, and Zod schema for parameters
|
||||||
- Registers a handler that calls `callKicadScript(command, args)`
|
- Registers a handler that calls `callKicadScript(command, args)`
|
||||||
|
|
||||||
Example from `src/tools/project.ts`:
|
Example from `src/tools/project.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
server.tool(
|
server.tool(
|
||||||
"create_project",
|
"create_project",
|
||||||
@@ -130,13 +132,14 @@ server.tool(
|
|||||||
async (args) => {
|
async (args) => {
|
||||||
const result = await callKicadScript("create_project", args);
|
const result = await callKicadScript("create_project", args);
|
||||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tool Router (`src/tools/router.ts` and `src/tools/registry.ts`)
|
### Tool Router (`src/tools/router.ts` and `src/tools/registry.ts`)
|
||||||
|
|
||||||
The router pattern reduces AI context usage:
|
The router pattern reduces AI context usage:
|
||||||
|
|
||||||
- `registry.ts` defines tool categories and which tools are "direct" (always visible) vs "routed" (discoverable)
|
- `registry.ts` defines tool categories and which tools are "direct" (always visible) vs "routed" (discoverable)
|
||||||
- `router.ts` provides 4 meta-tools: `list_tool_categories`, `get_category_tools`, `search_tools`, `execute_tool`
|
- `router.ts` provides 4 meta-tools: `list_tool_categories`, `get_category_tools`, `search_tools`, `execute_tool`
|
||||||
- Routed tools are not registered as individual MCP tools -- they are invoked through `execute_tool`
|
- Routed tools are not registered as individual MCP tools -- they are invoked through `execute_tool`
|
||||||
@@ -144,6 +147,7 @@ The router pattern reduces AI context usage:
|
|||||||
### Python Subprocess Communication
|
### Python Subprocess Communication
|
||||||
|
|
||||||
`callKicadScript(command, args)` in `server.ts`:
|
`callKicadScript(command, args)` in `server.ts`:
|
||||||
|
|
||||||
1. Spawns `python3 python/kicad_interface.py` (if not already running)
|
1. Spawns `python3 python/kicad_interface.py` (if not already running)
|
||||||
2. Sends a JSON message: `{"command": "...", "params": {...}}`
|
2. Sends a JSON message: `{"command": "...", "params": {...}}`
|
||||||
3. Reads the JSON response
|
3. Reads the JSON response
|
||||||
@@ -164,6 +168,7 @@ The router pattern reduces AI context usage:
|
|||||||
### Command Routing
|
### Command Routing
|
||||||
|
|
||||||
Commands are routed by name to handler methods. The mapping is defined in `kicad_interface.py`. Each handler:
|
Commands are routed by name to handler methods. The mapping is defined in `kicad_interface.py`. Each handler:
|
||||||
|
|
||||||
1. Receives a params dict
|
1. Receives a params dict
|
||||||
2. Calls the appropriate command class method
|
2. Calls the appropriate command class method
|
||||||
3. Returns a result dict with `success`, `message`, and any additional data
|
3. Returns a result dict with `success`, `message`, and any additional data
|
||||||
@@ -173,12 +178,14 @@ Commands are routed by name to handler methods. The mapping is defined in `kicad
|
|||||||
Two backends for interacting with KiCAD:
|
Two backends for interacting with KiCAD:
|
||||||
|
|
||||||
**SWIG Backend** (default):
|
**SWIG Backend** (default):
|
||||||
|
|
||||||
- Direct Python bindings to KiCAD's C++ API via SWIG
|
- Direct Python bindings to KiCAD's C++ API via SWIG
|
||||||
- Operates on files -- loads .kicad_pcb, modifies in memory, saves back
|
- Operates on files -- loads .kicad_pcb, modifies in memory, saves back
|
||||||
- Works without KiCAD running
|
- Works without KiCAD running
|
||||||
- Requires manual UI reload to see changes
|
- Requires manual UI reload to see changes
|
||||||
|
|
||||||
**IPC Backend** (experimental):
|
**IPC Backend** (experimental):
|
||||||
|
|
||||||
- Communicates with running KiCAD via IPC API socket
|
- Communicates with running KiCAD via IPC API socket
|
||||||
- Changes appear in the UI immediately
|
- Changes appear in the UI immediately
|
||||||
- Requires KiCAD 9.0+ running with IPC enabled
|
- Requires KiCAD 9.0+ running with IPC enabled
|
||||||
@@ -189,6 +196,7 @@ Two backends for interacting with KiCAD:
|
|||||||
### Schematic System
|
### Schematic System
|
||||||
|
|
||||||
Schematic manipulation uses a different stack than PCB operations:
|
Schematic manipulation uses a different stack than PCB operations:
|
||||||
|
|
||||||
- **kicad-skip** library for reading/modifying schematic files
|
- **kicad-skip** library for reading/modifying schematic files
|
||||||
- **S-expression parsing** for direct file manipulation (wires, symbols)
|
- **S-expression parsing** for direct file manipulation (wires, symbols)
|
||||||
- **DynamicSymbolLoader** for injecting any KiCad symbol into a schematic
|
- **DynamicSymbolLoader** for injecting any KiCad symbol into a schematic
|
||||||
@@ -214,7 +222,7 @@ server.tool(
|
|||||||
async (args) => {
|
async (args) => {
|
||||||
const result = await callKicadScript("my_new_tool", args);
|
const result = await callKicadScript("my_new_tool", args);
|
||||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -271,11 +279,13 @@ npm run test:py # Run Python tests
|
|||||||
### Python Tests
|
### Python Tests
|
||||||
|
|
||||||
Located in `python/tests/`. Run with:
|
Located in `python/tests/`. Run with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pytest python/tests/ -v
|
pytest python/tests/ -v
|
||||||
```
|
```
|
||||||
|
|
||||||
Key test files:
|
Key test files:
|
||||||
|
|
||||||
- `test_schematic_tools.py` -- schematic tool tests
|
- `test_schematic_tools.py` -- schematic tool tests
|
||||||
- `test_freerouting.py` -- autorouter tests
|
- `test_freerouting.py` -- autorouter tests
|
||||||
- `test_delete_schematic_component.py` -- component deletion tests
|
- `test_delete_schematic_component.py` -- component deletion tests
|
||||||
@@ -303,7 +313,7 @@ Key test files:
|
|||||||
## Source Files Reference
|
## Source Files Reference
|
||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
|------|---------|
|
| ------------------------------------------ | ----------------------------------- |
|
||||||
| `src/server.ts` | MCP server, subprocess management |
|
| `src/server.ts` | MCP server, subprocess management |
|
||||||
| `src/tools/registry.ts` | Tool categories and organization |
|
| `src/tools/registry.ts` | Tool categories and organization |
|
||||||
| `src/tools/router.ts` | Router meta-tools |
|
| `src/tools/router.ts` | Router meta-tools |
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ This guide shows how to configure the KiCAD MCP Server with various MCP-compatib
|
|||||||
## Quick Reference
|
## Quick Reference
|
||||||
|
|
||||||
| Client | Config File Location |
|
| Client | Config File Location |
|
||||||
|--------|---------------------|
|
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| **Claude Desktop** | Linux: `~/.config/Claude/claude_desktop_config.json`<br>macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`<br>Windows: `%APPDATA%\Claude\claude_desktop_config.json` |
|
| **Claude Desktop** | Linux: `~/.config/Claude/claude_desktop_config.json`<br>macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`<br>Windows: `%APPDATA%\Claude\claude_desktop_config.json` |
|
||||||
| **Cline (VSCode)** | VSCode Settings → Extensions → Cline → MCP Settings |
|
| **Cline (VSCode)** | VSCode Settings → Extensions → Cline → MCP Settings |
|
||||||
| **Claude Code** | `~/.config/claude-code/mcp_config.json` |
|
| **Claude Code** | `~/.config/claude-code/mcp_config.json` |
|
||||||
@@ -194,11 +194,7 @@ For any MCP-compatible client that supports STDIO transport:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"command": "node",
|
"command": "node",
|
||||||
"args": [
|
"args": ["/path/to/KiCAD-MCP-Server/dist/index.js", "--config", "/path/to/custom-config.json"],
|
||||||
"/path/to/KiCAD-MCP-Server/dist/index.js",
|
|
||||||
"--config",
|
|
||||||
"/path/to/custom-config.json"
|
|
||||||
],
|
|
||||||
"transport": "stdio"
|
"transport": "stdio"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -210,13 +206,13 @@ For any MCP-compatible client that supports STDIO transport:
|
|||||||
### Required
|
### Required
|
||||||
|
|
||||||
| Variable | Description | Example |
|
| Variable | Description | Example |
|
||||||
|----------|-------------|---------|
|
| ------------ | ---------------------------- | ------------------------------------------ |
|
||||||
| `PYTHONPATH` | Path to KiCAD Python modules | `/usr/lib/kicad/lib/python3/dist-packages` |
|
| `PYTHONPATH` | Path to KiCAD Python modules | `/usr/lib/kicad/lib/python3/dist-packages` |
|
||||||
|
|
||||||
### Optional
|
### Optional
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
|----------|-------------|---------|
|
| ----------------- | ------------------------------------------------- | -------------- |
|
||||||
| `LOG_LEVEL` | Logging verbosity | `info` |
|
| `LOG_LEVEL` | Logging verbosity | `info` |
|
||||||
| `NODE_ENV` | Node environment | `development` |
|
| `NODE_ENV` | Node environment | `development` |
|
||||||
| `KICAD_BACKEND` | Force backend (`swig` or `ipc`) | Auto-detect |
|
| `KICAD_BACKEND` | Force backend (`swig` or `ipc`) | Auto-detect |
|
||||||
@@ -312,6 +308,7 @@ claude-code
|
|||||||
**Error:** `Cannot find module 'pcbnew'`
|
**Error:** `Cannot find module 'pcbnew'`
|
||||||
|
|
||||||
**Solution:** Verify `PYTHONPATH` is correct:
|
**Solution:** Verify `PYTHONPATH` is correct:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -c "import sys; sys.path.append('/usr/lib/kicad/lib/python3/dist-packages'); import pcbnew; print(pcbnew.GetBuildVersion())"
|
python3 -c "import sys; sys.path.append('/usr/lib/kicad/lib/python3/dist-packages'); import pcbnew; print(pcbnew.GetBuildVersion())"
|
||||||
```
|
```
|
||||||
@@ -319,6 +316,7 @@ python3 -c "import sys; sys.path.append('/usr/lib/kicad/lib/python3/dist-package
|
|||||||
**Error:** `ENOENT: no such file or directory`
|
**Error:** `ENOENT: no such file or directory`
|
||||||
|
|
||||||
**Solution:** Check that `dist/index.js` exists:
|
**Solution:** Check that `dist/index.js` exists:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /path/to/KiCAD-MCP-Server
|
cd /path/to/KiCAD-MCP-Server
|
||||||
npm run build
|
npm run build
|
||||||
@@ -330,6 +328,7 @@ ls -lh dist/index.js
|
|||||||
**Issue:** Claude Desktop doesn't show KiCAD tools
|
**Issue:** Claude Desktop doesn't show KiCAD tools
|
||||||
|
|
||||||
**Solutions:**
|
**Solutions:**
|
||||||
|
|
||||||
1. Restart Claude Desktop completely (quit, not just close window)
|
1. Restart Claude Desktop completely (quit, not just close window)
|
||||||
2. Check config file syntax with `jq`:
|
2. Check config file syntax with `jq`:
|
||||||
```bash
|
```bash
|
||||||
@@ -345,6 +344,7 @@ ls -lh dist/index.js
|
|||||||
**Error:** `ModuleNotFoundError: No module named 'kicad_api'`
|
**Error:** `ModuleNotFoundError: No module named 'kicad_api'`
|
||||||
|
|
||||||
**Solution:** Server is looking for the wrong Python modules. This is an internal error. Check:
|
**Solution:** Server is looking for the wrong Python modules. This is an internal error. Check:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Verify PYTHONPATH in server config includes both KiCAD and our modules
|
# Verify PYTHONPATH in server config includes both KiCAD and our modules
|
||||||
"PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages:/path/to/KiCAD-MCP-Server/python"
|
"PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages:/path/to/KiCAD-MCP-Server/python"
|
||||||
@@ -398,17 +398,14 @@ Then use it:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"command": "node",
|
"command": "node",
|
||||||
"args": [
|
"args": ["/path/to/dist/index.js", "--config", "/path/to/config/production.json"]
|
||||||
"/path/to/dist/index.js",
|
|
||||||
"--config",
|
|
||||||
"/path/to/config/production.json"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Development vs Production
|
### Development vs Production
|
||||||
|
|
||||||
Development (verbose logging):
|
Development (verbose logging):
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
@@ -419,6 +416,7 @@ Development (verbose logging):
|
|||||||
```
|
```
|
||||||
|
|
||||||
Production (minimal logging):
|
Production (minimal logging):
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
@@ -473,10 +471,7 @@ Running server in WSL2, client on Windows:
|
|||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"kicad": {
|
"kicad": {
|
||||||
"command": "wsl",
|
"command": "wsl",
|
||||||
"args": [
|
"args": ["node", "/home/user/KiCAD-MCP-Server/dist/index.js"],
|
||||||
"node",
|
|
||||||
"/home/user/KiCAD-MCP-Server/dist/index.js"
|
|
||||||
],
|
|
||||||
"env": {
|
"env": {
|
||||||
"PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages"
|
"PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Scans a KiCAD schematic and fills in missing Datasheet URLs for components that
|
|||||||
**How it works:**
|
**How it works:**
|
||||||
|
|
||||||
For every placed symbol that has:
|
For every placed symbol that has:
|
||||||
|
|
||||||
- An LCSC property set (e.g., `(property "LCSC" "C123456")`)
|
- An LCSC property set (e.g., `(property "LCSC" "C123456")`)
|
||||||
- An empty or missing Datasheet field
|
- An empty or missing Datasheet field
|
||||||
|
|
||||||
@@ -25,22 +26,25 @@ The URL is then visible in KiCAD's footprint browser, symbol properties dialog,
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Default | Description |
|
| Parameter | Type | Required | Default | Description |
|
||||||
|-----------|------|----------|---------|-------------|
|
| ---------------- | ------- | -------- | ------- | --------------------------------------- |
|
||||||
| `schematic_path` | string | Yes | -- | Path to the .kicad_sch file to enrich |
|
| `schematic_path` | string | Yes | -- | Path to the .kicad_sch file to enrich |
|
||||||
| `dry_run` | boolean | No | false | Preview changes without writing to disk |
|
| `dry_run` | boolean | No | false | Preview changes without writing to disk |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
- Number of components updated
|
- Number of components updated
|
||||||
- Number already set (skipped)
|
- Number already set (skipped)
|
||||||
- Number without LCSC number
|
- Number without LCSC number
|
||||||
- Details of each updated component (reference, LCSC number, URL)
|
- Details of each updated component (reference, LCSC number, URL)
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Enrich datasheets for all components in ~/Projects/MyBoard/MyBoard.kicad_sch
|
Enrich datasheets for all components in ~/Projects/MyBoard/MyBoard.kicad_sch
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `dry_run=true` to preview what would change:
|
Use `dry_run=true` to preview what would change:
|
||||||
|
|
||||||
```
|
```
|
||||||
Preview datasheet enrichment for ~/Projects/MyBoard/MyBoard.kicad_sch with dry run enabled.
|
Preview datasheet enrichment for ~/Projects/MyBoard/MyBoard.kicad_sch with dry run enabled.
|
||||||
```
|
```
|
||||||
@@ -54,14 +58,16 @@ Get the LCSC datasheet URL for a single component by LCSC number.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | -------------------------------------------------------------------------- |
|
||||||
| `lcsc` | string | Yes | LCSC part number, with or without "C" prefix (e.g., "C179739" or "179739") |
|
| `lcsc` | string | Yes | LCSC part number, with or without "C" prefix (e.g., "C179739" or "179739") |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
- Datasheet PDF URL
|
- Datasheet PDF URL
|
||||||
- Product page URL
|
- Product page URL
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Get the datasheet URL for LCSC part C179739.
|
Get the datasheet URL for LCSC part C179739.
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ Footprints define the physical copper pads, silkscreen markings, and courtyard b
|
|||||||
Create a new KiCAD footprint (.kicad_mod) inside a .pretty library directory. Supports SMD and THT pads, courtyard, silkscreen, and fab-layer rectangles.
|
Create a new KiCAD footprint (.kicad_mod) inside a .pretty library directory. Supports SMD and THT pads, courtyard, silkscreen, and fab-layer rectangles.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------------- | ------- | -------- | ------------------------------------------------------------------------------------------ |
|
||||||
| `libraryPath` | string | Yes | Path to the .pretty library directory (created if missing). E.g. C:/MyProject/MyLib.pretty |
|
| `libraryPath` | string | Yes | Path to the .pretty library directory (created if missing). E.g. C:/MyProject/MyLib.pretty |
|
||||||
| `name` | string | Yes | Footprint name, e.g. 'R_0603_Custom' |
|
| `name` | string | Yes | Footprint name, e.g. 'R_0603_Custom' |
|
||||||
| `description` | string | No | Human-readable description |
|
| `description` | string | No | Human-readable description |
|
||||||
@@ -22,7 +22,7 @@ Create a new KiCAD footprint (.kicad_mod) inside a .pretty library directory. Su
|
|||||||
| `courtyard` | object | No | Courtyard rectangle on F.CrtYd (recommended: 0.25 mm clearance around pads) |
|
| `courtyard` | object | No | Courtyard rectangle on F.CrtYd (recommended: 0.25 mm clearance around pads) |
|
||||||
| `silkscreen` | object | No | Silkscreen rectangle on F.SilkS |
|
| `silkscreen` | object | No | Silkscreen rectangle on F.SilkS |
|
||||||
| `fabLayer` | object | No | Fab-layer rectangle on F.Fab (shows component body) |
|
| `fabLayer` | object | No | Fab-layer rectangle on F.Fab (shows component body) |
|
||||||
| `refPosition` | object | No | Position of the REF** text, e.g. {x: 0, y: -1.27} (default: 0, -1.27) |
|
| `refPosition` | object | No | Position of the REF\*\* text, e.g. {x: 0, y: -1.27} (default: 0, -1.27) |
|
||||||
| `valuePosition` | object | No | Position of the Value text, e.g. {x: 0, y: 1.27} (default: 0, 1.27) |
|
| `valuePosition` | object | No | Position of the Value text, e.g. {x: 0, y: 1.27} (default: 0, 1.27) |
|
||||||
| `overwrite` | boolean | No | Replace existing footprint file (default: false) |
|
| `overwrite` | boolean | No | Replace existing footprint file (default: false) |
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ Create a new KiCAD footprint (.kicad_mod) inside a .pretty library directory. Su
|
|||||||
Each pad object in the `pads` array supports:
|
Each pad object in the `pads` array supports:
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ----------------- | ---------------- | -------- | -------------------------------------------------------------------------------------------- |
|
||||||
| `number` | string | Yes | Pad number / name, e.g. '1', '2', 'A1' |
|
| `number` | string | Yes | Pad number / name, e.g. '1', '2', 'A1' |
|
||||||
| `type` | enum | Yes | Pad type: `smd`, `thru_hole`, or `np_thru_hole` |
|
| `type` | enum | Yes | Pad type: `smd`, `thru_hole`, or `np_thru_hole` |
|
||||||
| `shape` | enum | No | Pad shape: `rect`, `circle`, `oval`, or `roundrect` (default: rect for SMD, circle for THT) |
|
| `shape` | enum | No | Pad shape: `rect`, `circle`, `oval`, or `roundrect` (default: rect for SMD, circle for THT) |
|
||||||
@@ -44,7 +44,7 @@ Each pad object in the `pads` array supports:
|
|||||||
#### Rectangle Schema (courtyard, silkscreen, fabLayer)
|
#### Rectangle Schema (courtyard, silkscreen, fabLayer)
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | ---------------- |
|
||||||
| `x1` | number | Yes | Left X in mm |
|
| `x1` | number | Yes | Left X in mm |
|
||||||
| `y1` | number | Yes | Top Y in mm |
|
| `y1` | number | Yes | Top Y in mm |
|
||||||
| `x2` | number | Yes | Right X in mm |
|
| `x2` | number | Yes | Right X in mm |
|
||||||
@@ -54,15 +54,15 @@ Each pad object in the `pads` array supports:
|
|||||||
#### Pad Types
|
#### Pad Types
|
||||||
|
|
||||||
- **SMD (smd)**: Surface-mount pads for components that sit on top of the PCB. Default layers: F.Cu, F.Paste, F.Mask
|
- **SMD (smd)**: Surface-mount pads for components that sit on top of the PCB. Default layers: F.Cu, F.Paste, F.Mask
|
||||||
- **THT (thru_hole)**: Through-hole pads for components with leads that pass through the PCB. Requires `drill` parameter. Default layers: *.Cu, F.Mask, B.Mask
|
- **THT (thru_hole)**: Through-hole pads for components with leads that pass through the PCB. Requires `drill` parameter. Default layers: \*.Cu, F.Mask, B.Mask
|
||||||
- **NPTH (np_thru_hole)**: Non-plated through-holes for mechanical mounting. Requires `drill` parameter. Default layers: *.Mask
|
- **NPTH (np_thru_hole)**: Non-plated through-holes for mechanical mounting. Requires `drill` parameter. Default layers: \*.Mask
|
||||||
|
|
||||||
### edit_footprint_pad
|
### edit_footprint_pad
|
||||||
|
|
||||||
Edit an existing pad inside a .kicad_mod footprint file. Updates size, position, drill, or shape without recreating the whole footprint.
|
Edit an existing pad inside a .kicad_mod footprint file. Updates size, position, drill, or shape without recreating the whole footprint.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------------- | ---------------- | -------- | ---------------------------------------------------------------------------- |
|
||||||
| `footprintPath` | string | Yes | Full path to the .kicad_mod file, e.g. C:/MyLib.pretty/R_Custom.kicad_mod |
|
| `footprintPath` | string | Yes | Full path to the .kicad_mod file, e.g. C:/MyLib.pretty/R_Custom.kicad_mod |
|
||||||
| `padNumber` | string or number | Yes | Pad number to edit, e.g. '1' or 2 |
|
| `padNumber` | string or number | Yes | Pad number to edit, e.g. '1' or 2 |
|
||||||
| `size` | object | No | New pad size: {w: number, h: number} in mm |
|
| `size` | object | No | New pad size: {w: number, h: number} in mm |
|
||||||
@@ -77,7 +77,7 @@ Edit an existing pad inside a .kicad_mod footprint file. Updates size, position,
|
|||||||
Register a .pretty footprint library in KiCAD's fp-lib-table so KiCAD can find the footprints. Run this after create_footprint when KiCAD shows 'library not found in footprint library table'.
|
Register a .pretty footprint library in KiCAD's fp-lib-table so KiCAD can find the footprints. Run this after create_footprint when KiCAD shows 'library not found in footprint library table'.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `libraryPath` | string | Yes | Full path to the .pretty directory to register |
|
| `libraryPath` | string | Yes | Full path to the .pretty directory to register |
|
||||||
| `libraryName` | string | No | Nickname for the library in KiCAD (default: directory name without .pretty) |
|
| `libraryName` | string | No | Nickname for the library in KiCAD (default: directory name without .pretty) |
|
||||||
| `description` | string | No | Optional description |
|
| `description` | string | No | Optional description |
|
||||||
@@ -91,7 +91,7 @@ Register a .pretty footprint library in KiCAD's fp-lib-table so KiCAD can find t
|
|||||||
List available .pretty footprint libraries and their contents (first 20 footprints per library). Searches KiCAD standard install paths by default.
|
List available .pretty footprint libraries and their contents (first 20 footprints per library). Searches KiCAD standard install paths by default.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ----- | -------- | --------------------------------------------------------------------------------------------- |
|
||||||
| `searchPaths` | array | No | Override default search paths. Each entry should be a directory that contains .pretty subdirs |
|
| `searchPaths` | array | No | Override default search paths. Each entry should be a directory that contains .pretty subdirs |
|
||||||
|
|
||||||
### Example: Creating a Custom SOT-23 Footprint
|
### Example: Creating a Custom SOT-23 Footprint
|
||||||
@@ -172,6 +172,7 @@ Create a new schematic symbol in a .kicad_sym library file (created if missing).
|
|||||||
Pin positions are where the wire connects; the symbol body is drawn between them.
|
Pin positions are where the wire connects; the symbol body is drawn between them.
|
||||||
|
|
||||||
**Coordinate tips:**
|
**Coordinate tips:**
|
||||||
|
|
||||||
- Body rectangle typically spans ±2.54 to ±5.08 mm
|
- Body rectangle typically spans ±2.54 to ±5.08 mm
|
||||||
- Pins on left side: at.x = body_left - length, angle=0 (wire goes right)
|
- Pins on left side: at.x = body_left - length, angle=0 (wire goes right)
|
||||||
- Pins on right side: at.x = body_right + length, angle=180 (wire goes left)
|
- Pins on right side: at.x = body_right + length, angle=180 (wire goes left)
|
||||||
@@ -180,7 +181,7 @@ Pin positions are where the wire connects; the symbol body is drawn between them
|
|||||||
- Standard pin length: 2.54 mm, standard grid: 2.54 mm
|
- Standard pin length: 2.54 mm, standard grid: 2.54 mm
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ----------------- | ------- | -------- | ---------------------------------------------------------------------------------------- |
|
||||||
| `libraryPath` | string | Yes | Path to the .kicad_sym file (created if missing) |
|
| `libraryPath` | string | Yes | Path to the .kicad_sym file (created if missing) |
|
||||||
| `name` | string | Yes | Symbol name, e.g. 'TMC2209', 'MyOpAmp' |
|
| `name` | string | Yes | Symbol name, e.g. 'TMC2209', 'MyOpAmp' |
|
||||||
| `referencePrefix` | string | No | Schematic reference prefix: 'U' (IC), 'R' (resistor), 'J' (connector), etc. Default: 'U' |
|
| `referencePrefix` | string | No | Schematic reference prefix: 'U' (IC), 'R' (resistor), 'J' (connector), etc. Default: 'U' |
|
||||||
@@ -200,7 +201,7 @@ Pin positions are where the wire connects; the symbol body is drawn between them
|
|||||||
Each pin object in the `pins` array supports:
|
Each pin object in the `pins` array supports:
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `name` | string | Yes | Pin name, e.g. 'VCC', 'GND', 'IN+', '~' for unnamed |
|
| `name` | string | Yes | Pin name, e.g. 'VCC', 'GND', 'IN+', '~' for unnamed |
|
||||||
| `number` | string or number | Yes | Pin number, e.g. '1', '2', 'A1' |
|
| `number` | string or number | Yes | Pin number, e.g. '1', '2', 'A1' |
|
||||||
| `type` | enum | Yes | Electrical pin type (see Pin Types below) |
|
| `type` | enum | Yes | Electrical pin type (see Pin Types below) |
|
||||||
@@ -209,6 +210,7 @@ Each pin object in the `pins` array supports:
|
|||||||
| `shape` | enum | No | Pin graphic shape (default: line) |
|
| `shape` | enum | No | Pin graphic shape (default: line) |
|
||||||
|
|
||||||
**Pin angle conventions:**
|
**Pin angle conventions:**
|
||||||
|
|
||||||
- 0 = right (wire extends to the right from the symbol body)
|
- 0 = right (wire extends to the right from the symbol body)
|
||||||
- 90 = up (wire extends upward)
|
- 90 = up (wire extends upward)
|
||||||
- 180 = left (wire extends to the left)
|
- 180 = left (wire extends to the left)
|
||||||
@@ -217,7 +219,7 @@ Each pin object in the `pins` array supports:
|
|||||||
#### Pin Types (Electrical)
|
#### Pin Types (Electrical)
|
||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|------|-------------|
|
| ---------------- | ----------------------------------------- |
|
||||||
| `input` | Input pin |
|
| `input` | Input pin |
|
||||||
| `output` | Output pin |
|
| `output` | Output pin |
|
||||||
| `bidirectional` | Bidirectional I/O |
|
| `bidirectional` | Bidirectional I/O |
|
||||||
@@ -234,7 +236,7 @@ Each pin object in the `pins` array supports:
|
|||||||
#### Pin Shapes (Graphical)
|
#### Pin Shapes (Graphical)
|
||||||
|
|
||||||
| Shape | Description |
|
| Shape | Description |
|
||||||
|-------|-------------|
|
| -------------------- | -------------------------- |
|
||||||
| `line` | Standard pin (default) |
|
| `line` | Standard pin (default) |
|
||||||
| `inverted` | Pin with inversion bubble |
|
| `inverted` | Pin with inversion bubble |
|
||||||
| `clock` | Clock input (triangle) |
|
| `clock` | Clock input (triangle) |
|
||||||
@@ -248,7 +250,7 @@ Each pin object in the `pins` array supports:
|
|||||||
#### Rectangle Schema
|
#### Rectangle Schema
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | ------------------------------------------------------------------- |
|
||||||
| `x1` | number | Yes | Left X in mm |
|
| `x1` | number | Yes | Left X in mm |
|
||||||
| `y1` | number | Yes | Top Y in mm |
|
| `y1` | number | Yes | Top Y in mm |
|
||||||
| `x2` | number | Yes | Right X in mm |
|
| `x2` | number | Yes | Right X in mm |
|
||||||
@@ -259,7 +261,7 @@ Each pin object in the `pins` array supports:
|
|||||||
#### Polyline Schema
|
#### Polyline Schema
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | ------------------------------------------------------ |
|
||||||
| `points` | array | Yes | List of XY points: [{x: number, y: number}, ...] in mm |
|
| `points` | array | Yes | List of XY points: [{x: number, y: number}, ...] in mm |
|
||||||
| `width` | number | No | Stroke width in mm (default 0.254) |
|
| `width` | number | No | Stroke width in mm (default 0.254) |
|
||||||
| `fill` | enum | No | Fill type: `none`, `outline`, or `background` |
|
| `fill` | enum | No | Fill type: `none`, `outline`, or `background` |
|
||||||
@@ -269,7 +271,7 @@ Each pin object in the `pins` array supports:
|
|||||||
Remove a symbol from a .kicad_sym library file.
|
Remove a symbol from a .kicad_sym library file.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | --------------------------- |
|
||||||
| `libraryPath` | string | Yes | Path to the .kicad_sym file |
|
| `libraryPath` | string | Yes | Path to the .kicad_sym file |
|
||||||
| `name` | string | Yes | Symbol name to delete |
|
| `name` | string | Yes | Symbol name to delete |
|
||||||
|
|
||||||
@@ -278,7 +280,7 @@ Remove a symbol from a .kicad_sym library file.
|
|||||||
List all symbol names in a .kicad_sym library file.
|
List all symbol names in a .kicad_sym library file.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | --------------------------- |
|
||||||
| `libraryPath` | string | Yes | Path to the .kicad_sym file |
|
| `libraryPath` | string | Yes | Path to the .kicad_sym file |
|
||||||
|
|
||||||
### register_symbol_library
|
### register_symbol_library
|
||||||
@@ -286,7 +288,7 @@ List all symbol names in a .kicad_sym library file.
|
|||||||
Register a .kicad_sym library in KiCAD's sym-lib-table so symbols can be used in schematics. Run this after create_symbol when KiCAD shows 'library not found'.
|
Register a .kicad_sym library in KiCAD's sym-lib-table so symbols can be used in schematics. Run this after create_symbol when KiCAD shows 'library not found'.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ------------------------------------------------------------------------------------- |
|
||||||
| `libraryPath` | string | Yes | Full path to the .kicad_sym file |
|
| `libraryPath` | string | Yes | Full path to the .kicad_sym file |
|
||||||
| `libraryName` | string | No | Nickname (default: file name without extension) |
|
| `libraryName` | string | No | Nickname (default: file name without extension) |
|
||||||
| `description` | string | No | Optional description |
|
| `description` | string | No | Optional description |
|
||||||
@@ -351,6 +353,7 @@ This example creates a 4-pin IC symbol (VCC, GND, IN, OUT):
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Pin positioning explained:**
|
**Pin positioning explained:**
|
||||||
|
|
||||||
- VIN pin at (-7.62, 2.54, angle=0): Wire extends to the right, so the symbol body should be to the right. Body left edge is at -5.08, and pin length is 2.54, so -7.62 = -5.08 - 2.54
|
- VIN pin at (-7.62, 2.54, angle=0): Wire extends to the right, so the symbol body should be to the right. Body left edge is at -5.08, and pin length is 2.54, so -7.62 = -5.08 - 2.54
|
||||||
- GND pin at (0, -7.62, angle=90): Wire extends upward, body bottom is at -5.08, so -7.62 = -5.08 - 2.54
|
- GND pin at (0, -7.62, angle=90): Wire extends upward, body bottom is at -5.08, so -7.62 = -5.08 - 2.54
|
||||||
- VOUT pin at (7.62, 2.54, angle=180): Wire extends to the left, body right is at 5.08, so 7.62 = 5.08 + 2.54
|
- VOUT pin at (7.62, 2.54, angle=180): Wire extends to the left, body right is at 5.08, so 7.62 = 5.08 + 2.54
|
||||||
@@ -397,6 +400,7 @@ Footprints use a "Y-down" coordinate system (like screen coordinates), while sym
|
|||||||
### Validation
|
### Validation
|
||||||
|
|
||||||
After creating custom parts:
|
After creating custom parts:
|
||||||
|
|
||||||
- Open KiCAD schematic editor and verify the symbol appears in the "Add Symbol" dialog
|
- Open KiCAD schematic editor and verify the symbol appears in the "Add Symbol" dialog
|
||||||
- Check pin numbers, names, and electrical types in symbol properties
|
- Check pin numbers, names, and electrical types in symbol properties
|
||||||
- Open KiCAD PCB editor and verify the footprint appears in the footprint browser
|
- Open KiCAD PCB editor and verify the footprint appears in the footprint browser
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ curl -L -o ~/.kicad-mcp/freerouting.jar \
|
|||||||
```
|
```
|
||||||
|
|
||||||
The default location is `~/.kicad-mcp/freerouting.jar`. You can override this with:
|
The default location is `~/.kicad-mcp/freerouting.jar`. You can override this with:
|
||||||
|
|
||||||
- The `freeroutingJar` parameter on any tool call
|
- The `freeroutingJar` parameter on any tool call
|
||||||
- The `FREEROUTING_JAR` environment variable
|
- The `FREEROUTING_JAR` environment variable
|
||||||
|
|
||||||
@@ -85,6 +86,7 @@ Verify that prerequisites are installed before running the autorouter.
|
|||||||
**Returns:** Java availability, version, Docker status, JAR location
|
**Returns:** Java availability, version, Docker status, JAR location
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Check if Freerouting is ready on my system.
|
Check if Freerouting is ready on my system.
|
||||||
```
|
```
|
||||||
@@ -102,6 +104,7 @@ Run the full autorouting workflow (export DSN, route, import SES).
|
|||||||
| `timeout` | number | No | 300 | Timeout in seconds |
|
| `timeout` | number | No | 300 | Timeout in seconds |
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Autoroute the current board using Freerouting with a 5-minute timeout.
|
Autoroute the current board using Freerouting with a 5-minute timeout.
|
||||||
```
|
```
|
||||||
@@ -153,6 +156,7 @@ For advanced users or external autorouters:
|
|||||||
```
|
```
|
||||||
|
|
||||||
This is useful when you want to:
|
This is useful when you want to:
|
||||||
|
|
||||||
- Use the Freerouting GUI for interactive routing
|
- Use the Freerouting GUI for interactive routing
|
||||||
- Use a different autorouter that supports DSN/SES
|
- Use a different autorouter that supports DSN/SES
|
||||||
- Route the board on a different machine
|
- Route the board on a different machine
|
||||||
@@ -190,12 +194,14 @@ Install either Java 21+ or Docker/Podman. See the Prerequisites section above.
|
|||||||
### "Java found but version < 21"
|
### "Java found but version < 21"
|
||||||
|
|
||||||
Freerouting 2.x requires Java 21+. Either:
|
Freerouting 2.x requires Java 21+. Either:
|
||||||
|
|
||||||
- Upgrade your Java installation
|
- Upgrade your Java installation
|
||||||
- Install Docker as a fallback
|
- Install Docker as a fallback
|
||||||
|
|
||||||
### Timeout Errors
|
### Timeout Errors
|
||||||
|
|
||||||
For complex boards, increase the timeout:
|
For complex boards, increase the timeout:
|
||||||
|
|
||||||
```
|
```
|
||||||
Autoroute with timeout 600 and max passes 30.
|
Autoroute with timeout 600 and max passes 30.
|
||||||
```
|
```
|
||||||
@@ -203,6 +209,7 @@ Autoroute with timeout 600 and max passes 30.
|
|||||||
### Routing Quality
|
### Routing Quality
|
||||||
|
|
||||||
If the autorouter does not route all connections:
|
If the autorouter does not route all connections:
|
||||||
|
|
||||||
- Increase `maxPasses` (default: 20)
|
- Increase `maxPasses` (default: 20)
|
||||||
- Check that your design rules allow the autorouter enough clearance
|
- Check that your design rules allow the autorouter enough clearance
|
||||||
- Run DRC after autorouting to identify any violations
|
- Run DRC after autorouting to identify any violations
|
||||||
@@ -211,6 +218,7 @@ If the autorouter does not route all connections:
|
|||||||
### Docker Permission Errors
|
### Docker Permission Errors
|
||||||
|
|
||||||
If Docker reports permission errors:
|
If Docker reports permission errors:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Add your user to the docker group
|
# Add your user to the docker group
|
||||||
sudo usermod -aG docker $USER
|
sudo usermod -aG docker $USER
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ KiCAD MCP Server -- AI-assisted PCB design via Model Context Protocol
|
|||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
| Document | Description |
|
| Document | Description |
|
||||||
|----------|-------------|
|
| ----------------------------------------------- | -------------------------------------------------------------- |
|
||||||
| [README](../README.md) | Project overview, installation, configuration, quick start |
|
| [README](../README.md) | Project overview, installation, configuration, quick start |
|
||||||
| [Client Configuration](CLIENT_CONFIGURATION.md) | MCP client setup (Claude Desktop, Cline, Claude Code) |
|
| [Client Configuration](CLIENT_CONFIGURATION.md) | MCP client setup (Claude Desktop, Cline, Claude Code) |
|
||||||
| [Platform Guide](PLATFORM_GUIDE.md) | Linux vs Windows vs macOS differences |
|
| [Platform Guide](PLATFORM_GUIDE.md) | Linux vs Windows vs macOS differences |
|
||||||
@@ -20,7 +20,7 @@ KiCAD MCP Server -- AI-assisted PCB design via Model Context Protocol
|
|||||||
## Tool References
|
## Tool References
|
||||||
|
|
||||||
| Document | Description |
|
| Document | Description |
|
||||||
|----------|-------------|
|
| ----------------------------------------------------------------------- | ----------------------------------------------------------- |
|
||||||
| [Tool Inventory](TOOL_INVENTORY.md) | Complete list of all 122 tools with access types |
|
| [Tool Inventory](TOOL_INVENTORY.md) | Complete list of all 122 tools with access types |
|
||||||
| [Schematic Tools Reference](SCHEMATIC_TOOLS_REFERENCE.md) | 27 schematic tools -- components, wiring, analysis, export |
|
| [Schematic Tools Reference](SCHEMATIC_TOOLS_REFERENCE.md) | 27 schematic tools -- components, wiring, analysis, export |
|
||||||
| [Routing Tools Reference](ROUTING_TOOLS_REFERENCE.md) | 13 routing tools -- traces, vias, differential pairs, zones |
|
| [Routing Tools Reference](ROUTING_TOOLS_REFERENCE.md) | 13 routing tools -- traces, vias, differential pairs, zones |
|
||||||
@@ -34,7 +34,7 @@ KiCAD MCP Server -- AI-assisted PCB design via Model Context Protocol
|
|||||||
## Integration Guides
|
## Integration Guides
|
||||||
|
|
||||||
| Document | Description |
|
| Document | Description |
|
||||||
|----------|-------------|
|
| --------------------------------------------- | -------------------------------------------------- |
|
||||||
| [JLCPCB Integration](JLCPCB_INTEGRATION.md) | JLCPCB parts catalog, pricing, component selection |
|
| [JLCPCB Integration](JLCPCB_INTEGRATION.md) | JLCPCB parts catalog, pricing, component selection |
|
||||||
| [JLCPCB Usage Guide](JLCPCB_USAGE_GUIDE.md) | Detailed JLCPCB setup and usage |
|
| [JLCPCB Usage Guide](JLCPCB_USAGE_GUIDE.md) | Detailed JLCPCB setup and usage |
|
||||||
| [Library Integration](LIBRARY_INTEGRATION.md) | Footprint and symbol library setup |
|
| [Library Integration](LIBRARY_INTEGRATION.md) | Footprint and symbol library setup |
|
||||||
@@ -45,7 +45,7 @@ KiCAD MCP Server -- AI-assisted PCB design via Model Context Protocol
|
|||||||
## Workflows
|
## Workflows
|
||||||
|
|
||||||
| Document | Description |
|
| Document | Description |
|
||||||
|----------|-------------|
|
| --------------------------------------------- | ----------------------------------------- |
|
||||||
| [Realtime Workflow](REALTIME_WORKFLOW.md) | Working with IPC backend for live updates |
|
| [Realtime Workflow](REALTIME_WORKFLOW.md) | Working with IPC backend for live updates |
|
||||||
| [Visual Feedback](VISUAL_FEEDBACK.md) | UI visual feedback guide |
|
| [Visual Feedback](VISUAL_FEEDBACK.md) | UI visual feedback guide |
|
||||||
| [UI Auto Launch](UI_AUTO_LAUNCH.md) | Automatic KiCAD UI launch feature |
|
| [UI Auto Launch](UI_AUTO_LAUNCH.md) | Automatic KiCAD UI launch feature |
|
||||||
@@ -58,7 +58,7 @@ KiCAD MCP Server -- AI-assisted PCB design via Model Context Protocol
|
|||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
| Document | Description |
|
| Document | Description |
|
||||||
|----------|-------------|
|
| --------------------------------------------------------- | ------------------------------ |
|
||||||
| [Known Issues](KNOWN_ISSUES.md) | Current issues and workarounds |
|
| [Known Issues](KNOWN_ISSUES.md) | Current issues and workarounds |
|
||||||
| [Windows Troubleshooting](WINDOWS_TROUBLESHOOTING.md) | Windows-specific problems |
|
| [Windows Troubleshooting](WINDOWS_TROUBLESHOOTING.md) | Windows-specific problems |
|
||||||
| [Linux Compatibility Audit](LINUX_COMPATIBILITY_AUDIT.md) | Linux platform details |
|
| [Linux Compatibility Audit](LINUX_COMPATIBILITY_AUDIT.md) | Linux platform details |
|
||||||
@@ -68,7 +68,7 @@ KiCAD MCP Server -- AI-assisted PCB design via Model Context Protocol
|
|||||||
## Project Information
|
## Project Information
|
||||||
|
|
||||||
| Document | Description |
|
| Document | Description |
|
||||||
|----------|-------------|
|
| ----------------------------------- | ----------------------------------------- |
|
||||||
| [Status Summary](STATUS_SUMMARY.md) | Current project status and feature matrix |
|
| [Status Summary](STATUS_SUMMARY.md) | Current project status and feature matrix |
|
||||||
| [Roadmap](ROADMAP.md) | Development roadmap and planned features |
|
| [Roadmap](ROADMAP.md) | Development roadmap and planned features |
|
||||||
| [Changelog](../CHANGELOG.md) | Detailed release notes for all versions |
|
| [Changelog](../CHANGELOG.md) | Detailed release notes for all versions |
|
||||||
@@ -78,7 +78,7 @@ KiCAD MCP Server -- AI-assisted PCB design via Model Context Protocol
|
|||||||
## For Contributors
|
## For Contributors
|
||||||
|
|
||||||
| Document | Description |
|
| Document | Description |
|
||||||
|----------|-------------|
|
| ---------------------------------- | ---------------------------------------- |
|
||||||
| [Contributing](../CONTRIBUTING.md) | How to contribute to the project |
|
| [Contributing](../CONTRIBUTING.md) | How to contribute to the project |
|
||||||
| [Architecture](ARCHITECTURE.md) | System architecture and adding new tools |
|
| [Architecture](ARCHITECTURE.md) | System architecture and adding new tools |
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ This feature is experimental and under active testing. The server uses a hybrid
|
|||||||
## Key Differences
|
## Key Differences
|
||||||
|
|
||||||
| Feature | SWIG | IPC |
|
| Feature | SWIG | IPC |
|
||||||
|---------|------|-----|
|
| -------------- | ---------------------- | ------------------------ |
|
||||||
| UI Updates | Manual reload required | Immediate (when working) |
|
| UI Updates | Manual reload required | Immediate (when working) |
|
||||||
| Undo/Redo | Not supported | Transaction support |
|
| Undo/Redo | Not supported | Transaction support |
|
||||||
| API Stability | Deprecated in KiCAD 9 | Official, versioned |
|
| API Stability | Deprecated in KiCAD 9 | Official, versioned |
|
||||||
@@ -28,7 +28,7 @@ This feature is experimental and under active testing. The server uses a hybrid
|
|||||||
The following MCP commands have IPC handlers:
|
The following MCP commands have IPC handlers:
|
||||||
|
|
||||||
| Command | IPC Handler | Status |
|
| Command | IPC Handler | Status |
|
||||||
|---------|-------------|--------|
|
| -------------------------- | ------------------------------- | -------------------- |
|
||||||
| `route_trace` | `_ipc_route_trace` | Implemented |
|
| `route_trace` | `_ipc_route_trace` | Implemented |
|
||||||
| `add_via` | `_ipc_add_via` | Implemented |
|
| `add_via` | `_ipc_add_via` | Implemented |
|
||||||
| `add_net` | `_ipc_add_net` | Implemented |
|
| `add_net` | `_ipc_add_net` | Implemented |
|
||||||
@@ -54,6 +54,7 @@ The following MCP commands have IPC handlers:
|
|||||||
### Implemented Backend Features
|
### Implemented Backend Features
|
||||||
|
|
||||||
**Core Connection:**
|
**Core Connection:**
|
||||||
|
|
||||||
- Connect to running KiCAD instance
|
- Connect to running KiCAD instance
|
||||||
- Auto-detect socket path (`/tmp/kicad/api.sock`)
|
- Auto-detect socket path (`/tmp/kicad/api.sock`)
|
||||||
- Version checking and validation
|
- Version checking and validation
|
||||||
@@ -61,6 +62,7 @@ The following MCP commands have IPC handlers:
|
|||||||
- Change notification callbacks
|
- Change notification callbacks
|
||||||
|
|
||||||
**Board Operations:**
|
**Board Operations:**
|
||||||
|
|
||||||
- Get board reference
|
- Get board reference
|
||||||
- Get/Set board size
|
- Get/Set board size
|
||||||
- List enabled layers
|
- List enabled layers
|
||||||
@@ -69,6 +71,7 @@ The following MCP commands have IPC handlers:
|
|||||||
- Add mounting holes
|
- Add mounting holes
|
||||||
|
|
||||||
**Component Operations:**
|
**Component Operations:**
|
||||||
|
|
||||||
- List all components
|
- List all components
|
||||||
- Place component (hybrid: SWIG for library loading, IPC for placement)
|
- Place component (hybrid: SWIG for library loading, IPC for placement)
|
||||||
- Move component
|
- Move component
|
||||||
@@ -77,6 +80,7 @@ The following MCP commands have IPC handlers:
|
|||||||
- Get component properties
|
- Get component properties
|
||||||
|
|
||||||
**Routing Operations:**
|
**Routing Operations:**
|
||||||
|
|
||||||
- Add track
|
- Add track
|
||||||
- Add via
|
- Add via
|
||||||
- Get all tracks
|
- Get all tracks
|
||||||
@@ -84,16 +88,19 @@ The following MCP commands have IPC handlers:
|
|||||||
- Get all nets
|
- Get all nets
|
||||||
|
|
||||||
**Zone Operations:**
|
**Zone Operations:**
|
||||||
|
|
||||||
- Add copper pour zones
|
- Add copper pour zones
|
||||||
- Get zones list
|
- Get zones list
|
||||||
- Refill zones
|
- Refill zones
|
||||||
|
|
||||||
**UI Integration:**
|
**UI Integration:**
|
||||||
|
|
||||||
- Add text to board
|
- Add text to board
|
||||||
- Get current selection
|
- Get current selection
|
||||||
- Clear selection
|
- Clear selection
|
||||||
|
|
||||||
**Transaction Support:**
|
**Transaction Support:**
|
||||||
|
|
||||||
- Begin transaction
|
- Begin transaction
|
||||||
- Commit transaction (with description for undo)
|
- Commit transaction (with description for undo)
|
||||||
- Rollback transaction
|
- Rollback transaction
|
||||||
@@ -162,20 +169,24 @@ Run the test script to verify IPC functionality:
|
|||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### "Connection failed"
|
### "Connection failed"
|
||||||
|
|
||||||
- Ensure KiCAD is running
|
- Ensure KiCAD is running
|
||||||
- Enable IPC API: `Preferences > Plugins > Enable IPC API Server`
|
- Enable IPC API: `Preferences > Plugins > Enable IPC API Server`
|
||||||
- Check if a board is open
|
- Check if a board is open
|
||||||
|
|
||||||
### "kicad-python not found"
|
### "kicad-python not found"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install kicad-python
|
pip install kicad-python
|
||||||
```
|
```
|
||||||
|
|
||||||
### "Version mismatch"
|
### "Version mismatch"
|
||||||
|
|
||||||
- Update kicad-python: `pip install --upgrade kicad-python`
|
- Update kicad-python: `pip install --upgrade kicad-python`
|
||||||
- Ensure KiCAD 9.0+ is installed
|
- Ensure KiCAD 9.0+ is installed
|
||||||
|
|
||||||
### "No board open"
|
### "No board open"
|
||||||
|
|
||||||
- Open a board in KiCAD's PCB editor before connecting
|
- Open a board in KiCAD's PCB editor before connecting
|
||||||
|
|
||||||
## File Structure
|
## File Structure
|
||||||
|
|||||||
@@ -98,14 +98,17 @@ footprints = db.map_package_to_footprint("0603")
|
|||||||
### JLCSearchClient
|
### JLCSearchClient
|
||||||
|
|
||||||
#### `search_resistors(resistance, package, limit)`
|
#### `search_resistors(resistance, package, limit)`
|
||||||
|
|
||||||
Search for resistors by value and package.
|
Search for resistors by value and package.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `resistance` (int, optional): Resistance in ohms
|
- `resistance` (int, optional): Resistance in ohms
|
||||||
- `package` (str, optional): Package size ("0402", "0603", "0805", etc.)
|
- `package` (str, optional): Package size ("0402", "0603", "0805", etc.)
|
||||||
- `limit` (int): Maximum results (default: 100)
|
- `limit` (int): Maximum results (default: 100)
|
||||||
|
|
||||||
**Returns:** List of resistor dicts with fields:
|
**Returns:** List of resistor dicts with fields:
|
||||||
|
|
||||||
- `lcsc`: LCSC number (integer)
|
- `lcsc`: LCSC number (integer)
|
||||||
- `mfr`: Manufacturer part number
|
- `mfr`: Manufacturer part number
|
||||||
- `package`: Package size
|
- `package`: Package size
|
||||||
@@ -117,9 +120,11 @@ Search for resistors by value and package.
|
|||||||
- `price1`: Unit price in USD
|
- `price1`: Unit price in USD
|
||||||
|
|
||||||
#### `search_capacitors(capacitance, package, limit)`
|
#### `search_capacitors(capacitance, package, limit)`
|
||||||
|
|
||||||
Search for capacitors by value and package.
|
Search for capacitors by value and package.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `capacitance` (float, optional): Capacitance in farads (e.g., 1e-7 for 100nF)
|
- `capacitance` (float, optional): Capacitance in farads (e.g., 1e-7 for 100nF)
|
||||||
- `package` (str, optional): Package size
|
- `package` (str, optional): Package size
|
||||||
- `limit` (int): Maximum results
|
- `limit` (int): Maximum results
|
||||||
@@ -127,9 +132,11 @@ Search for capacitors by value and package.
|
|||||||
**Returns:** List of capacitor dicts
|
**Returns:** List of capacitor dicts
|
||||||
|
|
||||||
#### `search_components(category, limit, offset, **filters)`
|
#### `search_components(category, limit, offset, **filters)`
|
||||||
|
|
||||||
General component search.
|
General component search.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `category` (str): "resistors", "capacitors", "components", etc.
|
- `category` (str): "resistors", "capacitors", "components", etc.
|
||||||
- `limit` (int): Maximum results
|
- `limit` (int): Maximum results
|
||||||
- `offset` (int): Pagination offset
|
- `offset` (int): Pagination offset
|
||||||
@@ -138,9 +145,11 @@ General component search.
|
|||||||
**Returns:** List of component dicts
|
**Returns:** List of component dicts
|
||||||
|
|
||||||
#### `download_all_components(callback, batch_size)`
|
#### `download_all_components(callback, batch_size)`
|
||||||
|
|
||||||
Download entire JLCPCB parts catalog.
|
Download entire JLCPCB parts catalog.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `callback` (callable, optional): Progress callback(parts_count, status_msg)
|
- `callback` (callable, optional): Progress callback(parts_count, status_msg)
|
||||||
- `batch_size` (int): Parts per batch (default: 1000)
|
- `batch_size` (int): Parts per batch (default: 1000)
|
||||||
|
|
||||||
@@ -151,16 +160,20 @@ Download entire JLCPCB parts catalog.
|
|||||||
### JLCPCBPartsManager
|
### JLCPCBPartsManager
|
||||||
|
|
||||||
#### `import_jlcsearch_parts(parts, progress_callback)`
|
#### `import_jlcsearch_parts(parts, progress_callback)`
|
||||||
|
|
||||||
Import parts from JLCSearch into local SQLite database.
|
Import parts from JLCSearch into local SQLite database.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `parts` (list): List of part dicts from JLCSearchClient
|
- `parts` (list): List of part dicts from JLCSearchClient
|
||||||
- `progress_callback` (callable, optional): Progress updates
|
- `progress_callback` (callable, optional): Progress updates
|
||||||
|
|
||||||
#### `search_parts(query, category, package, library_type, manufacturer, in_stock, limit)`
|
#### `search_parts(query, category, package, library_type, manufacturer, in_stock, limit)`
|
||||||
|
|
||||||
Search local database with filters.
|
Search local database with filters.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `query` (str, optional): Free-text search
|
- `query` (str, optional): Free-text search
|
||||||
- `category` (str, optional): Category filter
|
- `category` (str, optional): Category filter
|
||||||
- `package` (str, optional): Package filter
|
- `package` (str, optional): Package filter
|
||||||
@@ -172,17 +185,21 @@ Search local database with filters.
|
|||||||
**Returns:** List of matching parts
|
**Returns:** List of matching parts
|
||||||
|
|
||||||
#### `get_part_info(lcsc_number)`
|
#### `get_part_info(lcsc_number)`
|
||||||
|
|
||||||
Get detailed part information.
|
Get detailed part information.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `lcsc_number` (str): LCSC part number (e.g., "C25804")
|
- `lcsc_number` (str): LCSC part number (e.g., "C25804")
|
||||||
|
|
||||||
**Returns:** Part dict or None
|
**Returns:** Part dict or None
|
||||||
|
|
||||||
#### `get_database_stats()`
|
#### `get_database_stats()`
|
||||||
|
|
||||||
Get database statistics.
|
Get database statistics.
|
||||||
|
|
||||||
**Returns:** Dict with:
|
**Returns:** Dict with:
|
||||||
|
|
||||||
- `total_parts`: Total parts count
|
- `total_parts`: Total parts count
|
||||||
- `basic_parts`: Basic library count
|
- `basic_parts`: Basic library count
|
||||||
- `extended_parts`: Extended library count
|
- `extended_parts`: Extended library count
|
||||||
@@ -190,9 +207,11 @@ Get database statistics.
|
|||||||
- `db_path`: Database file path
|
- `db_path`: Database file path
|
||||||
|
|
||||||
#### `map_package_to_footprint(package)`
|
#### `map_package_to_footprint(package)`
|
||||||
|
|
||||||
Map JLCPCB package to KiCad footprints.
|
Map JLCPCB package to KiCad footprints.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `package` (str): JLCPCB package name
|
- `package` (str): JLCPCB package name
|
||||||
|
|
||||||
**Returns:** List of KiCad footprint library references
|
**Returns:** List of KiCad footprint library references
|
||||||
@@ -239,7 +258,7 @@ CREATE TABLE components (
|
|||||||
## Package to Footprint Mappings
|
## Package to Footprint Mappings
|
||||||
|
|
||||||
| JLCPCB Package | KiCad Footprints |
|
| JLCPCB Package | KiCad Footprints |
|
||||||
|----------------|------------------|
|
| -------------- | ------------------------------------------------------------------------------------------------ |
|
||||||
| 0402 | Resistor_SMD:R_0402_1005Metric<br>Capacitor_SMD:C_0402_1005Metric<br>LED_SMD:LED_0402_1005Metric |
|
| 0402 | Resistor_SMD:R_0402_1005Metric<br>Capacitor_SMD:C_0402_1005Metric<br>LED_SMD:LED_0402_1005Metric |
|
||||||
| 0603 | Resistor_SMD:R_0603_1608Metric<br>Capacitor_SMD:C_0603_1608Metric<br>LED_SMD:LED_0603_1608Metric |
|
| 0603 | Resistor_SMD:R_0603_1608Metric<br>Capacitor_SMD:C_0603_1608Metric<br>LED_SMD:LED_0603_1608Metric |
|
||||||
| 0805 | Resistor_SMD:R_0805_2012Metric<br>Capacitor_SMD:C_0805_2012Metric |
|
| 0805 | Resistor_SMD:R_0805_2012Metric<br>Capacitor_SMD:C_0805_2012Metric |
|
||||||
@@ -254,6 +273,7 @@ CREATE TABLE components (
|
|||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
### 1. Always Use Basic Library Parts First
|
### 1. Always Use Basic Library Parts First
|
||||||
|
|
||||||
Basic library parts have **no assembly fee** ($0/part), while Extended parts cost **$3/part**.
|
Basic library parts have **no assembly fee** ($0/part), while Extended parts cost **$3/part**.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -262,6 +282,7 @@ basic_parts = [p for p in results if p['is_basic']]
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 2. Check Stock Availability
|
### 2. Check Stock Availability
|
||||||
|
|
||||||
Ensure sufficient stock before committing to a design.
|
Ensure sufficient stock before committing to a design.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -270,6 +291,7 @@ high_stock = [p for p in results if p['stock'] > 1000]
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 3. Compare Prices
|
### 3. Compare Prices
|
||||||
|
|
||||||
Even within Basic library, prices vary significantly.
|
Even within Basic library, prices vary significantly.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -278,9 +300,11 @@ cheapest = min(results, key=lambda x: x.get('price1', 999))
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 4. Use Standardized Packages
|
### 4. Use Standardized Packages
|
||||||
|
|
||||||
Stick to common packages (0402, 0603, 0805) for better availability and pricing.
|
Stick to common packages (0402, 0603, 0805) for better availability and pricing.
|
||||||
|
|
||||||
### 5. Cache Database Locally
|
### 5. Cache Database Locally
|
||||||
|
|
||||||
Download the full parts database once and search locally for faster results.
|
Download the full parts database once and search locally for faster results.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -296,23 +320,29 @@ results = db.search_parts(...)
|
|||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### API Rate Limiting
|
### API Rate Limiting
|
||||||
|
|
||||||
JLCSearch is a community service. If you hit rate limits:
|
JLCSearch is a community service. If you hit rate limits:
|
||||||
|
|
||||||
- Add delays between requests (`time.sleep(0.1)`)
|
- Add delays between requests (`time.sleep(0.1)`)
|
||||||
- Use the local database instead of repeated API calls
|
- Use the local database instead of repeated API calls
|
||||||
- Download the full database once and work offline
|
- Download the full database once and work offline
|
||||||
|
|
||||||
### Missing Data
|
### Missing Data
|
||||||
|
|
||||||
JLCSearch may not have all fields that official JLCPCB API provides:
|
JLCSearch may not have all fields that official JLCPCB API provides:
|
||||||
|
|
||||||
- No datasheets (use manufacturer website)
|
- No datasheets (use manufacturer website)
|
||||||
- Limited category information
|
- Limited category information
|
||||||
- No solder joint count
|
- No solder joint count
|
||||||
|
|
||||||
### Stock Discrepancies
|
### Stock Discrepancies
|
||||||
|
|
||||||
Stock levels are updated periodically but may lag real-time JLCPCB data by a few hours.
|
Stock levels are updated periodically but may lag real-time JLCPCB data by a few hours.
|
||||||
|
|
||||||
## Official JLCPCB API (Alternative)
|
## Official JLCPCB API (Alternative)
|
||||||
|
|
||||||
The project also includes an implementation of the official JLCPCB API with HMAC-SHA256 authentication. However, this requires:
|
The project also includes an implementation of the official JLCPCB API with HMAC-SHA256 authentication. However, this requires:
|
||||||
|
|
||||||
1. API approval from JLCPCB (not all applications are approved)
|
1. API approval from JLCPCB (not all applications are approved)
|
||||||
2. APP_ID, ACCESS_KEY, and SECRET_KEY credentials
|
2. APP_ID, ACCESS_KEY, and SECRET_KEY credentials
|
||||||
3. Previous order history with JLCPCB
|
3. Previous order history with JLCPCB
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ All approaches can be used together to give you maximum flexibility.
|
|||||||
## Approach 1: JLCSearch Public API (Recommended)
|
## Approach 1: JLCSearch Public API (Recommended)
|
||||||
|
|
||||||
### What It Does
|
### What It Does
|
||||||
|
|
||||||
- Access to 2.5M+ JLCPCB parts with pricing and stock data
|
- Access to 2.5M+ JLCPCB parts with pricing and stock data
|
||||||
- **No authentication required** - works immediately
|
- **No authentication required** - works immediately
|
||||||
- **No JLCPCB account needed**
|
- **No JLCPCB account needed**
|
||||||
@@ -39,6 +40,7 @@ download_jlcpcb_database({ force: false })
|
|||||||
This downloads ~2.5M parts from JLCSearch API and creates a local SQLite database (`data/jlcpcb_parts.db`).
|
This downloads ~2.5M parts from JLCSearch API and creates a local SQLite database (`data/jlcpcb_parts.db`).
|
||||||
|
|
||||||
**Expected Output:**
|
**Expected Output:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Downloading JLCPCB parts database...
|
Downloading JLCPCB parts database...
|
||||||
Downloaded 100 parts...
|
Downloaded 100 parts...
|
||||||
@@ -59,6 +61,7 @@ See "Approach 2" usage examples below - the API is the same.
|
|||||||
## Approach 2: Local Symbol Libraries (Good for Offline Use)
|
## Approach 2: Local Symbol Libraries (Good for Offline Use)
|
||||||
|
|
||||||
### What It Does
|
### What It Does
|
||||||
|
|
||||||
- Searches symbol libraries you've installed via KiCad's Plugin and Content Manager (PCM)
|
- Searches symbol libraries you've installed via KiCad's Plugin and Content Manager (PCM)
|
||||||
- Works with community JLCPCB libraries like `JLCPCB-KiCad-Library`
|
- Works with community JLCPCB libraries like `JLCPCB-KiCad-Library`
|
||||||
- No API credentials needed
|
- No API credentials needed
|
||||||
@@ -81,6 +84,7 @@ See "Approach 2" usage examples below - the API is the same.
|
|||||||
### Usage Examples
|
### Usage Examples
|
||||||
|
|
||||||
#### Search for Components
|
#### Search for Components
|
||||||
|
|
||||||
```
|
```
|
||||||
search_symbols({
|
search_symbols({
|
||||||
query: "ESP32",
|
query: "ESP32",
|
||||||
@@ -89,6 +93,7 @@ search_symbols({
|
|||||||
```
|
```
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
```
|
```
|
||||||
Found 12 symbols matching "ESP32":
|
Found 12 symbols matching "ESP32":
|
||||||
|
|
||||||
@@ -98,6 +103,7 @@ PCM_JLCPCB-MCUs:ESP32-S2 | LCSC: C701342 | ESP32-S2 WiFi SoC
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### Search by LCSC ID
|
#### Search by LCSC ID
|
||||||
|
|
||||||
```
|
```
|
||||||
search_symbols({
|
search_symbols({
|
||||||
query: "C2934196" // Direct LCSC ID search
|
query: "C2934196" // Direct LCSC ID search
|
||||||
@@ -105,6 +111,7 @@ search_symbols({
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### Get Symbol Details
|
#### Get Symbol Details
|
||||||
|
|
||||||
```
|
```
|
||||||
get_symbol_info({
|
get_symbol_info({
|
||||||
symbol: "PCM_JLCPCB-MCUs:ESP32-C3"
|
symbol: "PCM_JLCPCB-MCUs:ESP32-C3"
|
||||||
@@ -112,6 +119,7 @@ get_symbol_info({
|
|||||||
```
|
```
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
```
|
```
|
||||||
Symbol: PCM_JLCPCB-MCUs:ESP32-C3
|
Symbol: PCM_JLCPCB-MCUs:ESP32-C3
|
||||||
Description: ESP32-C3 RISC-V WiFi/BLE SoC
|
Description: ESP32-C3 RISC-V WiFi/BLE SoC
|
||||||
@@ -123,6 +131,7 @@ Class: Extended
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Advantages
|
### Advantages
|
||||||
|
|
||||||
- ✅ No API credentials required
|
- ✅ No API credentials required
|
||||||
- ✅ Works offline after library installation
|
- ✅ Works offline after library installation
|
||||||
- ✅ Symbols pre-configured with correct footprints
|
- ✅ Symbols pre-configured with correct footprints
|
||||||
@@ -130,6 +139,7 @@ Class: Extended
|
|||||||
- ✅ Instant availability
|
- ✅ Instant availability
|
||||||
|
|
||||||
### Limitations
|
### Limitations
|
||||||
|
|
||||||
- ❌ Only parts in installed libraries (typically 1k-10k parts)
|
- ❌ Only parts in installed libraries (typically 1k-10k parts)
|
||||||
- ❌ No real-time pricing or stock information
|
- ❌ No real-time pricing or stock information
|
||||||
- ❌ Requires manual library updates via PCM
|
- ❌ Requires manual library updates via PCM
|
||||||
@@ -139,6 +149,7 @@ Class: Extended
|
|||||||
## Approach 3: Official JLCPCB API (Advanced - Enterprise Accounts Only)
|
## Approach 3: Official JLCPCB API (Advanced - Enterprise Accounts Only)
|
||||||
|
|
||||||
### What It Does
|
### What It Does
|
||||||
|
|
||||||
- Downloads from the **official JLCPCB API** (requires enterprise account)
|
- Downloads from the **official JLCPCB API** (requires enterprise account)
|
||||||
- Provides **real-time pricing and stock information**
|
- Provides **real-time pricing and stock information**
|
||||||
- Automatic **Basic vs Extended** library type identification (Basic = free assembly)
|
- Automatic **Basic vs Extended** library type identification (Basic = free assembly)
|
||||||
@@ -150,6 +161,7 @@ Class: Extended
|
|||||||
#### 1. Get JLCPCB API Credentials
|
#### 1. Get JLCPCB API Credentials
|
||||||
|
|
||||||
Visit [JLCPCB](https://jlcpcb.com/) and get your API credentials:
|
Visit [JLCPCB](https://jlcpcb.com/) and get your API credentials:
|
||||||
|
|
||||||
1. Log in to your JLCPCB account
|
1. Log in to your JLCPCB account
|
||||||
2. Go to: **Account → API Management**
|
2. Go to: **Account → API Management**
|
||||||
3. Click "Create API Key"
|
3. Click "Create API Key"
|
||||||
@@ -182,6 +194,7 @@ download_jlcpcb_database({ force: false })
|
|||||||
This downloads ~100k parts from JLCPCB and creates a local SQLite database (`data/jlcpcb_parts.db`).
|
This downloads ~100k parts from JLCPCB and creates a local SQLite database (`data/jlcpcb_parts.db`).
|
||||||
|
|
||||||
**Output:**
|
**Output:**
|
||||||
|
|
||||||
```
|
```
|
||||||
✓ Successfully downloaded JLCPCB parts database
|
✓ Successfully downloaded JLCPCB parts database
|
||||||
|
|
||||||
@@ -205,6 +218,7 @@ search_jlcpcb_parts({
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Found 15 JLCPCB parts:
|
Found 15 JLCPCB parts:
|
||||||
|
|
||||||
@@ -225,6 +239,7 @@ get_jlcpcb_part({
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```
|
```
|
||||||
LCSC: C58972
|
LCSC: C58972
|
||||||
MFR Part: 0603WAF1002T5E
|
MFR Part: 0603WAF1002T5E
|
||||||
@@ -257,6 +272,7 @@ suggest_jlcpcb_alternatives({
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Alternative parts for C25804:
|
Alternative parts for C25804:
|
||||||
|
|
||||||
@@ -289,6 +305,7 @@ get_jlcpcb_database_stats({})
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```
|
```
|
||||||
JLCPCB Database Statistics:
|
JLCPCB Database Statistics:
|
||||||
|
|
||||||
@@ -300,6 +317,7 @@ Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Advantages
|
### Advantages
|
||||||
|
|
||||||
- ✅ Complete JLCPCB catalog (100k+ parts)
|
- ✅ Complete JLCPCB catalog (100k+ parts)
|
||||||
- ✅ Real-time pricing and stock data
|
- ✅ Real-time pricing and stock data
|
||||||
- ✅ Automatic Basic/Extended identification
|
- ✅ Automatic Basic/Extended identification
|
||||||
@@ -308,6 +326,7 @@ Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db
|
|||||||
- ✅ Fast parametric search
|
- ✅ Fast parametric search
|
||||||
|
|
||||||
### Limitations
|
### Limitations
|
||||||
|
|
||||||
- ❌ Requires API credentials
|
- ❌ Requires API credentials
|
||||||
- ❌ Initial download takes 5-10 minutes
|
- ❌ Initial download takes 5-10 minutes
|
||||||
- ❌ Database needs periodic updates for latest parts
|
- ❌ Database needs periodic updates for latest parts
|
||||||
@@ -320,6 +339,7 @@ Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db
|
|||||||
### Workflow 1: Design with Known Components
|
### Workflow 1: Design with Known Components
|
||||||
|
|
||||||
**Use Local Libraries:**
|
**Use Local Libraries:**
|
||||||
|
|
||||||
```
|
```
|
||||||
1. search_symbols({ query: "STM32F103", library: "JLCPCB" })
|
1. search_symbols({ query: "STM32F103", library: "JLCPCB" })
|
||||||
2. Select component from installed library
|
2. Select component from installed library
|
||||||
@@ -331,6 +351,7 @@ Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db
|
|||||||
### Workflow 2: Find Optimal Part for Cost
|
### Workflow 2: Find Optimal Part for Cost
|
||||||
|
|
||||||
**Use JLCPCB API:**
|
**Use JLCPCB API:**
|
||||||
|
|
||||||
```
|
```
|
||||||
1. search_jlcpcb_parts({
|
1. search_jlcpcb_parts({
|
||||||
query: "10k resistor",
|
query: "10k resistor",
|
||||||
@@ -346,6 +367,7 @@ Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db
|
|||||||
### Workflow 3: Explore Unknown Parts
|
### Workflow 3: Explore Unknown Parts
|
||||||
|
|
||||||
**Start with API, verify with Libraries:**
|
**Start with API, verify with Libraries:**
|
||||||
|
|
||||||
```
|
```
|
||||||
1. search_jlcpcb_parts({ query: "ESP32", limit: 20 })
|
1. search_jlcpcb_parts({ query: "ESP32", limit: 20 })
|
||||||
2. Find interesting part (e.g., C2934196)
|
2. Find interesting part (e.g., C2934196)
|
||||||
@@ -393,6 +415,7 @@ search_jlcpcb_parts({
|
|||||||
### 4. Calculate BOM Cost
|
### 4. Calculate BOM Cost
|
||||||
|
|
||||||
For each part in your design:
|
For each part in your design:
|
||||||
|
|
||||||
1. Use `get_jlcpcb_part()` to get price breaks
|
1. Use `get_jlcpcb_part()` to get price breaks
|
||||||
2. Sum up total cost based on order quantity
|
2. Sum up total cost based on order quantity
|
||||||
3. Check library_type count (each unique Extended part = $3 fee)
|
3. Check library_type count (each unique Extended part = $3 fee)
|
||||||
@@ -422,6 +445,7 @@ Future versions will support incremental updates that only fetch new/changed par
|
|||||||
### "JLCPCB API credentials not configured"
|
### "JLCPCB API credentials not configured"
|
||||||
|
|
||||||
**Solution:** Set environment variables:
|
**Solution:** Set environment variables:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export JLCPCB_API_KEY="your_key"
|
export JLCPCB_API_KEY="your_key"
|
||||||
export JLCPCB_API_SECRET="your_secret"
|
export JLCPCB_API_SECRET="your_secret"
|
||||||
@@ -430,6 +454,7 @@ export JLCPCB_API_SECRET="your_secret"
|
|||||||
### "Database not found or empty"
|
### "Database not found or empty"
|
||||||
|
|
||||||
**Solution:** Run:
|
**Solution:** Run:
|
||||||
|
|
||||||
```
|
```
|
||||||
download_jlcpcb_database({ force: false })
|
download_jlcpcb_database({ force: false })
|
||||||
```
|
```
|
||||||
@@ -437,6 +462,7 @@ download_jlcpcb_database({ force: false })
|
|||||||
### "No symbols found" (Local Libraries)
|
### "No symbols found" (Local Libraries)
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Install JLCPCB libraries via KiCad PCM
|
1. Install JLCPCB libraries via KiCad PCM
|
||||||
2. Verify library is enabled in KiCad symbol library table
|
2. Verify library is enabled in KiCad symbol library table
|
||||||
3. Restart KiCad MCP server
|
3. Restart KiCad MCP server
|
||||||
@@ -444,6 +470,7 @@ download_jlcpcb_database({ force: false })
|
|||||||
### "Authentication failed"
|
### "Authentication failed"
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Verify your API credentials are correct
|
1. Verify your API credentials are correct
|
||||||
2. Check JLCPCB account has API access enabled
|
2. Check JLCPCB account has API access enabled
|
||||||
3. Try regenerating API key/secret in JLCPCB dashboard
|
3. Try regenerating API key/secret in JLCPCB dashboard
|
||||||
@@ -453,7 +480,7 @@ download_jlcpcb_database({ force: false })
|
|||||||
## API vs Libraries: Quick Reference
|
## API vs Libraries: Quick Reference
|
||||||
|
|
||||||
| Feature | Local Libraries | JLCPCB API |
|
| Feature | Local Libraries | JLCPCB API |
|
||||||
|---------|----------------|------------|
|
| --------------------- | ------------------ | -------------------------- |
|
||||||
| **Parts Count** | 1k-10k (installed) | 100k+ (complete catalog) |
|
| **Parts Count** | 1k-10k (installed) | 100k+ (complete catalog) |
|
||||||
| **Setup** | Install via PCM | API credentials + download |
|
| **Setup** | Install via PCM | API credentials + download |
|
||||||
| **Offline Use** | ✅ Yes | ✅ Yes (after download) |
|
| **Offline Use** | ✅ Yes | ✅ Yes (after download) |
|
||||||
@@ -505,12 +532,14 @@ search_symbols({ query: "USB-C" })
|
|||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
**Use Local Libraries when:**
|
**Use Local Libraries when:**
|
||||||
|
|
||||||
- Starting a new design with common components
|
- Starting a new design with common components
|
||||||
- You want pre-configured, tested symbols
|
- You want pre-configured, tested symbols
|
||||||
- Working offline
|
- Working offline
|
||||||
- Components are in installed libraries
|
- Components are in installed libraries
|
||||||
|
|
||||||
**Use JLCPCB API when:**
|
**Use JLCPCB API when:**
|
||||||
|
|
||||||
- Optimizing cost (find cheapest Basic parts)
|
- Optimizing cost (find cheapest Basic parts)
|
||||||
- Checking real-time stock availability
|
- Checking real-time stock availability
|
||||||
- Exploring parts outside installed libraries
|
- Exploring parts outside installed libraries
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ This document tracks known issues and provides workarounds where available.
|
|||||||
**Status:** KNOWN - Non-critical
|
**Status:** KNOWN - Non-critical
|
||||||
|
|
||||||
**Symptoms:**
|
**Symptoms:**
|
||||||
|
|
||||||
```
|
```
|
||||||
AttributeError: 'BOARD' object has no attribute 'LT_USER'
|
AttributeError: 'BOARD' object has no attribute 'LT_USER'
|
||||||
```
|
```
|
||||||
@@ -31,10 +32,12 @@ AttributeError: 'BOARD' object has no attribute 'LT_USER'
|
|||||||
**Status:** KNOWN - Workaround available
|
**Status:** KNOWN - Workaround available
|
||||||
|
|
||||||
**Symptoms:**
|
**Symptoms:**
|
||||||
|
|
||||||
- Copper pours created but not filled automatically when using SWIG backend
|
- Copper pours created but not filled automatically when using SWIG backend
|
||||||
- Calling `ZONE_FILLER` via SWIG causes segfault
|
- Calling `ZONE_FILLER` via SWIG causes segfault
|
||||||
|
|
||||||
**Workaround Options:**
|
**Workaround Options:**
|
||||||
|
|
||||||
1. Use IPC backend (zones fill correctly via IPC)
|
1. Use IPC backend (zones fill correctly via IPC)
|
||||||
2. Open the board in KiCAD UI -- zones fill automatically when opened
|
2. Open the board in KiCAD UI -- zones fill automatically when opened
|
||||||
3. Use `refill_zones` tool (may still segfault in some configurations)
|
3. Use `refill_zones` tool (may still segfault in some configurations)
|
||||||
@@ -48,6 +51,7 @@ AttributeError: 'BOARD' object has no attribute 'LT_USER'
|
|||||||
**Status:** BY DESIGN
|
**Status:** BY DESIGN
|
||||||
|
|
||||||
**Symptoms:**
|
**Symptoms:**
|
||||||
|
|
||||||
- MCP makes changes via SWIG backend
|
- MCP makes changes via SWIG backend
|
||||||
- KiCAD does not show changes until file is reloaded
|
- KiCAD does not show changes until file is reloaded
|
||||||
|
|
||||||
@@ -64,6 +68,7 @@ AttributeError: 'BOARD' object has no attribute 'LT_USER'
|
|||||||
**Status:** EXPERIMENTAL
|
**Status:** EXPERIMENTAL
|
||||||
|
|
||||||
**Known Limitations:**
|
**Known Limitations:**
|
||||||
|
|
||||||
- KiCAD must be running with IPC enabled (Preferences > Plugins > Enable IPC API Server)
|
- KiCAD must be running with IPC enabled (Preferences > Plugins > Enable IPC API Server)
|
||||||
- Some commands fall back to SWIG (e.g., delete_trace)
|
- Some commands fall back to SWIG (e.g., delete_trace)
|
||||||
- Footprint loading uses hybrid approach (SWIG for library, IPC for placement)
|
- Footprint loading uses hybrid approach (SWIG for library, IPC for placement)
|
||||||
@@ -85,32 +90,40 @@ AttributeError: 'BOARD' object has no attribute 'LT_USER'
|
|||||||
## Recently Fixed (v2.2.0 - v2.2.3)
|
## Recently Fixed (v2.2.0 - v2.2.3)
|
||||||
|
|
||||||
### B.Cu Footprint Routing (Fixed v2.2.3)
|
### B.Cu Footprint Routing (Fixed v2.2.3)
|
||||||
|
|
||||||
- `route_pad_to_pad` now correctly detects B.Cu footprints and inserts vias
|
- `route_pad_to_pad` now correctly detects B.Cu footprints and inserts vias
|
||||||
- KiCAD 9 SWIG `pad.GetLayerName()` always returned F.Cu for flipped footprints -- fixed using `footprint.GetLayer()`
|
- KiCAD 9 SWIG `pad.GetLayerName()` always returned F.Cu for flipped footprints -- fixed using `footprint.GetLayer()`
|
||||||
|
|
||||||
### B.Cu Placement Hang (Fixed v2.2.3)
|
### B.Cu Placement Hang (Fixed v2.2.3)
|
||||||
|
|
||||||
- Placing footprints on B.Cu no longer causes ~30s freeze
|
- Placing footprints on B.Cu no longer causes ~30s freeze
|
||||||
- Fix: call `board.Add()` before `Flip()`
|
- Fix: call `board.Add()` before `Flip()`
|
||||||
|
|
||||||
### Board Outline Rounded Corners (Fixed v2.2.3)
|
### Board Outline Rounded Corners (Fixed v2.2.3)
|
||||||
|
|
||||||
- `add_board_outline` now correctly applies cornerRadius for rounded_rectangle shape
|
- `add_board_outline` now correctly applies cornerRadius for rounded_rectangle shape
|
||||||
|
|
||||||
### Project-Local Library Resolution (Fixed v2.2.2)
|
### Project-Local Library Resolution (Fixed v2.2.2)
|
||||||
|
|
||||||
- `add_schematic_component` and `place_component` now search project-local sym-lib-table and fp-lib-table
|
- `add_schematic_component` and `place_component` now search project-local sym-lib-table and fp-lib-table
|
||||||
- Previously only global KiCAD library paths were searched
|
- Previously only global KiCAD library paths were searched
|
||||||
|
|
||||||
### Template File Corruption (Fixed v2.2.2)
|
### Template File Corruption (Fixed v2.2.2)
|
||||||
|
|
||||||
- Removed invalid `;;` comment lines from template schematics
|
- Removed invalid `;;` comment lines from template schematics
|
||||||
- Restored KiCAD 9 format version (20250114) in templates
|
- Restored KiCAD 9 format version (20250114) in templates
|
||||||
|
|
||||||
### copy_routing_pattern Empty Results (Fixed v2.2.2)
|
### copy_routing_pattern Empty Results (Fixed v2.2.2)
|
||||||
|
|
||||||
- Added geometric fallback when pads have no net assignments
|
- Added geometric fallback when pads have no net assignments
|
||||||
|
|
||||||
### Schematic Component Corruption (Fixed v2.2.1)
|
### Schematic Component Corruption (Fixed v2.2.1)
|
||||||
|
|
||||||
- `add_schematic_component` no longer corrupts .kicad_sch files
|
- `add_schematic_component` no longer corrupts .kicad_sch files
|
||||||
- Rewritten to use text manipulation instead of sexpdata formatting
|
- Rewritten to use text manipulation instead of sexpdata formatting
|
||||||
|
|
||||||
### SWIG/UUID Comparison Bugs (Fixed v2.2.0)
|
### SWIG/UUID Comparison Bugs (Fixed v2.2.0)
|
||||||
|
|
||||||
- Fixed SwigPyObject UUID comparison
|
- Fixed SwigPyObject UUID comparison
|
||||||
- Fixed SWIG iterator invalidation after board.Remove()
|
- Fixed SWIG iterator invalidation after board.Remove()
|
||||||
- Added board.SetModified() to prevent dangling pointer crashes
|
- Added board.SetModified() to prevent dangling pointer crashes
|
||||||
@@ -136,6 +149,7 @@ If you encounter an issue not listed here:
|
|||||||
## General Workarounds
|
## General Workarounds
|
||||||
|
|
||||||
### Server Will Not Start
|
### Server Will Not Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check Python can import pcbnew
|
# Check Python can import pcbnew
|
||||||
python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
||||||
@@ -145,12 +159,14 @@ python3 python/utils/platform_helper.py
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Commands Fail After Server Restart
|
### Commands Fail After Server Restart
|
||||||
|
|
||||||
```
|
```
|
||||||
# Board reference is lost on restart
|
# Board reference is lost on restart
|
||||||
# Always run open_project after server restart
|
# Always run open_project after server restart
|
||||||
```
|
```
|
||||||
|
|
||||||
### KiCAD UI Does Not Show Changes (SWIG Mode)
|
### KiCAD UI Does Not Show Changes (SWIG Mode)
|
||||||
|
|
||||||
```
|
```
|
||||||
# File > Revert (or click reload prompt)
|
# File > Revert (or click reload prompt)
|
||||||
# Or: Close and reopen file in KiCAD
|
# Or: Close and reopen file in KiCAD
|
||||||
@@ -158,6 +174,7 @@ python3 python/utils/platform_helper.py
|
|||||||
```
|
```
|
||||||
|
|
||||||
### IPC Not Connecting
|
### IPC Not Connecting
|
||||||
|
|
||||||
```
|
```
|
||||||
# Ensure KiCAD is running
|
# Ensure KiCAD is running
|
||||||
# Enable IPC: Preferences > Plugins > Enable IPC API Server
|
# Enable IPC: Preferences > Plugins > Enable IPC API Server
|
||||||
@@ -168,6 +185,7 @@ python3 python/utils/platform_helper.py
|
|||||||
---
|
---
|
||||||
|
|
||||||
**Need Help?**
|
**Need Help?**
|
||||||
|
|
||||||
- Check [IPC_BACKEND_STATUS.md](IPC_BACKEND_STATUS.md) for IPC details
|
- Check [IPC_BACKEND_STATUS.md](IPC_BACKEND_STATUS.md) for IPC details
|
||||||
- Check logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
- Check logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
||||||
- Open an issue on GitHub
|
- Open an issue on GitHub
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The KiCAD MCP Server includes full library integration for both footprints and symbols, enabling:
|
The KiCAD MCP Server includes full library integration for both footprints and symbols, enabling:
|
||||||
|
|
||||||
- ✅ Automatic discovery of all installed KiCAD footprint libraries
|
- ✅ Automatic discovery of all installed KiCAD footprint libraries
|
||||||
- ✅ Automatic discovery of KiCAD symbol libraries (including project-local)
|
- ✅ Automatic discovery of KiCAD symbol libraries (including project-local)
|
||||||
- ✅ Search and browse footprints/symbols across all libraries
|
- ✅ Search and browse footprints/symbols across all libraries
|
||||||
@@ -45,6 +46,7 @@ The library system automatically discovers both footprint and symbol libraries:
|
|||||||
### Supported Formats
|
### Supported Formats
|
||||||
|
|
||||||
**Library:Footprint format (recommended):**
|
**Library:Footprint format (recommended):**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"componentId": "Resistor_SMD:R_0603_1608Metric"
|
"componentId": "Resistor_SMD:R_0603_1608Metric"
|
||||||
@@ -52,6 +54,7 @@ The library system automatically discovers both footprint and symbol libraries:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Footprint-only format (searches all libraries):**
|
**Footprint-only format (searches all libraries):**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"componentId": "R_0603_1608Metric"
|
"componentId": "R_0603_1608Metric"
|
||||||
@@ -67,6 +70,7 @@ List all available footprint libraries.
|
|||||||
**Parameters:** None
|
**Parameters:** None
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -80,6 +84,7 @@ List all available footprint libraries.
|
|||||||
Search for footprints matching a pattern.
|
Search for footprints matching a pattern.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"pattern": "*0603*", // Supports wildcards
|
"pattern": "*0603*", // Supports wildcards
|
||||||
@@ -88,6 +93,7 @@ Search for footprints matching a pattern.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -107,6 +113,7 @@ Search for footprints matching a pattern.
|
|||||||
List all footprints in a specific library.
|
List all footprints in a specific library.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"library": "Resistor_SMD"
|
"library": "Resistor_SMD"
|
||||||
@@ -114,6 +121,7 @@ List all footprints in a specific library.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -128,6 +136,7 @@ List all footprints in a specific library.
|
|||||||
Get detailed information about a specific footprint.
|
Get detailed information about a specific footprint.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"footprint": "Resistor_SMD:R_0603_1608Metric"
|
"footprint": "Resistor_SMD:R_0603_1608Metric"
|
||||||
@@ -135,6 +144,7 @@ Get detailed information about a specific footprint.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -154,7 +164,7 @@ The `place_component` tool now uses the library system:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"componentId": "Resistor_SMD:R_0603_1608Metric", // Library:Footprint format
|
"componentId": "Resistor_SMD:R_0603_1608Metric", // Library:Footprint format
|
||||||
"position": {"x": 50, "y": 40, "unit": "mm"},
|
"position": { "x": 50, "y": 40, "unit": "mm" },
|
||||||
"reference": "R1",
|
"reference": "R1",
|
||||||
"value": "10k",
|
"value": "10k",
|
||||||
"rotation": 0,
|
"rotation": 0,
|
||||||
@@ -163,6 +173,7 @@ The `place_component` tool now uses the library system:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
|
|
||||||
- ✅ Automatic footprint discovery across all libraries
|
- ✅ Automatic footprint discovery across all libraries
|
||||||
- ✅ Helpful error messages with suggestions
|
- ✅ Helpful error messages with suggestions
|
||||||
- ✅ Supports KiCAD 9.0 API (EDA_ANGLE, GetFPIDAsString)
|
- ✅ Supports KiCAD 9.0 API (EDA_ANGLE, GetFPIDAsString)
|
||||||
@@ -170,6 +181,7 @@ The `place_component` tool now uses the library system:
|
|||||||
## Example Usage (Claude Code)
|
## Example Usage (Claude Code)
|
||||||
|
|
||||||
**Search for a resistor footprint:**
|
**Search for a resistor footprint:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Find me a 0603 resistor footprint"
|
User: "Find me a 0603 resistor footprint"
|
||||||
|
|
||||||
@@ -178,6 +190,7 @@ Claude: [uses search_footprints tool with pattern "*R_0603*"]
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Place a component:**
|
**Place a component:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Place a 10k 0603 resistor at 50,40mm"
|
User: "Place a 10k 0603 resistor at 50,40mm"
|
||||||
|
|
||||||
@@ -186,6 +199,7 @@ Claude: [uses place_component with "Resistor_SMD:R_0603_1608Metric"]
|
|||||||
```
|
```
|
||||||
|
|
||||||
**List available capacitors:**
|
**List available capacitors:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "What capacitor footprints are available?"
|
User: "What capacitor footprints are available?"
|
||||||
|
|
||||||
@@ -223,18 +237,22 @@ The system automatically detects KiCAD installations, but you can add custom lib
|
|||||||
The library integration includes full KiCAD 9.0 API support:
|
The library integration includes full KiCAD 9.0 API support:
|
||||||
|
|
||||||
### Fixed API Changes:
|
### Fixed API Changes:
|
||||||
|
|
||||||
1. ✅ `SetOrientation()` → now uses `EDA_ANGLE(degrees, DEGREES_T)`
|
1. ✅ `SetOrientation()` → now uses `EDA_ANGLE(degrees, DEGREES_T)`
|
||||||
2. ✅ `GetOrientation()` → returns `EDA_ANGLE`, call `.AsDegrees()`
|
2. ✅ `GetOrientation()` → returns `EDA_ANGLE`, call `.AsDegrees()`
|
||||||
3. ✅ `GetFootprintName()` → now `GetFPIDAsString()`
|
3. ✅ `GetFootprintName()` → now `GetFPIDAsString()`
|
||||||
|
|
||||||
### Example Fixes:
|
### Example Fixes:
|
||||||
|
|
||||||
**Old (KiCAD 8.0):**
|
**Old (KiCAD 8.0):**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
module.SetOrientation(90 * 10) # Decidegrees
|
module.SetOrientation(90 * 10) # Decidegrees
|
||||||
rotation = module.GetOrientation() / 10
|
rotation = module.GetOrientation() / 10
|
||||||
```
|
```
|
||||||
|
|
||||||
**New (KiCAD 9.0):**
|
**New (KiCAD 9.0):**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
angle = pcbnew.EDA_ANGLE(90, pcbnew.DEGREES_T)
|
angle = pcbnew.EDA_ANGLE(90, pcbnew.DEGREES_T)
|
||||||
module.SetOrientation(angle)
|
module.SetOrientation(angle)
|
||||||
@@ -248,6 +266,7 @@ rotation = module.GetOrientation().AsDegrees()
|
|||||||
**Location:** `python/commands/library.py`
|
**Location:** `python/commands/library.py`
|
||||||
|
|
||||||
**Key Methods:**
|
**Key Methods:**
|
||||||
|
|
||||||
- `_load_libraries()` - Parse fp-lib-table files
|
- `_load_libraries()` - Parse fp-lib-table files
|
||||||
- `_parse_fp_lib_table()` - S-expression parser
|
- `_parse_fp_lib_table()` - S-expression parser
|
||||||
- `_resolve_uri()` - Handle environment variables
|
- `_resolve_uri()` - Handle environment variables
|
||||||
@@ -256,6 +275,7 @@ rotation = module.GetOrientation().AsDegrees()
|
|||||||
- `list_footprints()` - List library contents
|
- `list_footprints()` - List library contents
|
||||||
|
|
||||||
**Performance:**
|
**Performance:**
|
||||||
|
|
||||||
- Libraries loaded once at startup
|
- Libraries loaded once at startup
|
||||||
- Footprint lists cached on first access
|
- Footprint lists cached on first access
|
||||||
- Fast search using Python regex
|
- Fast search using Python regex
|
||||||
@@ -281,6 +301,7 @@ rotation = module.GetOrientation().AsDegrees()
|
|||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
**Test Coverage:**
|
**Test Coverage:**
|
||||||
|
|
||||||
- ✅ Library path discovery (Linux/Windows/macOS)
|
- ✅ Library path discovery (Linux/Windows/macOS)
|
||||||
- ✅ fp-lib-table parsing
|
- ✅ fp-lib-table parsing
|
||||||
- ✅ Environment variable resolution
|
- ✅ Environment variable resolution
|
||||||
@@ -289,6 +310,7 @@ rotation = module.GetOrientation().AsDegrees()
|
|||||||
- ✅ Error handling and suggestions
|
- ✅ Error handling and suggestions
|
||||||
|
|
||||||
**Verified With:**
|
**Verified With:**
|
||||||
|
|
||||||
- KiCAD 9.0.5 on Ubuntu 24.04
|
- KiCAD 9.0.5 on Ubuntu 24.04
|
||||||
- 153 standard libraries (8,000+ footprints)
|
- 153 standard libraries (8,000+ footprints)
|
||||||
- pcbnew Python API
|
- pcbnew Python API
|
||||||
@@ -316,6 +338,7 @@ rotation = module.GetOrientation().AsDegrees()
|
|||||||
**Cause:** fp-lib-table not found or empty
|
**Cause:** fp-lib-table not found or empty
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Verify KiCAD is installed
|
1. Verify KiCAD is installed
|
||||||
2. Open KiCAD and ensure libraries are configured
|
2. Open KiCAD and ensure libraries are configured
|
||||||
3. Check `~/.config/kicad/9.0/fp-lib-table` exists
|
3. Check `~/.config/kicad/9.0/fp-lib-table` exists
|
||||||
@@ -325,6 +348,7 @@ rotation = module.GetOrientation().AsDegrees()
|
|||||||
**Cause:** Footprint doesn't exist or library not loaded
|
**Cause:** Footprint doesn't exist or library not loaded
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Use `search_footprints` to find similar footprints
|
1. Use `search_footprints` to find similar footprints
|
||||||
2. Check library name is correct
|
2. Check library name is correct
|
||||||
3. Verify library is in fp-lib-table
|
3. Verify library is in fp-lib-table
|
||||||
@@ -334,6 +358,7 @@ rotation = module.GetOrientation().AsDegrees()
|
|||||||
**Cause:** Corrupt .kicad_mod file or permissions issue
|
**Cause:** Corrupt .kicad_mod file or permissions issue
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Check file permissions on library directories
|
1. Check file permissions on library directories
|
||||||
2. Reinstall KiCAD libraries if corrupt
|
2. Reinstall KiCAD libraries if corrupt
|
||||||
3. Check logs for detailed error
|
3. Check logs for detailed error
|
||||||
@@ -348,6 +373,7 @@ rotation = module.GetOrientation().AsDegrees()
|
|||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
**2026-03-21 - v2.2.3+**
|
**2026-03-21 - v2.2.3+**
|
||||||
|
|
||||||
- ✅ Project-local symbol library support (v2.2.2)
|
- ✅ Project-local symbol library support (v2.2.2)
|
||||||
- ✅ Project-local footprint library support (v2.2.2)
|
- ✅ Project-local footprint library support (v2.2.2)
|
||||||
- ✅ Implemented LibraryManager class
|
- ✅ Implemented LibraryManager class
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Linux Compatibility Audit Report
|
# Linux Compatibility Audit Report
|
||||||
|
|
||||||
**Date:** 2025-10-25
|
**Date:** 2025-10-25
|
||||||
**Target Platform:** Ubuntu 24.04 LTS (primary), Fedora, Arch (secondary)
|
**Target Platform:** Ubuntu 24.04 LTS (primary), Fedora, Arch (secondary)
|
||||||
**Current Status:** Windows-optimized, partial Linux support
|
**Current Status:** Windows-optimized, partial Linux support
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
The KiCAD MCP Server was originally developed for Windows and has several compatibility issues preventing smooth operation on Linux. This audit identifies all platform-specific issues and provides remediation priorities.
|
The KiCAD MCP Server was originally developed for Windows and has several compatibility issues preventing smooth operation on Linux. This audit identifies all platform-specific issues and provides remediation priorities.
|
||||||
|
|
||||||
**Overall Status:** 🟡 **PARTIAL COMPATIBILITY**
|
**Overall Status:** 🟡 **PARTIAL COMPATIBILITY**
|
||||||
|
|
||||||
- ✅ TypeScript server: Good cross-platform support
|
- ✅ TypeScript server: Good cross-platform support
|
||||||
- 🟡 Python interface: Mixed (some hardcoded paths)
|
- 🟡 Python interface: Mixed (some hardcoded paths)
|
||||||
- ❌ Configuration: Windows-specific examples
|
- ❌ Configuration: Windows-specific examples
|
||||||
@@ -20,7 +22,9 @@ The KiCAD MCP Server was originally developed for Windows and has several compat
|
|||||||
## Critical Issues (P0 - Must Fix)
|
## Critical Issues (P0 - Must Fix)
|
||||||
|
|
||||||
### 1. Hardcoded Windows Paths in Config Examples
|
### 1. Hardcoded Windows Paths in Config Examples
|
||||||
|
|
||||||
**File:** `config/claude-desktop-config.json`
|
**File:** `config/claude-desktop-config.json`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"cwd": "c:/repo/KiCAD-MCP",
|
"cwd": "c:/repo/KiCAD-MCP",
|
||||||
"PYTHONPATH": "C:/Program Files/KiCad/9.0/lib/python3/dist-packages"
|
"PYTHONPATH": "C:/Program Files/KiCad/9.0/lib/python3/dist-packages"
|
||||||
@@ -33,7 +37,9 @@ The KiCAD MCP Server was originally developed for Windows and has several compat
|
|||||||
---
|
---
|
||||||
|
|
||||||
### 2. Library Search Paths (Mixed Approach)
|
### 2. Library Search Paths (Mixed Approach)
|
||||||
|
|
||||||
**File:** `python/commands/library_schematic.py:16`
|
**File:** `python/commands/library_schematic.py:16`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
search_paths = [
|
search_paths = [
|
||||||
"C:/Program Files/KiCad/*/share/kicad/symbols/*.kicad_sym", # Windows
|
"C:/Program Files/KiCad/*/share/kicad/symbols/*.kicad_sym", # Windows
|
||||||
@@ -49,7 +55,9 @@ search_paths = [
|
|||||||
---
|
---
|
||||||
|
|
||||||
### 3. Python Path Detection
|
### 3. Python Path Detection
|
||||||
|
|
||||||
**File:** `python/kicad_interface.py:38-45`
|
**File:** `python/kicad_interface.py:38-45`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
kicad_paths = [
|
kicad_paths = [
|
||||||
os.path.join(os.path.dirname(sys.executable), 'Lib', 'site-packages'),
|
os.path.join(os.path.dirname(sys.executable), 'Lib', 'site-packages'),
|
||||||
@@ -66,9 +74,11 @@ kicad_paths = [
|
|||||||
## High Priority Issues (P1)
|
## High Priority Issues (P1)
|
||||||
|
|
||||||
### 4. Documentation is Windows-Only
|
### 4. Documentation is Windows-Only
|
||||||
|
|
||||||
**Files:** `README.md`, installation instructions
|
**Files:** `README.md`, installation instructions
|
||||||
|
|
||||||
**Issues:**
|
**Issues:**
|
||||||
|
|
||||||
- Installation paths reference `C:\Program Files`
|
- Installation paths reference `C:\Program Files`
|
||||||
- VSCode settings path is Windows format
|
- VSCode settings path is Windows format
|
||||||
- No Linux-specific troubleshooting
|
- No Linux-specific troubleshooting
|
||||||
@@ -79,6 +89,7 @@ kicad_paths = [
|
|||||||
---
|
---
|
||||||
|
|
||||||
### 5. Missing Python Dependencies Documentation
|
### 5. Missing Python Dependencies Documentation
|
||||||
|
|
||||||
**File:** None (no requirements.txt)
|
**File:** None (no requirements.txt)
|
||||||
|
|
||||||
**Impact:** Users don't know what Python packages to install
|
**Impact:** Users don't know what Python packages to install
|
||||||
@@ -88,6 +99,7 @@ kicad_paths = [
|
|||||||
---
|
---
|
||||||
|
|
||||||
### 6. Path Handling Uses os.path Instead of pathlib
|
### 6. Path Handling Uses os.path Instead of pathlib
|
||||||
|
|
||||||
**Files:** All Python files (11 files)
|
**Files:** All Python files (11 files)
|
||||||
|
|
||||||
**Impact:** Code is less readable and more error-prone
|
**Impact:** Code is less readable and more error-prone
|
||||||
@@ -99,6 +111,7 @@ kicad_paths = [
|
|||||||
## Medium Priority Issues (P2)
|
## Medium Priority Issues (P2)
|
||||||
|
|
||||||
### 7. No Linux-Specific Testing
|
### 7. No Linux-Specific Testing
|
||||||
|
|
||||||
**Impact:** Can't verify Linux compatibility
|
**Impact:** Can't verify Linux compatibility
|
||||||
**Fix:** Add GitHub Actions with Ubuntu runner
|
**Fix:** Add GitHub Actions with Ubuntu runner
|
||||||
**Priority:** P2
|
**Priority:** P2
|
||||||
@@ -106,9 +119,11 @@ kicad_paths = [
|
|||||||
---
|
---
|
||||||
|
|
||||||
### 8. Log File Paths May Differ
|
### 8. Log File Paths May Differ
|
||||||
|
|
||||||
**File:** `src/logger.ts:13`
|
**File:** `src/logger.ts:13`
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
const DEFAULT_LOG_DIR = join(os.homedir(), ".kicad-mcp", "logs");
|
||||||
```
|
```
|
||||||
|
|
||||||
**Impact:** `.kicad-mcp` is okay for Linux, but best practice is `~/.config/kicad-mcp`
|
**Impact:** `.kicad-mcp` is okay for Linux, but best practice is `~/.config/kicad-mcp`
|
||||||
@@ -118,6 +133,7 @@ const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
|||||||
---
|
---
|
||||||
|
|
||||||
### 9. No Bash/Shell Scripts for Linux
|
### 9. No Bash/Shell Scripts for Linux
|
||||||
|
|
||||||
**Impact:** Manual setup is harder on Linux
|
**Impact:** Manual setup is harder on Linux
|
||||||
**Fix:** Create `install.sh` and `run.sh` scripts
|
**Fix:** Create `install.sh` and `run.sh` scripts
|
||||||
**Priority:** P2
|
**Priority:** P2
|
||||||
@@ -127,6 +143,7 @@ const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
|||||||
## Low Priority Issues (P3)
|
## Low Priority Issues (P3)
|
||||||
|
|
||||||
### 10. TypeScript Build Uses Windows Conventions
|
### 10. TypeScript Build Uses Windows Conventions
|
||||||
|
|
||||||
**File:** `package.json`
|
**File:** `package.json`
|
||||||
|
|
||||||
**Impact:** Works but could be more Linux-friendly
|
**Impact:** Works but could be more Linux-friendly
|
||||||
@@ -151,6 +168,7 @@ const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
|||||||
### **Week 1 - Critical Fixes (P0)**
|
### **Week 1 - Critical Fixes (P0)**
|
||||||
|
|
||||||
1. **Create Platform-Specific Config Templates**
|
1. **Create Platform-Specific Config Templates**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
config/
|
config/
|
||||||
├── linux-config.example.json
|
├── linux-config.example.json
|
||||||
@@ -159,6 +177,7 @@ const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
|||||||
```
|
```
|
||||||
|
|
||||||
2. **Fix Python Path Detection**
|
2. **Fix Python Path Detection**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Detect platform and set appropriate paths
|
# Detect platform and set appropriate paths
|
||||||
import platform
|
import platform
|
||||||
@@ -187,6 +206,7 @@ const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
|||||||
### **Week 1 - High Priority (P1)**
|
### **Week 1 - High Priority (P1)**
|
||||||
|
|
||||||
4. **Create requirements.txt**
|
4. **Create requirements.txt**
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
# requirements.txt
|
# requirements.txt
|
||||||
kicad-skip>=0.1.0
|
kicad-skip>=0.1.0
|
||||||
@@ -209,6 +229,7 @@ const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
|||||||
## Testing Checklist
|
## Testing Checklist
|
||||||
|
|
||||||
### Ubuntu 24.04 LTS Testing
|
### Ubuntu 24.04 LTS Testing
|
||||||
|
|
||||||
- [ ] Install KiCAD 9.0 from official PPA
|
- [ ] Install KiCAD 9.0 from official PPA
|
||||||
- [ ] Install Node.js 18+ from NodeSource
|
- [ ] Install Node.js 18+ from NodeSource
|
||||||
- [ ] Clone repository
|
- [ ] Clone repository
|
||||||
@@ -220,10 +241,12 @@ const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
|||||||
- [ ] Test: Export Gerbers
|
- [ ] Test: Export Gerbers
|
||||||
|
|
||||||
### Fedora Testing
|
### Fedora Testing
|
||||||
|
|
||||||
- [ ] Install KiCAD from Fedora repos
|
- [ ] Install KiCAD from Fedora repos
|
||||||
- [ ] Test same workflow
|
- [ ] Test same workflow
|
||||||
|
|
||||||
### Arch Testing
|
### Arch Testing
|
||||||
|
|
||||||
- [ ] Install KiCAD from AUR
|
- [ ] Install KiCAD from AUR
|
||||||
- [ ] Test same workflow
|
- [ ] Test same workflow
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ Create a new KiCAD project named "LEDBoard" in ~/Projects/
|
|||||||
```
|
```
|
||||||
|
|
||||||
This uses `create_project` to generate:
|
This uses `create_project` to generate:
|
||||||
|
|
||||||
- `.kicad_pro` -- project file
|
- `.kicad_pro` -- project file
|
||||||
- `.kicad_pcb` -- PCB layout file
|
- `.kicad_pcb` -- PCB layout file
|
||||||
- `.kicad_sch` -- schematic file (with template symbols pre-loaded)
|
- `.kicad_sch` -- schematic file (with template symbols pre-loaded)
|
||||||
@@ -119,6 +120,7 @@ Align all resistors horizontally.
|
|||||||
### Route Traces
|
### Route Traces
|
||||||
|
|
||||||
**Preferred approach -- pad-to-pad routing:**
|
**Preferred approach -- pad-to-pad routing:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Route R1 pad 2 to LED1 pad 1 with 0.3mm trace width.
|
Route R1 pad 2 to LED1 pad 1 with 0.3mm trace width.
|
||||||
```
|
```
|
||||||
@@ -126,6 +128,7 @@ Route R1 pad 2 to LED1 pad 1 with 0.3mm trace width.
|
|||||||
**Tool:** `route_pad_to_pad` -- auto-detects pad positions, nets, and inserts vias when pads are on different layers
|
**Tool:** `route_pad_to_pad` -- auto-detects pad positions, nets, and inserts vias when pads are on different layers
|
||||||
|
|
||||||
**Manual approach:**
|
**Manual approach:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Route a trace from x=15, y=25 to x=25, y=25 on the front copper layer.
|
Route a trace from x=15, y=25 to x=25, y=25 on the front copper layer.
|
||||||
```
|
```
|
||||||
@@ -135,11 +138,13 @@ Route a trace from x=15, y=25 to x=25, y=25 on the front copper layer.
|
|||||||
### Advanced Routing
|
### Advanced Routing
|
||||||
|
|
||||||
**Differential pairs:**
|
**Differential pairs:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Route a differential pair for USB_P and USB_N with 0.2mm width and 0.15mm gap.
|
Route a differential pair for USB_P and USB_N with 0.2mm width and 0.15mm gap.
|
||||||
```
|
```
|
||||||
|
|
||||||
**Copper zones:**
|
**Copper zones:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Add a GND copper pour on the bottom layer covering the entire board.
|
Add a GND copper pour on the bottom layer covering the entire board.
|
||||||
```
|
```
|
||||||
@@ -149,6 +154,7 @@ Add a GND copper pour on the bottom layer covering the entire board.
|
|||||||
### Autorouting
|
### Autorouting
|
||||||
|
|
||||||
For boards with many connections:
|
For boards with many connections:
|
||||||
|
|
||||||
```
|
```
|
||||||
Check if Freerouting is available.
|
Check if Freerouting is available.
|
||||||
Autoroute the board using Freerouting.
|
Autoroute the board using Freerouting.
|
||||||
@@ -246,6 +252,7 @@ Suggest alternatives to part C25804.
|
|||||||
```
|
```
|
||||||
|
|
||||||
After selecting parts, enrich datasheets:
|
After selecting parts, enrich datasheets:
|
||||||
|
|
||||||
```
|
```
|
||||||
Enrich datasheets for all components in the schematic.
|
Enrich datasheets for all components in the schematic.
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ This guide explains the differences between using KiCAD MCP Server on Linux and
|
|||||||
## Quick Comparison
|
## Quick Comparison
|
||||||
|
|
||||||
| Feature | Linux | Windows |
|
| Feature | Linux | Windows |
|
||||||
|---------|-------|---------|
|
| ------------------------ | ------------------------- | ------------------------------- |
|
||||||
| **Primary Support** | Full (tested extensively) | Community tested |
|
| **Primary Support** | Full (tested extensively) | Community tested |
|
||||||
| **Setup Complexity** | Moderate | Easy (automated script) |
|
| **Setup Complexity** | Moderate | Easy (automated script) |
|
||||||
| **Prerequisites** | Manual package management | Automated detection |
|
| **Prerequisites** | Manual package management | Automated detection |
|
||||||
@@ -25,12 +25,14 @@ This guide explains the differences between using KiCAD MCP Server on Linux and
|
|||||||
### Linux Installation
|
### Linux Installation
|
||||||
|
|
||||||
**Advantages:**
|
**Advantages:**
|
||||||
|
|
||||||
- Native package manager integration
|
- Native package manager integration
|
||||||
- Better tested and documented
|
- Better tested and documented
|
||||||
- More predictable Python environments
|
- More predictable Python environments
|
||||||
- Standard Unix paths
|
- Standard Unix paths
|
||||||
|
|
||||||
**Process:**
|
**Process:**
|
||||||
|
|
||||||
1. Install KiCAD 9.0 via package manager (apt, dnf, pacman)
|
1. Install KiCAD 9.0 via package manager (apt, dnf, pacman)
|
||||||
2. Install Node.js via package manager or nvm
|
2. Install Node.js via package manager or nvm
|
||||||
3. Clone repository
|
3. Clone repository
|
||||||
@@ -40,6 +42,7 @@ This guide explains the differences between using KiCAD MCP Server on Linux and
|
|||||||
7. Set PYTHONPATH environment variable
|
7. Set PYTHONPATH environment variable
|
||||||
|
|
||||||
**Typical paths:**
|
**Typical paths:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
KiCAD Python: /usr/lib/kicad/lib/python3/dist-packages
|
KiCAD Python: /usr/lib/kicad/lib/python3/dist-packages
|
||||||
Node.js: /usr/bin/node
|
Node.js: /usr/bin/node
|
||||||
@@ -47,6 +50,7 @@ Python: /usr/bin/python3
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Configuration example:**
|
**Configuration example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
@@ -64,12 +68,14 @@ Python: /usr/bin/python3
|
|||||||
### Windows Installation
|
### Windows Installation
|
||||||
|
|
||||||
**Advantages:**
|
**Advantages:**
|
||||||
|
|
||||||
- Automated setup script handles everything
|
- Automated setup script handles everything
|
||||||
- KiCAD includes bundled Python (no system Python needed)
|
- KiCAD includes bundled Python (no system Python needed)
|
||||||
- Better error diagnostics
|
- Better error diagnostics
|
||||||
- Comprehensive troubleshooting guide
|
- Comprehensive troubleshooting guide
|
||||||
|
|
||||||
**Process:**
|
**Process:**
|
||||||
|
|
||||||
1. Install KiCAD 9.0 from official installer
|
1. Install KiCAD 9.0 from official installer
|
||||||
2. Install Node.js from official installer
|
2. Install Node.js from official installer
|
||||||
3. Clone repository
|
3. Clone repository
|
||||||
@@ -82,6 +88,7 @@ Python: /usr/bin/python3
|
|||||||
- Validates setup
|
- Validates setup
|
||||||
|
|
||||||
**Typical paths:**
|
**Typical paths:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
KiCAD Python: C:\Program Files\KiCad\9.0\bin\python.exe
|
KiCAD Python: C:\Program Files\KiCad\9.0\bin\python.exe
|
||||||
KiCAD Libraries: C:\Program Files\KiCad\9.0\lib\python3\dist-packages
|
KiCAD Libraries: C:\Program Files\KiCad\9.0\lib\python3\dist-packages
|
||||||
@@ -89,6 +96,7 @@ Node.js: C:\Program Files\nodejs\node.exe
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Configuration example:**
|
**Configuration example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
@@ -108,12 +116,14 @@ Node.js: C:\Program Files\nodejs\node.exe
|
|||||||
## Path Handling
|
## Path Handling
|
||||||
|
|
||||||
### Linux Paths
|
### Linux Paths
|
||||||
|
|
||||||
- Use forward slashes: `/home/user/project`
|
- Use forward slashes: `/home/user/project`
|
||||||
- Case-sensitive filesystem
|
- Case-sensitive filesystem
|
||||||
- No drive letters
|
- No drive letters
|
||||||
- Symbolic links commonly used
|
- Symbolic links commonly used
|
||||||
|
|
||||||
**Example commands:**
|
**Example commands:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /home/username/KiCAD-MCP-Server
|
cd /home/username/KiCAD-MCP-Server
|
||||||
export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
||||||
@@ -121,6 +131,7 @@ python3 -c "import pcbnew"
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Windows Paths
|
### Windows Paths
|
||||||
|
|
||||||
- Use backslashes in native commands: `C:\Users\username`
|
- Use backslashes in native commands: `C:\Users\username`
|
||||||
- Use double backslashes in JSON: `C:\\Users\\username`
|
- Use double backslashes in JSON: `C:\\Users\\username`
|
||||||
- OR use forward slashes in JSON: `C:/Users/username`
|
- OR use forward slashes in JSON: `C:/Users/username`
|
||||||
@@ -128,6 +139,7 @@ python3 -c "import pcbnew"
|
|||||||
- Drive letters required (C:, D:, etc.)
|
- Drive letters required (C:, D:, etc.)
|
||||||
|
|
||||||
**Example commands:**
|
**Example commands:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
cd C:\Users\username\KiCAD-MCP-Server
|
cd C:\Users\username\KiCAD-MCP-Server
|
||||||
$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
||||||
@@ -135,6 +147,7 @@ $env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
|||||||
```
|
```
|
||||||
|
|
||||||
**JSON configuration notes:**
|
**JSON configuration notes:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
// Wrong - single backslash will cause errors
|
// Wrong - single backslash will cause errors
|
||||||
"args": ["C:\Users\name\project"]
|
"args": ["C:\Users\name\project"]
|
||||||
@@ -153,11 +166,13 @@ $env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
|||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
**System Python:**
|
**System Python:**
|
||||||
|
|
||||||
- Usually Python 3.10+ available system-wide
|
- Usually Python 3.10+ available system-wide
|
||||||
- KiCAD uses system Python with additional modules
|
- KiCAD uses system Python with additional modules
|
||||||
- Virtual environments recommended for isolation
|
- Virtual environments recommended for isolation
|
||||||
|
|
||||||
**Setup:**
|
**Setup:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check Python version
|
# Check Python version
|
||||||
python3 --version
|
python3 --version
|
||||||
@@ -175,6 +190,7 @@ pip install -r requirements.txt
|
|||||||
```
|
```
|
||||||
|
|
||||||
**PYTHONPATH:**
|
**PYTHONPATH:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Temporary (current session)
|
# Temporary (current session)
|
||||||
export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
||||||
@@ -186,11 +202,13 @@ echo 'export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages' >> ~/.bashrc
|
|||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
**KiCAD Bundled Python:**
|
**KiCAD Bundled Python:**
|
||||||
|
|
||||||
- KiCAD 9.0 includes Python 3.11
|
- KiCAD 9.0 includes Python 3.11
|
||||||
- No system Python installation needed
|
- No system Python installation needed
|
||||||
- Use KiCAD's Python for all MCP operations
|
- Use KiCAD's Python for all MCP operations
|
||||||
|
|
||||||
**Setup:**
|
**Setup:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Check KiCAD Python
|
# Check KiCAD Python
|
||||||
& "C:\Program Files\KiCad\9.0\bin\python.exe" --version
|
& "C:\Program Files\KiCad\9.0\bin\python.exe" --version
|
||||||
@@ -203,6 +221,7 @@ echo 'export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages' >> ~/.bashrc
|
|||||||
```
|
```
|
||||||
|
|
||||||
**PYTHONPATH:**
|
**PYTHONPATH:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Temporary (current session)
|
# Temporary (current session)
|
||||||
$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
||||||
@@ -222,18 +241,21 @@ $env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
|||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
**Check KiCAD installation:**
|
**Check KiCAD installation:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
which kicad
|
which kicad
|
||||||
kicad --version
|
kicad --version
|
||||||
```
|
```
|
||||||
|
|
||||||
**Check Python module:**
|
**Check Python module:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -c "import sys; print(sys.path)"
|
python3 -c "import sys; print(sys.path)"
|
||||||
python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Run tests:**
|
**Run tests:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /home/username/KiCAD-MCP-Server
|
cd /home/username/KiCAD-MCP-Server
|
||||||
npm test
|
npm test
|
||||||
@@ -241,11 +263,13 @@ pytest tests/
|
|||||||
```
|
```
|
||||||
|
|
||||||
**View logs:**
|
**View logs:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tail -f ~/.kicad-mcp/logs/kicad_interface.log
|
tail -f ~/.kicad-mcp/logs/kicad_interface.log
|
||||||
```
|
```
|
||||||
|
|
||||||
**Start server manually:**
|
**Start server manually:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
||||||
node dist/index.js
|
node dist/index.js
|
||||||
@@ -254,28 +278,33 @@ node dist/index.js
|
|||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
**Check KiCAD installation:**
|
**Check KiCAD installation:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
Test-Path "C:\Program Files\KiCad\9.0"
|
Test-Path "C:\Program Files\KiCad\9.0"
|
||||||
& "C:\Program Files\KiCad\9.0\bin\kicad.exe" --version
|
& "C:\Program Files\KiCad\9.0\bin\kicad.exe" --version
|
||||||
```
|
```
|
||||||
|
|
||||||
**Check Python module:**
|
**Check Python module:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import sys; print(sys.path)"
|
& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import sys; print(sys.path)"
|
||||||
& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Run automated diagnostics:**
|
**Run automated diagnostics:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\setup-windows.ps1
|
.\setup-windows.ps1
|
||||||
```
|
```
|
||||||
|
|
||||||
**View logs:**
|
**View logs:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
Get-Content "$env:USERPROFILE\.kicad-mcp\logs\kicad_interface.log" -Tail 50 -Wait
|
Get-Content "$env:USERPROFILE\.kicad-mcp\logs\kicad_interface.log" -Tail 50 -Wait
|
||||||
```
|
```
|
||||||
|
|
||||||
**Start server manually:**
|
**Start server manually:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages"
|
||||||
node dist\index.js
|
node dist\index.js
|
||||||
@@ -288,6 +317,7 @@ node dist\index.js
|
|||||||
### Linux-Specific Issues
|
### Linux-Specific Issues
|
||||||
|
|
||||||
**1. Permission Errors**
|
**1. Permission Errors**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Fix file permissions
|
# Fix file permissions
|
||||||
chmod +x python/kicad_interface.py
|
chmod +x python/kicad_interface.py
|
||||||
@@ -297,6 +327,7 @@ chmod -R 755 ~/KiCAD-MCP-Server
|
|||||||
```
|
```
|
||||||
|
|
||||||
**2. PYTHONPATH Not Set**
|
**2. PYTHONPATH Not Set**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check current PYTHONPATH
|
# Check current PYTHONPATH
|
||||||
echo $PYTHONPATH
|
echo $PYTHONPATH
|
||||||
@@ -306,6 +337,7 @@ find /usr -name "pcbnew.py" 2>/dev/null
|
|||||||
```
|
```
|
||||||
|
|
||||||
**3. KiCAD Not in PATH**
|
**3. KiCAD Not in PATH**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Add to PATH temporarily
|
# Add to PATH temporarily
|
||||||
export PATH=$PATH:/usr/bin
|
export PATH=$PATH:/usr/bin
|
||||||
@@ -315,6 +347,7 @@ export PATH=$PATH:/usr/bin
|
|||||||
```
|
```
|
||||||
|
|
||||||
**4. Library Dependencies**
|
**4. Library Dependencies**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install missing system libraries
|
# Install missing system libraries
|
||||||
sudo apt-get install python3-wxgtk4.0 python3-cairo
|
sudo apt-get install python3-wxgtk4.0 python3-cairo
|
||||||
@@ -326,11 +359,13 @@ ldd /usr/lib/kicad/lib/python3/dist-packages/pcbnew.so
|
|||||||
### Windows-Specific Issues
|
### Windows-Specific Issues
|
||||||
|
|
||||||
**1. Server Exits Immediately**
|
**1. Server Exits Immediately**
|
||||||
|
|
||||||
- Most common issue
|
- Most common issue
|
||||||
- Usually means pcbnew import failed
|
- Usually means pcbnew import failed
|
||||||
- Solution: Run `setup-windows.ps1` for diagnostics
|
- Solution: Run `setup-windows.ps1` for diagnostics
|
||||||
|
|
||||||
**2. Path Issues in Configuration**
|
**2. Path Issues in Configuration**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Test path accessibility
|
# Test path accessibility
|
||||||
Test-Path "C:\Users\name\KiCAD-MCP-Server\dist\index.js"
|
Test-Path "C:\Users\name\KiCAD-MCP-Server\dist\index.js"
|
||||||
@@ -340,6 +375,7 @@ cd C:\Users\[TAB]
|
|||||||
```
|
```
|
||||||
|
|
||||||
**3. PowerShell Execution Policy**
|
**3. PowerShell Execution Policy**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Check current policy
|
# Check current policy
|
||||||
Get-ExecutionPolicy
|
Get-ExecutionPolicy
|
||||||
@@ -349,6 +385,7 @@ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
|||||||
```
|
```
|
||||||
|
|
||||||
**4. Antivirus Blocking**
|
**4. Antivirus Blocking**
|
||||||
|
|
||||||
```
|
```
|
||||||
Windows Defender may block Node.js or Python processes
|
Windows Defender may block Node.js or Python processes
|
||||||
Solution: Add exclusion for project directory in Windows Security
|
Solution: Add exclusion for project directory in Windows Security
|
||||||
@@ -359,12 +396,14 @@ Solution: Add exclusion for project directory in Windows Security
|
|||||||
## Performance Considerations
|
## Performance Considerations
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
- Generally faster file I/O operations
|
- Generally faster file I/O operations
|
||||||
- Better process management
|
- Better process management
|
||||||
- Lower memory overhead
|
- Lower memory overhead
|
||||||
- Native Unix socket support (future IPC backend)
|
- Native Unix socket support (future IPC backend)
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
- Slightly slower file operations
|
- Slightly slower file operations
|
||||||
- More memory overhead
|
- More memory overhead
|
||||||
- Extra startup validation checks (for diagnostics)
|
- Extra startup validation checks (for diagnostics)
|
||||||
@@ -379,6 +418,7 @@ Solution: Add exclusion for project directory in Windows Security
|
|||||||
### Linux Development Environment
|
### Linux Development Environment
|
||||||
|
|
||||||
**Typical workflow:**
|
**Typical workflow:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start development
|
# Start development
|
||||||
cd ~/KiCAD-MCP-Server
|
cd ~/KiCAD-MCP-Server
|
||||||
@@ -395,6 +435,7 @@ python3 python/kicad_interface.py
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Recommended tools:**
|
**Recommended tools:**
|
||||||
|
|
||||||
- Terminal: GNOME Terminal, Konsole, or Alacritty
|
- Terminal: GNOME Terminal, Konsole, or Alacritty
|
||||||
- Editor: VSCode with Python and TypeScript extensions
|
- Editor: VSCode with Python and TypeScript extensions
|
||||||
- Process monitoring: `htop` or `top`
|
- Process monitoring: `htop` or `top`
|
||||||
@@ -403,6 +444,7 @@ python3 python/kicad_interface.py
|
|||||||
### Windows Development Environment
|
### Windows Development Environment
|
||||||
|
|
||||||
**Typical workflow:**
|
**Typical workflow:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Start development
|
# Start development
|
||||||
cd C:\Users\username\KiCAD-MCP-Server
|
cd C:\Users\username\KiCAD-MCP-Server
|
||||||
@@ -419,6 +461,7 @@ npm test
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Recommended tools:**
|
**Recommended tools:**
|
||||||
|
|
||||||
- Terminal: Windows Terminal or PowerShell 7
|
- Terminal: Windows Terminal or PowerShell 7
|
||||||
- Editor: VSCode with Python and TypeScript extensions
|
- Editor: VSCode with Python and TypeScript extensions
|
||||||
- Process monitoring: Task Manager or Process Explorer
|
- Process monitoring: Task Manager or Process Explorer
|
||||||
@@ -471,12 +514,14 @@ npm test
|
|||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
### Linux Support
|
### Linux Support
|
||||||
|
|
||||||
- Check: [README.md](../README.md) Linux installation section
|
- Check: [README.md](../README.md) Linux installation section
|
||||||
- Read: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md)
|
- Read: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md)
|
||||||
- Search: GitHub Issues filtered by `linux` label
|
- Search: GitHub Issues filtered by `linux` label
|
||||||
- Community: Linux users in Discussions
|
- Community: Linux users in Discussions
|
||||||
|
|
||||||
### Windows Support
|
### Windows Support
|
||||||
|
|
||||||
- Check: [README.md](../README.md) Windows installation section
|
- Check: [README.md](../README.md) Windows installation section
|
||||||
- Read: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md)
|
- Read: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md)
|
||||||
- Run: `setup-windows.ps1` for automated diagnostics
|
- Run: `setup-windows.ps1` for automated diagnostics
|
||||||
@@ -488,12 +533,14 @@ npm test
|
|||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
**Choose Linux if:**
|
**Choose Linux if:**
|
||||||
|
|
||||||
- You're comfortable with command-line tools
|
- You're comfortable with command-line tools
|
||||||
- You want the most stable, tested environment
|
- You want the most stable, tested environment
|
||||||
- You're developing or contributing to the project
|
- You're developing or contributing to the project
|
||||||
- You need maximum performance
|
- You need maximum performance
|
||||||
|
|
||||||
**Choose Windows if:**
|
**Choose Windows if:**
|
||||||
|
|
||||||
- You want automated setup and diagnostics
|
- You want automated setup and diagnostics
|
||||||
- You're less comfortable with terminal commands
|
- You're less comfortable with terminal commands
|
||||||
- You need detailed troubleshooting guidance
|
- You need detailed troubleshooting guidance
|
||||||
@@ -504,9 +551,11 @@ npm test
|
|||||||
---
|
---
|
||||||
|
|
||||||
**For platform-specific installation instructions, see:**
|
**For platform-specific installation instructions, see:**
|
||||||
|
|
||||||
- Linux: [README.md - Linux Installation](../README.md#linux-ubuntudebian)
|
- Linux: [README.md - Linux Installation](../README.md#linux-ubuntudebian)
|
||||||
- Windows: [README.md - Windows Installation](../README.md#windows-1011)
|
- Windows: [README.md - Windows Installation](../README.md#windows-1011)
|
||||||
|
|
||||||
**For troubleshooting:**
|
**For troubleshooting:**
|
||||||
|
|
||||||
- Linux: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md)
|
- Linux: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md)
|
||||||
- Windows: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md)
|
- Windows: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ The MCP server uses KiCAD's Python API (`pcbnew` module) to read and write `.kic
|
|||||||
**Use case:** Claude places components via MCP, human sees them in KiCAD UI
|
**Use case:** Claude places components via MCP, human sees them in KiCAD UI
|
||||||
|
|
||||||
1. **Claude places components** via MCP tools:
|
1. **Claude places components** via MCP tools:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# MCP internally uses:
|
# MCP internally uses:
|
||||||
board = pcbnew.LoadBoard('project.kicad_pcb')
|
board = pcbnew.LoadBoard('project.kicad_pcb')
|
||||||
@@ -51,6 +52,7 @@ The MCP server uses KiCAD's Python API (`pcbnew` module) to read and write `.kic
|
|||||||
- Components appear instantly ✅
|
- Components appear instantly ✅
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Place a 10k resistor at position 30, 30mm"
|
User: "Place a 10k resistor at position 30, 30mm"
|
||||||
Claude: [uses place_component MCP tool]
|
Claude: [uses place_component MCP tool]
|
||||||
@@ -74,6 +76,7 @@ User: [opens KiCAD UI]
|
|||||||
- KiCAD writes changes to `.kicad_pcb` file
|
- KiCAD writes changes to `.kicad_pcb` file
|
||||||
|
|
||||||
3. **Claude reads changes** via MCP tools:
|
3. **Claude reads changes** via MCP tools:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# MCP internally uses:
|
# MCP internally uses:
|
||||||
board = pcbnew.LoadBoard('project.kicad_pcb')
|
board = pcbnew.LoadBoard('project.kicad_pcb')
|
||||||
@@ -88,6 +91,7 @@ User: [opens KiCAD UI]
|
|||||||
- New traces and nets
|
- New traces and nets
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "I moved R1 to a new position, can you see it?"
|
User: "I moved R1 to a new position, can you see it?"
|
||||||
Claude: [uses get_board_info MCP tool]
|
Claude: [uses get_board_info MCP tool]
|
||||||
@@ -100,11 +104,13 @@ Claude: [uses get_board_info MCP tool]
|
|||||||
### Test 1: MCP→UI (Verified ✅)
|
### Test 1: MCP→UI (Verified ✅)
|
||||||
|
|
||||||
**Setup:**
|
**Setup:**
|
||||||
|
|
||||||
- Created new board via MCP (100x80mm)
|
- Created new board via MCP (100x80mm)
|
||||||
- Placed R1 (10k resistor) at (30, 30) mm
|
- Placed R1 (10k resistor) at (30, 30) mm
|
||||||
- Placed D1 (RED LED) at (50, 30) mm
|
- Placed D1 (RED LED) at (50, 30) mm
|
||||||
|
|
||||||
**Result:**
|
**Result:**
|
||||||
|
|
||||||
- Opened KiCAD PCB editor
|
- Opened KiCAD PCB editor
|
||||||
- Both components visible at correct positions ✅
|
- Both components visible at correct positions ✅
|
||||||
- All properties (reference, value, rotation) correct ✅
|
- All properties (reference, value, rotation) correct ✅
|
||||||
@@ -112,10 +118,12 @@ Claude: [uses get_board_info MCP tool]
|
|||||||
### Test 2: UI→MCP (Verified ✅)
|
### Test 2: UI→MCP (Verified ✅)
|
||||||
|
|
||||||
**Setup:**
|
**Setup:**
|
||||||
|
|
||||||
- User moved R1 from (30, 30) mm to (59.175, 49.0) mm in UI
|
- User moved R1 from (30, 30) mm to (59.175, 49.0) mm in UI
|
||||||
- User saved file (Ctrl+S)
|
- User saved file (Ctrl+S)
|
||||||
|
|
||||||
**Result:**
|
**Result:**
|
||||||
|
|
||||||
- MCP read board via `get_board_info`
|
- MCP read board via `get_board_info`
|
||||||
- New position detected correctly ✅
|
- New position detected correctly ✅
|
||||||
- D1 position unchanged (as expected) ✅
|
- D1 position unchanged (as expected) ✅
|
||||||
@@ -136,11 +144,13 @@ Claude: [uses get_board_info MCP tool]
|
|||||||
### MCP Tools for Collaboration
|
### MCP Tools for Collaboration
|
||||||
|
|
||||||
**Reading board state:**
|
**Reading board state:**
|
||||||
|
|
||||||
- `get_board_info` - Get all components and their positions
|
- `get_board_info` - Get all components and their positions
|
||||||
- `get_project_info` - Get project metadata
|
- `get_project_info` - Get project metadata
|
||||||
- `list_components` - List all components (if implemented)
|
- `list_components` - List all components (if implemented)
|
||||||
|
|
||||||
**Modifying board:**
|
**Modifying board:**
|
||||||
|
|
||||||
- `place_component` - Add new components
|
- `place_component` - Add new components
|
||||||
- `add_trace` - Add copper traces
|
- `add_trace` - Add copper traces
|
||||||
- `add_via` - Add vias
|
- `add_via` - Add vias
|
||||||
@@ -188,6 +198,7 @@ Claude: [uses get_board_info MCP tool]
|
|||||||
### For AI-Human Collaboration
|
### For AI-Human Collaboration
|
||||||
|
|
||||||
1. **Establish Turn-Taking:**
|
1. **Establish Turn-Taking:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "I'm going to add some components, one sec"
|
User: "I'm going to add some components, one sec"
|
||||||
[User edits in UI]
|
[User edits in UI]
|
||||||
@@ -201,6 +212,7 @@ Claude: [uses get_board_info MCP tool]
|
|||||||
- Claude: Always read fresh before making decisions
|
- Claude: Always read fresh before making decisions
|
||||||
|
|
||||||
3. **Communicate Changes:**
|
3. **Communicate Changes:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Claude: "I'm placing R1-R4 now..."
|
Claude: "I'm placing R1-R4 now..."
|
||||||
[MCP places components]
|
[MCP places components]
|
||||||
@@ -215,6 +227,7 @@ Claude: [uses get_board_info MCP tool]
|
|||||||
### Workflow Patterns
|
### Workflow Patterns
|
||||||
|
|
||||||
**Pattern 1: AI Does Layout, Human Reviews**
|
**Pattern 1: AI Does Layout, Human Reviews**
|
||||||
|
|
||||||
```
|
```
|
||||||
1. Claude places all components via MCP
|
1. Claude places all components via MCP
|
||||||
2. Claude routes critical traces via MCP
|
2. Claude routes critical traces via MCP
|
||||||
@@ -225,6 +238,7 @@ Claude: [uses get_board_info MCP tool]
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Pattern 2: Human Sketches, AI Refines**
|
**Pattern 2: Human Sketches, AI Refines**
|
||||||
|
|
||||||
```
|
```
|
||||||
1. Human places major components in UI
|
1. Human places major components in UI
|
||||||
2. Saves → Claude reads layout
|
2. Saves → Claude reads layout
|
||||||
@@ -235,6 +249,7 @@ Claude: [uses get_board_info MCP tool]
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Pattern 3: Pair Programming Style**
|
**Pattern 3: Pair Programming Style**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Place a 10k pull-up resistor on pin 3"
|
User: "Place a 10k pull-up resistor on pin 3"
|
||||||
Claude: [places R1 at calculated position]
|
Claude: [places R1 at calculated position]
|
||||||
@@ -276,6 +291,7 @@ Claude: [places D1]
|
|||||||
### Long-Term Vision
|
### Long-Term Vision
|
||||||
|
|
||||||
**Fully Real-Time Collaboration:**
|
**Fully Real-Time Collaboration:**
|
||||||
|
|
||||||
- Both AI and human see changes instantly
|
- Both AI and human see changes instantly
|
||||||
- No manual save/reload required
|
- No manual save/reload required
|
||||||
- Conflict detection and resolution
|
- Conflict detection and resolution
|
||||||
@@ -283,6 +299,7 @@ Claude: [places D1]
|
|||||||
- Chat/comment system for design discussion
|
- Chat/comment system for design discussion
|
||||||
|
|
||||||
**Example Future Workflow:**
|
**Example Future Workflow:**
|
||||||
|
|
||||||
```
|
```
|
||||||
[Claude and human both have board open]
|
[Claude and human both have board open]
|
||||||
Claude: [starts placing R1]
|
Claude: [starts placing R1]
|
||||||
@@ -299,6 +316,7 @@ Claude: "Good position for D1! I'll route them now"
|
|||||||
### File Format
|
### File Format
|
||||||
|
|
||||||
KiCAD uses S-expression format (`.kicad_pcb`):
|
KiCAD uses S-expression format (`.kicad_pcb`):
|
||||||
|
|
||||||
```lisp
|
```lisp
|
||||||
(kicad_pcb (version 20240108) (generator "pcbnew")
|
(kicad_pcb (version 20240108) (generator "pcbnew")
|
||||||
(footprint "Resistor_SMD:R_0603_1608Metric"
|
(footprint "Resistor_SMD:R_0603_1608Metric"
|
||||||
@@ -314,11 +332,13 @@ KiCAD uses S-expression format (`.kicad_pcb`):
|
|||||||
### Sync Mechanism
|
### Sync Mechanism
|
||||||
|
|
||||||
**Current (File-based):**
|
**Current (File-based):**
|
||||||
|
|
||||||
1. MCP: `pcbnew.SaveBoard(path, board)` → writes file
|
1. MCP: `pcbnew.SaveBoard(path, board)` → writes file
|
||||||
2. UI: File → Revert → reads file
|
2. UI: File → Revert → reads file
|
||||||
3. Latency: ~1-5 seconds (manual)
|
3. Latency: ~1-5 seconds (manual)
|
||||||
|
|
||||||
**Future (IPC-based):**
|
**Future (IPC-based):**
|
||||||
|
|
||||||
1. MCP: `kicad.AddFootprint(...)` → sends IPC command
|
1. MCP: `kicad.AddFootprint(...)` → sends IPC command
|
||||||
2. KiCAD: Receives command → updates internal state
|
2. KiCAD: Receives command → updates internal state
|
||||||
3. UI: Automatically refreshes display
|
3. UI: Automatically refreshes display
|
||||||
@@ -355,6 +375,7 @@ pcbnew.SaveBoard('project.kicad_pcb', board)
|
|||||||
**Cause:** UI hasn't reloaded the file
|
**Cause:** UI hasn't reloaded the file
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. File → Revert (or Ctrl+R if configured)
|
1. File → Revert (or Ctrl+R if configured)
|
||||||
2. Or close PCB editor and reopen
|
2. Or close PCB editor and reopen
|
||||||
3. Or restart KiCAD
|
3. Or restart KiCAD
|
||||||
@@ -364,6 +385,7 @@ pcbnew.SaveBoard('project.kicad_pcb', board)
|
|||||||
**Cause:** File not saved
|
**Cause:** File not saved
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Save file: Ctrl+S or File → Save
|
1. Save file: Ctrl+S or File → Save
|
||||||
2. Verify save: Check file modification time
|
2. Verify save: Check file modification time
|
||||||
3. Ask Claude to read board again
|
3. Ask Claude to read board again
|
||||||
@@ -373,6 +395,7 @@ pcbnew.SaveBoard('project.kicad_pcb', board)
|
|||||||
**Cause:** File overwritten by other party
|
**Cause:** File overwritten by other party
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Always save before asking MCP to make changes
|
1. Always save before asking MCP to make changes
|
||||||
2. Don't edit while MCP is working
|
2. Don't edit while MCP is working
|
||||||
3. Take turns to avoid conflicts
|
3. Take turns to avoid conflicts
|
||||||
@@ -382,6 +405,7 @@ pcbnew.SaveBoard('project.kicad_pcb', board)
|
|||||||
**Cause:** Unit conversion error or coordinate system mismatch
|
**Cause:** Unit conversion error or coordinate system mismatch
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Check KiCAD units (View → Switch Units)
|
1. Check KiCAD units (View → Switch Units)
|
||||||
2. MCP uses millimeters internally
|
2. MCP uses millimeters internally
|
||||||
3. Report issue if positions consistently wrong
|
3. Report issue if positions consistently wrong
|
||||||
@@ -410,6 +434,7 @@ The KiCAD MCP Server successfully enables paired circuit board design between AI
|
|||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
**2025-11-01 - v2.1.0-alpha**
|
**2025-11-01 - v2.1.0-alpha**
|
||||||
|
|
||||||
- ✅ Tested MCP→UI workflow (placing components via MCP, viewing in UI)
|
- ✅ Tested MCP→UI workflow (placing components via MCP, viewing in UI)
|
||||||
- ✅ Tested UI→MCP workflow (editing in UI, reading via MCP)
|
- ✅ Tested UI→MCP workflow (editing in UI, reading via MCP)
|
||||||
- ✅ Documented best practices and limitations
|
- ✅ Documented best practices and limitations
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
## Completed Milestones
|
## Completed Milestones
|
||||||
|
|
||||||
### v1.0.0 - Core Foundation (October 2025)
|
### v1.0.0 - Core Foundation (October 2025)
|
||||||
|
|
||||||
- [x] MCP protocol implementation (JSON-RPC 2.0, MCP 2025-06-18)
|
- [x] MCP protocol implementation (JSON-RPC 2.0, MCP 2025-06-18)
|
||||||
- [x] Project management (create, open, save)
|
- [x] Project management (create, open, save)
|
||||||
- [x] Board operations (size, outline, layers, mounting holes, text)
|
- [x] Board operations (size, outline, layers, mounting holes, text)
|
||||||
@@ -21,12 +22,14 @@
|
|||||||
- [x] UI auto-launch and detection
|
- [x] UI auto-launch and detection
|
||||||
|
|
||||||
### v2.0.0-alpha - Router and IPC (November-December 2025)
|
### v2.0.0-alpha - Router and IPC (November-December 2025)
|
||||||
|
|
||||||
- [x] Tool router pattern -- 70% AI context reduction
|
- [x] Tool router pattern -- 70% AI context reduction
|
||||||
- [x] IPC backend for real-time KiCAD UI synchronization (21 commands)
|
- [x] IPC backend for real-time KiCAD UI synchronization (21 commands)
|
||||||
- [x] Hybrid SWIG/IPC backend with automatic fallback
|
- [x] Hybrid SWIG/IPC backend with automatic fallback
|
||||||
- [x] Comprehensive Windows support with automated setup
|
- [x] Comprehensive Windows support with automated setup
|
||||||
|
|
||||||
### v2.1.0-alpha - Schematics and JLCPCB (January 2026)
|
### v2.1.0-alpha - Schematics and JLCPCB (January 2026)
|
||||||
|
|
||||||
- [x] Complete schematic workflow fix (Issue #26)
|
- [x] Complete schematic workflow fix (Issue #26)
|
||||||
- [x] Dynamic symbol loading -- access to all ~10,000 KiCad symbols
|
- [x] Dynamic symbol loading -- access to all ~10,000 KiCad symbols
|
||||||
- [x] Intelligent wiring system with pin discovery and smart routing
|
- [x] Intelligent wiring system with pin discovery and smart routing
|
||||||
@@ -36,6 +39,7 @@
|
|||||||
- [x] Local symbol library search (contributor: @l3wi)
|
- [x] Local symbol library search (contributor: @l3wi)
|
||||||
|
|
||||||
### v2.2.0 through v2.2.3 - Routing, Creators, Autorouting (February-March 2026)
|
### v2.2.0 through v2.2.3 - Routing, Creators, Autorouting (February-March 2026)
|
||||||
|
|
||||||
- [x] 13 new routing/component tools (delete/query/modify traces, arrays, alignment)
|
- [x] 13 new routing/component tools (delete/query/modify traces, arrays, alignment)
|
||||||
- [x] route_pad_to_pad with auto-via insertion for cross-layer connections
|
- [x] route_pad_to_pad with auto-via insertion for cross-layer connections
|
||||||
- [x] copy_routing_pattern for trace replication
|
- [x] copy_routing_pattern for trace replication
|
||||||
@@ -57,12 +61,14 @@
|
|||||||
## Current Focus: v2.3+
|
## Current Focus: v2.3+
|
||||||
|
|
||||||
### Documentation Overhaul (In Progress)
|
### Documentation Overhaul (In Progress)
|
||||||
|
|
||||||
- [ ] Per-feature documentation for all 122 tools
|
- [ ] Per-feature documentation for all 122 tools
|
||||||
- [ ] Architecture guide for contributors
|
- [ ] Architecture guide for contributors
|
||||||
- [ ] End-to-end PCB design workflow guide
|
- [ ] End-to-end PCB design workflow guide
|
||||||
- [ ] Documentation index
|
- [ ] Documentation index
|
||||||
|
|
||||||
### Quality and Stability
|
### Quality and Stability
|
||||||
|
|
||||||
- [ ] Expand test coverage across all tool categories
|
- [ ] Expand test coverage across all tool categories
|
||||||
- [ ] Performance profiling for large boards
|
- [ ] Performance profiling for large boards
|
||||||
- [ ] Update package.json version to match CHANGELOG
|
- [ ] Update package.json version to match CHANGELOG
|
||||||
@@ -72,24 +78,28 @@
|
|||||||
## Planned Features
|
## Planned Features
|
||||||
|
|
||||||
### Supplier Integration
|
### Supplier Integration
|
||||||
|
|
||||||
- [ ] Digikey API integration
|
- [ ] Digikey API integration
|
||||||
- [ ] Mouser API integration
|
- [ ] Mouser API integration
|
||||||
- [ ] Smart BOM management with real-time pricing
|
- [ ] Smart BOM management with real-time pricing
|
||||||
- [ ] Cost optimization across suppliers
|
- [ ] Cost optimization across suppliers
|
||||||
|
|
||||||
### Design Patterns and Templates
|
### Design Patterns and Templates
|
||||||
|
|
||||||
- [ ] Circuit patterns library (voltage regulators, USB, microcontrollers)
|
- [ ] Circuit patterns library (voltage regulators, USB, microcontrollers)
|
||||||
- [ ] Board templates (Arduino shields, RPi HATs, Feather wings)
|
- [ ] Board templates (Arduino shields, RPi HATs, Feather wings)
|
||||||
- [ ] Auto-suggest trace widths by current
|
- [ ] Auto-suggest trace widths by current
|
||||||
- [ ] Impedance-controlled trace support
|
- [ ] Impedance-controlled trace support
|
||||||
|
|
||||||
### Advanced Capabilities
|
### Advanced Capabilities
|
||||||
|
|
||||||
- [ ] Panelization support
|
- [ ] Panelization support
|
||||||
- [ ] Multi-board project management
|
- [ ] Multi-board project management
|
||||||
- [ ] High-speed design helpers (length matching, via stitching)
|
- [ ] High-speed design helpers (length matching, via stitching)
|
||||||
- [ ] SPICE simulation integration
|
- [ ] SPICE simulation integration
|
||||||
|
|
||||||
### Community and Education
|
### Community and Education
|
||||||
|
|
||||||
- [ ] Example project gallery with tutorials
|
- [ ] Example project gallery with tutorials
|
||||||
- [ ] Video walkthrough series
|
- [ ] Video walkthrough series
|
||||||
- [ ] Interactive beginner tutorials
|
- [ ] Interactive beginner tutorials
|
||||||
@@ -111,4 +121,4 @@ Check [CONTRIBUTING.md](../CONTRIBUTING.md) for details.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Maintained by: KiCAD MCP Team and community contributors*
|
_Maintained by: KiCAD MCP Team and community contributors_
|
||||||
|
|||||||
@@ -71,9 +71,11 @@ These cover the primary workflow (80%+ of use cases):
|
|||||||
### Routed Categories (8+ categories, 110+ tools)
|
### Routed Categories (8+ categories, 110+ tools)
|
||||||
|
|
||||||
#### 1. `board` - Board Configuration & Layout (9 tools)
|
#### 1. `board` - Board Configuration & Layout (9 tools)
|
||||||
|
|
||||||
Setup and configuration operations.
|
Setup and configuration operations.
|
||||||
|
|
||||||
**Tools:**
|
**Tools:**
|
||||||
|
|
||||||
- `add_layer` - Add PCB layer
|
- `add_layer` - Add PCB layer
|
||||||
- `set_active_layer` - Set active layer
|
- `set_active_layer` - Set active layer
|
||||||
- `get_layer_list` - List all layers
|
- `get_layer_list` - List all layers
|
||||||
@@ -85,9 +87,11 @@ Setup and configuration operations.
|
|||||||
- `launch_kicad_ui` - Launch KiCAD UI
|
- `launch_kicad_ui` - Launch KiCAD UI
|
||||||
|
|
||||||
#### 2. `component` - Advanced Component Operations (8 tools)
|
#### 2. `component` - Advanced Component Operations (8 tools)
|
||||||
|
|
||||||
Beyond basic placement.
|
Beyond basic placement.
|
||||||
|
|
||||||
**Tools:**
|
**Tools:**
|
||||||
|
|
||||||
- `rotate_component` - Rotate component
|
- `rotate_component` - Rotate component
|
||||||
- `delete_component` - Delete component
|
- `delete_component` - Delete component
|
||||||
- `edit_component` - Edit component properties
|
- `edit_component` - Edit component properties
|
||||||
@@ -98,9 +102,11 @@ Beyond basic placement.
|
|||||||
- `replace_component` - Replace component with another
|
- `replace_component` - Replace component with another
|
||||||
|
|
||||||
#### 3. `export` - File Export & Manufacturing (8 tools)
|
#### 3. `export` - File Export & Manufacturing (8 tools)
|
||||||
|
|
||||||
Generate output files for fabrication and documentation.
|
Generate output files for fabrication and documentation.
|
||||||
|
|
||||||
**Tools:**
|
**Tools:**
|
||||||
|
|
||||||
- `export_gerber` - Export Gerber files
|
- `export_gerber` - Export Gerber files
|
||||||
- `export_pdf` - Export PDF
|
- `export_pdf` - Export PDF
|
||||||
- `export_svg` - Export SVG
|
- `export_svg` - Export SVG
|
||||||
@@ -111,9 +117,11 @@ Generate output files for fabrication and documentation.
|
|||||||
- `export_vrml` - Export VRML 3D model
|
- `export_vrml` - Export VRML 3D model
|
||||||
|
|
||||||
#### 4. `drc` - Design Rules & Validation (9 tools)
|
#### 4. `drc` - Design Rules & Validation (9 tools)
|
||||||
|
|
||||||
Design rule checking and electrical validation.
|
Design rule checking and electrical validation.
|
||||||
|
|
||||||
**Tools:**
|
**Tools:**
|
||||||
|
|
||||||
- `set_design_rules` - Configure design rules
|
- `set_design_rules` - Configure design rules
|
||||||
- `get_design_rules` - Get current rules
|
- `get_design_rules` - Get current rules
|
||||||
- `run_drc` - Run design rule check
|
- `run_drc` - Run design rule check
|
||||||
@@ -124,9 +132,11 @@ Design rule checking and electrical validation.
|
|||||||
- `get_drc_violations` - Get DRC violations
|
- `get_drc_violations` - Get DRC violations
|
||||||
|
|
||||||
#### 5. `schematic` - Schematic Operations (9 tools)
|
#### 5. `schematic` - Schematic Operations (9 tools)
|
||||||
|
|
||||||
Schematic editor operations.
|
Schematic editor operations.
|
||||||
|
|
||||||
**Tools:**
|
**Tools:**
|
||||||
|
|
||||||
- `create_schematic` - Create new schematic
|
- `create_schematic` - Create new schematic
|
||||||
- `add_schematic_component` - Add component to schematic
|
- `add_schematic_component` - Add component to schematic
|
||||||
- `add_wire` - Add wire connection
|
- `add_wire` - Add wire connection
|
||||||
@@ -137,18 +147,22 @@ Schematic editor operations.
|
|||||||
- `generate_netlist` - Generate netlist
|
- `generate_netlist` - Generate netlist
|
||||||
|
|
||||||
#### 6. `library` - Footprint Library Access (4 tools)
|
#### 6. `library` - Footprint Library Access (4 tools)
|
||||||
|
|
||||||
Search and browse footprint libraries.
|
Search and browse footprint libraries.
|
||||||
|
|
||||||
**Tools:**
|
**Tools:**
|
||||||
|
|
||||||
- `list_libraries` - List available libraries
|
- `list_libraries` - List available libraries
|
||||||
- `search_footprints` - Search footprints
|
- `search_footprints` - Search footprints
|
||||||
- `list_library_footprints` - List library footprints
|
- `list_library_footprints` - List library footprints
|
||||||
- `get_footprint_info` - Get footprint details
|
- `get_footprint_info` - Get footprint details
|
||||||
|
|
||||||
#### 7. `routing` - Advanced Routing (3 tools)
|
#### 7. `routing` - Advanced Routing (3 tools)
|
||||||
|
|
||||||
Advanced routing operations beyond basic trace routing.
|
Advanced routing operations beyond basic trace routing.
|
||||||
|
|
||||||
**Tools:**
|
**Tools:**
|
||||||
|
|
||||||
- `add_via` - Add via
|
- `add_via` - Add via
|
||||||
- `add_copper_pour` - Add copper pour
|
- `add_copper_pour` - Add copper pour
|
||||||
|
|
||||||
@@ -157,11 +171,13 @@ Advanced routing operations beyond basic trace routing.
|
|||||||
## Router Tools
|
## Router Tools
|
||||||
|
|
||||||
### 1. `list_tool_categories`
|
### 1. `list_tool_categories`
|
||||||
|
|
||||||
**Description:** List all available tool categories with descriptions and tool counts.
|
**Description:** List all available tool categories with descriptions and tool counts.
|
||||||
|
|
||||||
**Parameters:** None
|
**Parameters:** None
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"total_categories": 7,
|
"total_categories": 7,
|
||||||
@@ -171,19 +187,22 @@ Advanced routing operations beyond basic trace routing.
|
|||||||
"name": "board",
|
"name": "board",
|
||||||
"description": "Board configuration: layers, mounting holes, zones, visualization",
|
"description": "Board configuration: layers, mounting holes, zones, visualization",
|
||||||
"tool_count": 9
|
"tool_count": 9
|
||||||
},
|
}
|
||||||
// ... more categories
|
// ... more categories
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. `get_category_tools`
|
### 2. `get_category_tools`
|
||||||
|
|
||||||
**Description:** Get detailed information about all tools in a specific category.
|
**Description:** Get detailed information about all tools in a specific category.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `category` (string) - Category name from `list_tool_categories`
|
- `category` (string) - Category name from `list_tool_categories`
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"category": "export",
|
"category": "export",
|
||||||
@@ -192,29 +211,36 @@ Advanced routing operations beyond basic trace routing.
|
|||||||
{
|
{
|
||||||
"name": "export_gerber",
|
"name": "export_gerber",
|
||||||
"description": "Export Gerber files for PCB fabrication",
|
"description": "Export Gerber files for PCB fabrication",
|
||||||
"parameters": { /* zod schema */ }
|
"parameters": {
|
||||||
},
|
/* zod schema */
|
||||||
|
}
|
||||||
|
}
|
||||||
// ... more tools
|
// ... more tools
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. `execute_tool`
|
### 3. `execute_tool`
|
||||||
|
|
||||||
**Description:** Execute a tool from any category.
|
**Description:** Execute a tool from any category.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `tool_name` (string) - Tool name from `get_category_tools`
|
- `tool_name` (string) - Tool name from `get_category_tools`
|
||||||
- `params` (object, optional) - Tool parameters
|
- `params` (object, optional) - Tool parameters
|
||||||
|
|
||||||
**Returns:** Tool execution result
|
**Returns:** Tool execution result
|
||||||
|
|
||||||
### 4. `search_tools`
|
### 4. `search_tools`
|
||||||
|
|
||||||
**Description:** Search for tools by keyword across all categories.
|
**Description:** Search for tools by keyword across all categories.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `query` (string) - Search term (e.g., "gerber", "zone", "export")
|
- `query` (string) - Search term (e.g., "gerber", "zone", "export")
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"query": "export",
|
"query": "export",
|
||||||
@@ -224,7 +250,7 @@ Advanced routing operations beyond basic trace routing.
|
|||||||
"category": "export",
|
"category": "export",
|
||||||
"tool": "export_gerber",
|
"tool": "export_gerber",
|
||||||
"description": "Export Gerber files for PCB fabrication"
|
"description": "Export Gerber files for PCB fabrication"
|
||||||
},
|
}
|
||||||
// ... more matches
|
// ... more matches
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -261,21 +287,25 @@ Advanced routing operations beyond basic trace routing.
|
|||||||
## Migration Strategy
|
## Migration Strategy
|
||||||
|
|
||||||
### Phase 1: Create Infrastructure
|
### Phase 1: Create Infrastructure
|
||||||
|
|
||||||
1. Create `registry.ts` with all tool definitions
|
1. Create `registry.ts` with all tool definitions
|
||||||
2. Create `router.ts` with router tools
|
2. Create `router.ts` with router tools
|
||||||
3. Create `direct.ts` with direct tool list
|
3. Create `direct.ts` with direct tool list
|
||||||
|
|
||||||
### Phase 2: Update Server
|
### Phase 2: Update Server
|
||||||
|
|
||||||
1. Modify server registration to use direct + router only
|
1. Modify server registration to use direct + router only
|
||||||
2. Keep all existing tool handlers intact
|
2. Keep all existing tool handlers intact
|
||||||
3. Route through `execute_tool`
|
3. Route through `execute_tool`
|
||||||
|
|
||||||
### Phase 3: Testing
|
### Phase 3: Testing
|
||||||
|
|
||||||
1. Test direct tools work as before
|
1. Test direct tools work as before
|
||||||
2. Test router tools (list/get/execute/search)
|
2. Test router tools (list/get/execute/search)
|
||||||
3. Test routed tools via `execute_tool`
|
3. Test routed tools via `execute_tool`
|
||||||
|
|
||||||
### Phase 4: Optimization (Optional)
|
### Phase 4: Optimization (Optional)
|
||||||
|
|
||||||
1. Add caching for tool lookups
|
1. Add caching for tool lookups
|
||||||
2. Add tool usage analytics
|
2. Add tool usage analytics
|
||||||
3. Implement intelligent tool suggestions
|
3. Implement intelligent tool suggestions
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ The KiCAD MCP Server includes an intelligent tool router that organizes 122+ too
|
|||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
Instead of loading all 59 tool schemas into every conversation, Claude now sees:
|
Instead of loading all 59 tool schemas into every conversation, Claude now sees:
|
||||||
|
|
||||||
- **12 direct tools** for high-frequency operations (always visible)
|
- **12 direct tools** for high-frequency operations (always visible)
|
||||||
- **4 router tools** for discovering and executing the other 47 tools
|
- **4 router tools** for discovering and executing the other 47 tools
|
||||||
|
|
||||||
When you ask Claude to do something (like "export gerber files"), it will:
|
When you ask Claude to do something (like "export gerber files"), it will:
|
||||||
|
|
||||||
1. Search for relevant tools using `search_tools`
|
1. Search for relevant tools using `search_tools`
|
||||||
2. Find the `export_gerber` tool in the "export" category
|
2. Find the `export_gerber` tool in the "export" category
|
||||||
3. Execute it via `execute_tool` with your parameters
|
3. Execute it via `execute_tool` with your parameters
|
||||||
@@ -23,42 +25,56 @@ When you ask Claude to do something (like "export gerber files"), it will:
|
|||||||
The 110+ routed tools are organized into these categories:
|
The 110+ routed tools are organized into these categories:
|
||||||
|
|
||||||
### 1. board (9 tools)
|
### 1. board (9 tools)
|
||||||
|
|
||||||
Board configuration: layers, mounting holes, zones, visualization
|
Board configuration: layers, mounting holes, zones, visualization
|
||||||
|
|
||||||
- add_layer, set_active_layer, get_layer_list
|
- add_layer, set_active_layer, get_layer_list
|
||||||
- add_mounting_hole, add_board_text
|
- add_mounting_hole, add_board_text
|
||||||
- add_zone, get_board_extents, get_board_2d_view
|
- add_zone, get_board_extents, get_board_2d_view
|
||||||
- launch_kicad_ui
|
- launch_kicad_ui
|
||||||
|
|
||||||
### 2. component (8 tools)
|
### 2. component (8 tools)
|
||||||
|
|
||||||
Advanced component operations: edit, delete, search, group, annotate
|
Advanced component operations: edit, delete, search, group, annotate
|
||||||
|
|
||||||
- rotate_component, delete_component, edit_component
|
- rotate_component, delete_component, edit_component
|
||||||
- find_component, get_component_properties
|
- find_component, get_component_properties
|
||||||
- add_component_annotation, group_components, replace_component
|
- add_component_annotation, group_components, replace_component
|
||||||
|
|
||||||
### 3. export (8 tools)
|
### 3. export (8 tools)
|
||||||
|
|
||||||
File export for fabrication and documentation
|
File export for fabrication and documentation
|
||||||
|
|
||||||
- export_gerber, export_pdf, export_svg, export_3d
|
- export_gerber, export_pdf, export_svg, export_3d
|
||||||
- export_bom, export_netlist, export_position_file, export_vrml
|
- export_bom, export_netlist, export_position_file, export_vrml
|
||||||
|
|
||||||
### 4. drc (8 tools)
|
### 4. drc (8 tools)
|
||||||
|
|
||||||
Design rule checking and electrical validation
|
Design rule checking and electrical validation
|
||||||
|
|
||||||
- set_design_rules, get_design_rules, run_drc
|
- set_design_rules, get_design_rules, run_drc
|
||||||
- add_net_class, assign_net_to_class, set_layer_constraints
|
- add_net_class, assign_net_to_class, set_layer_constraints
|
||||||
- check_clearance, get_drc_violations
|
- check_clearance, get_drc_violations
|
||||||
|
|
||||||
### 5. schematic (8 tools)
|
### 5. schematic (8 tools)
|
||||||
|
|
||||||
Schematic operations: create, add components, wire connections
|
Schematic operations: create, add components, wire connections
|
||||||
|
|
||||||
- create_schematic, add_schematic_component, add_wire
|
- create_schematic, add_schematic_component, add_wire
|
||||||
- add_schematic_connection, add_schematic_net_label
|
- add_schematic_connection, add_schematic_net_label
|
||||||
- connect_to_net, get_net_connections, generate_netlist
|
- connect_to_net, get_net_connections, generate_netlist
|
||||||
|
|
||||||
### 6. library (4 tools)
|
### 6. library (4 tools)
|
||||||
|
|
||||||
Footprint library access and search
|
Footprint library access and search
|
||||||
|
|
||||||
- list_libraries, search_footprints
|
- list_libraries, search_footprints
|
||||||
- list_library_footprints, get_footprint_info
|
- list_library_footprints, get_footprint_info
|
||||||
|
|
||||||
### 7. routing (2 tools)
|
### 7. routing (2 tools)
|
||||||
|
|
||||||
Advanced routing operations
|
Advanced routing operations
|
||||||
|
|
||||||
- add_via, add_copper_pour
|
- add_via, add_copper_pour
|
||||||
|
|
||||||
## Direct Tools (Always Available)
|
## Direct Tools (Always Available)
|
||||||
@@ -66,47 +82,58 @@ Advanced routing operations
|
|||||||
These 12 tools are always visible for common operations:
|
These 12 tools are always visible for common operations:
|
||||||
|
|
||||||
**Project Lifecycle:**
|
**Project Lifecycle:**
|
||||||
|
|
||||||
- create_project, open_project, save_project, get_project_info
|
- create_project, open_project, save_project, get_project_info
|
||||||
|
|
||||||
**Core PCB Operations:**
|
**Core PCB Operations:**
|
||||||
|
|
||||||
- place_component, move_component
|
- place_component, move_component
|
||||||
- add_net, route_trace
|
- add_net, route_trace
|
||||||
- get_board_info, set_board_size
|
- get_board_info, set_board_size
|
||||||
- add_board_outline
|
- add_board_outline
|
||||||
|
|
||||||
**UI Management:**
|
**UI Management:**
|
||||||
|
|
||||||
- check_kicad_ui
|
- check_kicad_ui
|
||||||
|
|
||||||
## Router Tools
|
## Router Tools
|
||||||
|
|
||||||
### list_tool_categories
|
### list_tool_categories
|
||||||
|
|
||||||
Browse all available tool categories.
|
Browse all available tool categories.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Claude, what tool categories are available?
|
Claude, what tool categories are available?
|
||||||
```
|
```
|
||||||
|
|
||||||
### get_category_tools
|
### get_category_tools
|
||||||
|
|
||||||
View all tools in a specific category.
|
View all tools in a specific category.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Show me all export tools available.
|
Show me all export tools available.
|
||||||
```
|
```
|
||||||
|
|
||||||
### search_tools
|
### search_tools
|
||||||
|
|
||||||
Find tools by keyword.
|
Find tools by keyword.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Search for tools related to "gerber" or "mounting holes"
|
Search for tools related to "gerber" or "mounting holes"
|
||||||
```
|
```
|
||||||
|
|
||||||
### execute_tool
|
### execute_tool
|
||||||
|
|
||||||
Execute any routed tool with parameters.
|
Execute any routed tool with parameters.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
Execute the export_gerber tool with outputDir set to ./fabrication
|
Execute the export_gerber tool with outputDir set to ./fabrication
|
||||||
```
|
```
|
||||||
@@ -114,6 +141,7 @@ Execute the export_gerber tool with outputDir set to ./fabrication
|
|||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
### Natural Interaction (Recommended)
|
### Natural Interaction (Recommended)
|
||||||
|
|
||||||
Just ask Claude what you want - it handles discovery automatically:
|
Just ask Claude what you want - it handles discovery automatically:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -124,6 +152,7 @@ Just ask Claude what you want - it handles discovery automatically:
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Manual Discovery (Optional)
|
### Manual Discovery (Optional)
|
||||||
|
|
||||||
You can also browse tools explicitly:
|
You can also browse tools explicitly:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -147,6 +176,7 @@ You can also browse tools explicitly:
|
|||||||
- **Server Integration**: `src/server.ts` - Router tools registered at startup
|
- **Server Integration**: `src/server.ts` - Router tools registered at startup
|
||||||
|
|
||||||
For implementation details, see:
|
For implementation details, see:
|
||||||
|
|
||||||
- [ROUTER_ARCHITECTURE.md](ROUTER_ARCHITECTURE.md) - Design specification
|
- [ROUTER_ARCHITECTURE.md](ROUTER_ARCHITECTURE.md) - Design specification
|
||||||
- [ROUTER_IMPLEMENTATION_STATUS.md](ROUTER_IMPLEMENTATION_STATUS.md) - Current status
|
- [ROUTER_IMPLEMENTATION_STATUS.md](ROUTER_IMPLEMENTATION_STATUS.md) - Current status
|
||||||
- [TOOL_INVENTORY.md](TOOL_INVENTORY.md) - Complete tool catalog
|
- [TOOL_INVENTORY.md](TOOL_INVENTORY.md) - Complete tool catalog
|
||||||
@@ -154,9 +184,11 @@ For implementation details, see:
|
|||||||
## Token Savings
|
## Token Savings
|
||||||
|
|
||||||
**Before Router:**
|
**Before Router:**
|
||||||
|
|
||||||
- 122 tools × ~700 tokens each = ~85K tokens per conversation
|
- 122 tools × ~700 tokens each = ~85K tokens per conversation
|
||||||
|
|
||||||
**After Router (Current):**
|
**After Router (Current):**
|
||||||
|
|
||||||
- 12 direct tools + 4 router tools = 16 tools visible
|
- 12 direct tools + 4 router tools = 16 tools visible
|
||||||
- Routed tools discovered on-demand
|
- Routed tools discovered on-demand
|
||||||
- ~12-15K tokens per conversation
|
- ~12-15K tokens per conversation
|
||||||
|
|||||||
@@ -13,16 +13,18 @@ Create a new net on the PCB.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | -------------- |
|
||||||
| name | string | Yes | Net name |
|
| name | string | Yes | Net name |
|
||||||
| netClass | string | No | Net class name |
|
| netClass | string | No | Net class name |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Creates a new net that can be assigned to traces and pads
|
- Creates a new net that can be assigned to traces and pads
|
||||||
- If the net already exists, it will be reused
|
- If the net already exists, it will be reused
|
||||||
- Net class assignment is optional; defaults to "Default" if not specified
|
- Net class assignment is optional; defaults to "Default" if not specified
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"name": "VCC_3V3",
|
"name": "VCC_3V3",
|
||||||
@@ -39,7 +41,7 @@ Route a trace segment between two XY points on a fixed layer.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | ------------------------------------------- |
|
||||||
| start | object | Yes | Start position with x, y, and optional unit |
|
| start | object | Yes | Start position with x, y, and optional unit |
|
||||||
| end | object | Yes | End position with x, y, and optional unit |
|
| end | object | Yes | End position with x, y, and optional unit |
|
||||||
| layer | string | Yes | PCB layer |
|
| layer | string | Yes | PCB layer |
|
||||||
@@ -47,16 +49,18 @@ Route a trace segment between two XY points on a fixed layer.
|
|||||||
| net | string | Yes | Net name |
|
| net | string | Yes | Net name |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- WARNING: Does NOT handle layer changes
|
- WARNING: Does NOT handle layer changes
|
||||||
- If start and end are on different copper layers, use `route_pad_to_pad` instead, which automatically inserts a via
|
- If start and end are on different copper layers, use `route_pad_to_pad` instead, which automatically inserts a via
|
||||||
- Coordinates use mm by default unless unit is specified
|
- Coordinates use mm by default unless unit is specified
|
||||||
- This is a low-level tool; prefer `route_pad_to_pad` for component-to-component routing
|
- This is a low-level tool; prefer `route_pad_to_pad` for component-to-component routing
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"start": {"x": 100.0, "y": 50.0, "unit": "mm"},
|
"start": { "x": 100.0, "y": 50.0, "unit": "mm" },
|
||||||
"end": {"x": 120.0, "y": 50.0, "unit": "mm"},
|
"end": { "x": 120.0, "y": 50.0, "unit": "mm" },
|
||||||
"layer": "F.Cu",
|
"layer": "F.Cu",
|
||||||
"width": 0.25,
|
"width": 0.25,
|
||||||
"net": "GND"
|
"net": "GND"
|
||||||
@@ -72,7 +76,7 @@ PREFERRED tool for pad-to-pad routing. Looks up pad positions automatically, det
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------------- | -------- | ---------------------------------------------------- |
|
||||||
| fromRef | string | Yes | Reference of the source component (e.g. 'U2') |
|
| fromRef | string | Yes | Reference of the source component (e.g. 'U2') |
|
||||||
| fromPad | string/number | Yes | Pad number on the source component (e.g. '6' or 6) |
|
| fromPad | string/number | Yes | Pad number on the source component (e.g. '6' or 6) |
|
||||||
| toRef | string | Yes | Reference of the target component (e.g. 'U1') |
|
| toRef | string | Yes | Reference of the target component (e.g. 'U1') |
|
||||||
@@ -82,6 +86,7 @@ PREFERRED tool for pad-to-pad routing. Looks up pad positions automatically, det
|
|||||||
| net | string | No | Net name override (default: auto-detected from pad) |
|
| net | string | No | Net name override (default: auto-detected from pad) |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- This is the PREFERRED tool for routing between component pads
|
- This is the PREFERRED tool for routing between component pads
|
||||||
- Automatically looks up pad positions - no need to query them separately
|
- Automatically looks up pad positions - no need to query them separately
|
||||||
- Auto-detects the net from the source pad
|
- Auto-detects the net from the source pad
|
||||||
@@ -90,6 +95,7 @@ PREFERRED tool for pad-to-pad routing. Looks up pad positions automatically, det
|
|||||||
- Via is placed at the start pad's X coordinate to avoid stacking issues with back-to-back mirrored connectors
|
- Via is placed at the start pad's X coordinate to avoid stacking issues with back-to-back mirrored connectors
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"fromRef": "U2",
|
"fromRef": "U2",
|
||||||
@@ -111,21 +117,23 @@ Add a via to the PCB.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | ----------------------------------------- |
|
||||||
| position | object | Yes | Via position with x, y, and optional unit |
|
| position | object | Yes | Via position with x, y, and optional unit |
|
||||||
| net | string | Yes | Net name |
|
| net | string | Yes | Net name |
|
||||||
| viaType | string | No | Via type: "through", "blind", or "buried" |
|
| viaType | string | No | Via type: "through", "blind", or "buried" |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Through vias connect all layers (default)
|
- Through vias connect all layers (default)
|
||||||
- Blind vias connect an outer layer to one or more inner layers
|
- Blind vias connect an outer layer to one or more inner layers
|
||||||
- Buried vias connect two or more inner layers without reaching outer layers
|
- Buried vias connect two or more inner layers without reaching outer layers
|
||||||
- Position coordinates use mm by default
|
- Position coordinates use mm by default
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"position": {"x": 110.0, "y": 50.0, "unit": "mm"},
|
"position": { "x": 110.0, "y": 50.0, "unit": "mm" },
|
||||||
"net": "GND",
|
"net": "GND",
|
||||||
"viaType": "through"
|
"viaType": "through"
|
||||||
}
|
}
|
||||||
@@ -142,7 +150,7 @@ Route a differential pair between two sets of points.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ----------- | ------ | -------- | ------------------------------------------ |
|
||||||
| positivePad | object | Yes | Positive pad with reference and pad number |
|
| positivePad | object | Yes | Positive pad with reference and pad number |
|
||||||
| negativePad | object | Yes | Negative pad with reference and pad number |
|
| negativePad | object | Yes | Negative pad with reference and pad number |
|
||||||
| layer | string | Yes | PCB layer |
|
| layer | string | Yes | PCB layer |
|
||||||
@@ -152,16 +160,18 @@ Route a differential pair between two sets of points.
|
|||||||
| negativeNet | string | Yes | Negative net name |
|
| negativeNet | string | Yes | Negative net name |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Used for high-speed signals like USB, Ethernet, HDMI, etc.
|
- Used for high-speed signals like USB, Ethernet, HDMI, etc.
|
||||||
- Maintains controlled impedance through consistent trace width and gap
|
- Maintains controlled impedance through consistent trace width and gap
|
||||||
- Both traces are routed in parallel with specified separation
|
- Both traces are routed in parallel with specified separation
|
||||||
- Pad object format: `{"reference": "U1", "pad": "1"}`
|
- Pad object format: `{"reference": "U1", "pad": "1"}`
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"positivePad": {"reference": "J1", "pad": "2"},
|
"positivePad": { "reference": "J1", "pad": "2" },
|
||||||
"negativePad": {"reference": "J1", "pad": "3"},
|
"negativePad": { "reference": "J1", "pad": "3" },
|
||||||
"layer": "F.Cu",
|
"layer": "F.Cu",
|
||||||
"width": 0.2,
|
"width": 0.2,
|
||||||
"gap": 0.2,
|
"gap": 0.2,
|
||||||
@@ -179,13 +189,14 @@ Copy routing pattern (traces and vias) from a group of source components to a ma
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ----------- | ------------- | -------- | ----------------------------------------------------------------------------------------- |
|
||||||
| sourceRefs | array[string] | Yes | References of the source components (e.g. ['U1', 'R1', 'C1']) |
|
| sourceRefs | array[string] | Yes | References of the source components (e.g. ['U1', 'R1', 'C1']) |
|
||||||
| targetRefs | array[string] | Yes | References of the target components in same order as sourceRefs (e.g. ['U2', 'R2', 'C2']) |
|
| targetRefs | array[string] | Yes | References of the target components in same order as sourceRefs (e.g. ['U2', 'R2', 'C2']) |
|
||||||
| includeVias | boolean | No | Also copy vias (default: true) |
|
| includeVias | boolean | No | Also copy vias (default: true) |
|
||||||
| traceWidth | number | No | Override trace width in mm (default: keep original width) |
|
| traceWidth | number | No | Override trace width in mm (default: keep original width) |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- The offset is calculated automatically from the position difference between the first source and first target component
|
- The offset is calculated automatically from the position difference between the first source and first target component
|
||||||
- Useful for replicating routing between identical circuit blocks
|
- Useful for replicating routing between identical circuit blocks
|
||||||
- Component arrays must be in matching order (sourceRefs[0] maps to targetRefs[0], etc.)
|
- Component arrays must be in matching order (sourceRefs[0] maps to targetRefs[0], etc.)
|
||||||
@@ -194,6 +205,7 @@ Copy routing pattern (traces and vias) from a group of source components to a ma
|
|||||||
- Original trace widths are preserved unless traceWidth override is specified
|
- Original trace widths are preserved unless traceWidth override is specified
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"sourceRefs": ["U1", "R1", "C1"],
|
"sourceRefs": ["U1", "R1", "C1"],
|
||||||
@@ -213,17 +225,19 @@ Get a list of all nets in the PCB with optional statistics.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------ | ------- | -------- | ---------------------------------------------------- |
|
||||||
| includeStats | boolean | No | Include statistics (track count, total length, etc.) |
|
| includeStats | boolean | No | Include statistics (track count, total length, etc.) |
|
||||||
| unit | string | No | Unit for length measurements: "mm" or "inch" |
|
| unit | string | No | Unit for length measurements: "mm" or "inch" |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Returns all nets present in the board
|
- Returns all nets present in the board
|
||||||
- Statistics include track count, via count, and total trace length
|
- Statistics include track count, via count, and total trace length
|
||||||
- Useful for verifying net connectivity and routing completeness
|
- Useful for verifying net connectivity and routing completeness
|
||||||
- Length measurements default to mm
|
- Length measurements default to mm
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"includeStats": true,
|
"includeStats": true,
|
||||||
@@ -240,7 +254,7 @@ Create a new net class with custom design rules.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ----------- | ------ | -------- | ------------------------- |
|
||||||
| name | string | Yes | Net class name |
|
| name | string | Yes | Net class name |
|
||||||
| traceWidth | number | No | Default trace width in mm |
|
| traceWidth | number | No | Default trace width in mm |
|
||||||
| clearance | number | No | Clearance in mm |
|
| clearance | number | No | Clearance in mm |
|
||||||
@@ -248,12 +262,14 @@ Create a new net class with custom design rules.
|
|||||||
| viaDrill | number | No | Via drill size in mm |
|
| viaDrill | number | No | Via drill size in mm |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Net classes define design rules for groups of nets
|
- Net classes define design rules for groups of nets
|
||||||
- Common use cases: power nets (wider traces), high-speed signals (controlled impedance)
|
- Common use cases: power nets (wider traces), high-speed signals (controlled impedance)
|
||||||
- Once created, assign nets to the class using the netClass parameter in `add_net`
|
- Once created, assign nets to the class using the netClass parameter in `add_net`
|
||||||
- All measurements in mm
|
- All measurements in mm
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"name": "Power",
|
"name": "Power",
|
||||||
@@ -275,7 +291,7 @@ Delete traces from the PCB. Can delete by UUID, position, or bulk-delete all tra
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ----------- | ------- | -------- | ----------------------------------------------------------- |
|
||||||
| traceUuid | string | No | UUID of a specific trace to delete |
|
| traceUuid | string | No | UUID of a specific trace to delete |
|
||||||
| position | object | No | Delete trace nearest to this position (x, y, optional unit) |
|
| position | object | No | Delete trace nearest to this position (x, y, optional unit) |
|
||||||
| net | string | No | Delete all traces on this net (bulk delete) |
|
| net | string | No | Delete all traces on this net (bulk delete) |
|
||||||
@@ -283,12 +299,14 @@ Delete traces from the PCB. Can delete by UUID, position, or bulk-delete all tra
|
|||||||
| includeVias | boolean | No | Include vias in net-based deletion |
|
| includeVias | boolean | No | Include vias in net-based deletion |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Three deletion modes: by UUID (specific), by position (nearest), or by net (bulk)
|
- Three deletion modes: by UUID (specific), by position (nearest), or by net (bulk)
|
||||||
- Position-based deletion finds the closest trace to the specified coordinates
|
- Position-based deletion finds the closest trace to the specified coordinates
|
||||||
- Net-based deletion can be filtered by layer
|
- Net-based deletion can be filtered by layer
|
||||||
- Vias are excluded from net-based deletion by default unless includeVias is true
|
- Vias are excluded from net-based deletion by default unless includeVias is true
|
||||||
|
|
||||||
**Example (bulk delete):**
|
**Example (bulk delete):**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"net": "GND",
|
"net": "GND",
|
||||||
@@ -306,19 +324,21 @@ Query traces on the board with optional filters by net, layer, or bounding box.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ----------- | ------ | -------- | ------------------------------------------------------------- |
|
||||||
| net | string | No | Filter by net name |
|
| net | string | No | Filter by net name |
|
||||||
| layer | string | No | Filter by layer name |
|
| layer | string | No | Filter by layer name |
|
||||||
| boundingBox | object | No | Filter by bounding box region (x1, y1, x2, y2, optional unit) |
|
| boundingBox | object | No | Filter by bounding box region (x1, y1, x2, y2, optional unit) |
|
||||||
| unit | string | No | Unit for coordinates: "mm" or "inch" |
|
| unit | string | No | Unit for coordinates: "mm" or "inch" |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Returns trace information including UUID, position, width, layer, and net
|
- Returns trace information including UUID, position, width, layer, and net
|
||||||
- Filters can be combined (e.g., specific net on specific layer)
|
- Filters can be combined (e.g., specific net on specific layer)
|
||||||
- Bounding box uses rectangular region defined by opposite corners
|
- Bounding box uses rectangular region defined by opposite corners
|
||||||
- Useful for analyzing routing in specific board regions or on specific nets
|
- Useful for analyzing routing in specific board regions or on specific nets
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"net": "VCC_3V3",
|
"net": "VCC_3V3",
|
||||||
@@ -335,19 +355,21 @@ Modify an existing trace (change width, layer, or net).
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | --------------------------- |
|
||||||
| traceUuid | string | Yes | UUID of the trace to modify |
|
| traceUuid | string | Yes | UUID of the trace to modify |
|
||||||
| width | number | No | New trace width in mm |
|
| width | number | No | New trace width in mm |
|
||||||
| layer | string | No | New layer name |
|
| layer | string | No | New layer name |
|
||||||
| net | string | No | New net name |
|
| net | string | No | New net name |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Requires the trace UUID, which can be obtained from `query_traces`
|
- Requires the trace UUID, which can be obtained from `query_traces`
|
||||||
- At least one modification parameter (width, layer, or net) must be provided
|
- At least one modification parameter (width, layer, or net) must be provided
|
||||||
- Use with caution when changing nets - ensure electrical correctness
|
- Use with caution when changing nets - ensure electrical correctness
|
||||||
- Width changes are useful for adjusting impedance or current capacity
|
- Width changes are useful for adjusting impedance or current capacity
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"traceUuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
"traceUuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||||
@@ -366,13 +388,14 @@ Add a copper pour (ground/power plane) to the PCB.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------------- | -------- | ----------------------------------------------------------------------------------------- |
|
||||||
| layer | string | Yes | PCB layer |
|
| layer | string | Yes | PCB layer |
|
||||||
| net | string | Yes | Net name |
|
| net | string | Yes | Net name |
|
||||||
| clearance | number | No | Clearance in mm |
|
| clearance | number | No | Clearance in mm |
|
||||||
| outline | array[object] | No | Array of {x, y} points defining the pour boundary. If omitted, the board outline is used. |
|
| outline | array[object] | No | Array of {x, y} points defining the pour boundary. If omitted, the board outline is used. |
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- Copper pours are typically used for ground and power planes
|
- Copper pours are typically used for ground and power planes
|
||||||
- If no outline is specified, the pour fills the entire board area
|
- If no outline is specified, the pour fills the entire board area
|
||||||
- Custom outlines are defined as arrays of coordinate points
|
- Custom outlines are defined as arrays of coordinate points
|
||||||
@@ -380,16 +403,17 @@ Add a copper pour (ground/power plane) to the PCB.
|
|||||||
- After adding a pour, use `refill_zones` to fill it
|
- After adding a pour, use `refill_zones` to fill it
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"layer": "B.Cu",
|
"layer": "B.Cu",
|
||||||
"net": "GND",
|
"net": "GND",
|
||||||
"clearance": 0.2,
|
"clearance": 0.2,
|
||||||
"outline": [
|
"outline": [
|
||||||
{"x": 10.0, "y": 10.0},
|
{ "x": 10.0, "y": 10.0 },
|
||||||
{"x": 90.0, "y": 10.0},
|
{ "x": 90.0, "y": 10.0 },
|
||||||
{"x": 90.0, "y": 60.0},
|
{ "x": 90.0, "y": 60.0 },
|
||||||
{"x": 10.0, "y": 60.0}
|
{ "x": 10.0, "y": 60.0 }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -405,6 +429,7 @@ Refill all copper zones on the board.
|
|||||||
None
|
None
|
||||||
|
|
||||||
**Usage Notes:**
|
**Usage Notes:**
|
||||||
|
|
||||||
- WARNING: SWIG path has known segfault risk (see KNOWN_ISSUES.md)
|
- WARNING: SWIG path has known segfault risk (see KNOWN_ISSUES.md)
|
||||||
- Prefer using IPC backend (KiCAD open) or triggering zone fill via KiCAD UI instead
|
- Prefer using IPC backend (KiCAD open) or triggering zone fill via KiCAD UI instead
|
||||||
- Required after adding or modifying copper pours to calculate the filled areas
|
- Required after adding or modifying copper pours to calculate the filled areas
|
||||||
@@ -412,6 +437,7 @@ None
|
|||||||
- May take several seconds on complex boards with many zones
|
- May take several seconds on complex boards with many zones
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{}
|
{}
|
||||||
```
|
```
|
||||||
@@ -439,6 +465,7 @@ The simplest and most robust approach for connecting component pads:
|
|||||||
```
|
```
|
||||||
|
|
||||||
This automatically:
|
This automatically:
|
||||||
|
|
||||||
- Looks up the exact pad positions
|
- Looks up the exact pad positions
|
||||||
- Detects the net from the pads
|
- Detects the net from the pads
|
||||||
- Creates the trace on the appropriate layer
|
- Creates the trace on the appropriate layer
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ This document provides a complete reference for the 27 schematic tools in the Ki
|
|||||||
## Component Operations (8 tools)
|
## Component Operations (8 tools)
|
||||||
|
|
||||||
### add_schematic_component
|
### add_schematic_component
|
||||||
|
|
||||||
Add a component to the schematic. Symbol format is 'Library:SymbolName' (e.g., 'Device:R', 'EDA-MCP:ESP32-C3').
|
Add a component to the schematic. Symbol format is 'Library:SymbolName' (e.g., 'Device:R', 'EDA-MCP:ESP32-C3').
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ---------------------------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the schematic file |
|
| schematicPath | string | Yes | Path to the schematic file |
|
||||||
| symbol | string | Yes | Symbol library:name reference (e.g., Device:R, EDA-MCP:ESP32-C3) |
|
| symbol | string | Yes | Symbol library:name reference (e.g., Device:R, EDA-MCP:ESP32-C3) |
|
||||||
| reference | string | Yes | Component reference (e.g., R1, U1) |
|
| reference | string | Yes | Component reference (e.g., R1, U1) |
|
||||||
@@ -22,18 +23,20 @@ Add a component to the schematic. Symbol format is 'Library:SymbolName' (e.g., '
|
|||||||
**Usage Notes:** The dynamic symbol loader provides access to ~10,000 KiCad standard symbols. If a symbol is not in the static template map, it will be loaded dynamically from the specified library.
|
**Usage Notes:** The dynamic symbol loader provides access to ~10,000 KiCad standard symbols. If a symbol is not in the static template map, it will be loaded dynamically from the specified library.
|
||||||
|
|
||||||
### delete_schematic_component
|
### delete_schematic_component
|
||||||
|
|
||||||
Remove a placed symbol from a KiCAD schematic (.kicad_sch). This removes the symbol instance (the placed component) from the schematic. It does NOT remove the symbol definition from lib_symbols. Note: This tool operates on schematic files (.kicad_sch). To remove a footprint from a PCB, use delete_component instead.
|
Remove a placed symbol from a KiCAD schematic (.kicad_sch). This removes the symbol instance (the placed component) from the schematic. It does NOT remove the symbol definition from lib_symbols. Note: This tool operates on schematic files (.kicad_sch). To remove a footprint from a PCB, use delete_component instead.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ------------------------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| reference | string | Yes | Reference designator of the component to remove (e.g. R1, U3) |
|
| reference | string | Yes | Reference designator of the component to remove (e.g. R1, U3) |
|
||||||
|
|
||||||
### edit_schematic_component
|
### edit_schematic_component
|
||||||
|
|
||||||
Update properties of a placed symbol in a KiCAD schematic (.kicad_sch) in-place. Use this tool to assign or update a footprint, change the value, or rename the reference of an already-placed component. This is more efficient than delete + re-add because it preserves the component's position and UUID. Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_component.
|
Update properties of a placed symbol in a KiCAD schematic (.kicad_sch) in-place. Use this tool to assign or update a footprint, change the value, or rename the reference of an already-placed component. This is more efficient than delete + re-add because it preserves the component's position and UUID. Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_component.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| -------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| reference | string | Yes | Current reference designator of the component (e.g. R1, U3) |
|
| reference | string | Yes | Current reference designator of the component (e.g. R1, U3) |
|
||||||
| footprint | string | No | New KiCAD footprint string (e.g. Resistor_SMD:R_0603_1608Metric) |
|
| footprint | string | No | New KiCAD footprint string (e.g. Resistor_SMD:R_0603_1608Metric) |
|
||||||
@@ -42,64 +45,71 @@ Update properties of a placed symbol in a KiCAD schematic (.kicad_sch) in-place.
|
|||||||
| fieldPositions | object | No | Reposition field labels: map of field name to {x, y, angle} (e.g. {"Reference": {"x": 12.5, "y": 17.0}}) |
|
| fieldPositions | object | No | Reposition field labels: map of field name to {x, y, angle} (e.g. {"Reference": {"x": 12.5, "y": 17.0}}) |
|
||||||
|
|
||||||
### get_schematic_component
|
### get_schematic_component
|
||||||
|
|
||||||
Get full component info from a schematic: position, field values, and each field's label position (at x/y/angle). Use this to inspect or prepare repositioning of Reference/Value labels.
|
Get full component info from a schematic: position, field values, and each field's label position (at x/y/angle). Use this to inspect or prepare repositioning of Reference/Value labels.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | -------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| reference | string | Yes | Component reference designator (e.g. R1, U1) |
|
| reference | string | Yes | Component reference designator (e.g. R1, U1) |
|
||||||
|
|
||||||
### list_schematic_components
|
### list_schematic_components
|
||||||
|
|
||||||
List all components in a schematic with their references, values, positions, and pins. Essential for inspecting what's on the schematic before making edits.
|
List all components in a schematic with their references, values, positions, and pins. Essential for inspecting what's on the schematic before making edits.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ---------------------- | ------ | -------- | --------------------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| filter | object | No | Optional filters with libId and/or referencePrefix fields |
|
| filter | object | No | Optional filters with libId and/or referencePrefix fields |
|
||||||
| filter.libId | string | No | Filter by library ID (e.g., 'Device:R') |
|
| filter.libId | string | No | Filter by library ID (e.g., 'Device:R') |
|
||||||
| filter.referencePrefix | string | No | Filter by reference prefix (e.g., 'R', 'C', 'U') |
|
| filter.referencePrefix | string | No | Filter by reference prefix (e.g., 'R', 'C', 'U') |
|
||||||
|
|
||||||
### move_schematic_component
|
### move_schematic_component
|
||||||
|
|
||||||
Move a placed symbol to a new position in the schematic.
|
Move a placed symbol to a new position in the schematic.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| reference | string | Yes | Reference designator (e.g., R1, U1) |
|
| reference | string | Yes | Reference designator (e.g., R1, U1) |
|
||||||
| position | object | Yes | New position with x and y coordinates |
|
| position | object | Yes | New position with x and y coordinates |
|
||||||
|
|
||||||
### rotate_schematic_component
|
### rotate_schematic_component
|
||||||
|
|
||||||
Rotate a placed symbol in the schematic.
|
Rotate a placed symbol in the schematic.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| reference | string | Yes | Reference designator (e.g., R1, U1) |
|
| reference | string | Yes | Reference designator (e.g., R1, U1) |
|
||||||
| angle | number | Yes | Rotation angle in degrees (0, 90, 180, 270) |
|
| angle | number | Yes | Rotation angle in degrees (0, 90, 180, 270) |
|
||||||
| mirror | enum | No | Optional mirror axis ("x" or "y") |
|
| mirror | enum | No | Optional mirror axis ("x" or "y") |
|
||||||
|
|
||||||
### annotate_schematic
|
### annotate_schematic
|
||||||
|
|
||||||
Assign reference designators to unannotated components (R? → R1, R2, ...). Must be called before tools that require known references.
|
Assign reference designators to unannotated components (R? → R1, R2, ...). Must be called before tools that require known references.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | --------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
|
|
||||||
## Wiring and Connections (8 tools)
|
## Wiring and Connections (8 tools)
|
||||||
|
|
||||||
### add_wire
|
### add_wire
|
||||||
|
|
||||||
Add a wire connection in the schematic.
|
Add a wire connection in the schematic.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | --------------------------------------- |
|
||||||
| start | object | Yes | Start position with x and y coordinates |
|
| start | object | Yes | Start position with x and y coordinates |
|
||||||
| end | object | Yes | End position with x and y coordinates |
|
| end | object | Yes | End position with x and y coordinates |
|
||||||
|
|
||||||
### add_schematic_connection
|
### add_schematic_connection
|
||||||
|
|
||||||
Connect two component pins with a wire. Use this for individual connections between components with different pin roles (e.g. U1.SDA → J3.2). WARNING: Do NOT use this in a loop to wire N passthrough pins — use connect_passthrough instead (single call, cleaner layout, far fewer tokens).
|
Connect two component pins with a wire. Use this for individual connections between components with different pin roles (e.g. U1.SDA → J3.2). WARNING: Do NOT use this in a loop to wire N passthrough pins — use connect_passthrough instead (single call, cleaner layout, far fewer tokens).
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ---------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the schematic file |
|
| schematicPath | string | Yes | Path to the schematic file |
|
||||||
| sourceRef | string | Yes | Source component reference (e.g., R1) |
|
| sourceRef | string | Yes | Source component reference (e.g., R1) |
|
||||||
| sourcePin | string | Yes | Source pin name/number (e.g., 1, 2, GND) |
|
| sourcePin | string | Yes | Source pin name/number (e.g., 1, 2, GND) |
|
||||||
@@ -107,19 +117,21 @@ Connect two component pins with a wire. Use this for individual connections betw
|
|||||||
| targetPin | string | Yes | Target pin name/number (e.g., 1, 2, VCC) |
|
| targetPin | string | Yes | Target pin name/number (e.g., 1, 2, VCC) |
|
||||||
|
|
||||||
### add_schematic_net_label
|
### add_schematic_net_label
|
||||||
|
|
||||||
Add a net label to the schematic.
|
Add a net label to the schematic.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ------------------------------------------ |
|
||||||
| schematicPath | string | Yes | Path to the schematic file |
|
| schematicPath | string | Yes | Path to the schematic file |
|
||||||
| netName | string | Yes | Name of the net (e.g., VCC, GND, SIGNAL_1) |
|
| netName | string | Yes | Name of the net (e.g., VCC, GND, SIGNAL_1) |
|
||||||
| position | array | Yes | Position [x, y] for the label |
|
| position | array | Yes | Position [x, y] for the label |
|
||||||
|
|
||||||
### connect_to_net
|
### connect_to_net
|
||||||
|
|
||||||
Connect a component pin to a named net.
|
Connect a component pin to a named net.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ---------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the schematic file |
|
| schematicPath | string | Yes | Path to the schematic file |
|
||||||
| componentRef | string | Yes | Component reference (e.g., U1, R1) |
|
| componentRef | string | Yes | Component reference (e.g., U1, R1) |
|
||||||
| pinName | string | Yes | Pin name/number to connect |
|
| pinName | string | Yes | Pin name/number to connect |
|
||||||
@@ -128,10 +140,11 @@ Connect a component pin to a named net.
|
|||||||
**Usage Notes:** Creates a wire stub from the pin and places a net label at the stub endpoint. The stub direction follows the pin's outward angle. Default stub length is 2.54mm (0.1 inch, standard grid spacing).
|
**Usage Notes:** Creates a wire stub from the pin and places a net label at the stub endpoint. The stub direction follows the pin's outward angle. Default stub length is 2.54mm (0.1 inch, standard grid spacing).
|
||||||
|
|
||||||
### connect_passthrough
|
### connect_passthrough
|
||||||
Connects all pins of a source connector (e.g. J1) to matching pins of a target connector (e.g. J2) via shared net labels — pin N gets net '{netPrefix}_{N}'. Use this for FFC/ribbon cable passthrough adapters instead of calling connect_to_net for every pin.
|
|
||||||
|
Connects all pins of a source connector (e.g. J1) to matching pins of a target connector (e.g. J2) via shared net labels — pin N gets net '{netPrefix}\_{N}'. Use this for FFC/ribbon cable passthrough adapters instead of calling connect_to_net for every pin.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | --------------------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the schematic file |
|
| schematicPath | string | Yes | Path to the schematic file |
|
||||||
| sourceRef | string | Yes | Source connector reference (e.g. J1) |
|
| sourceRef | string | Yes | Source connector reference (e.g. J1) |
|
||||||
| targetRef | string | Yes | Target connector reference (e.g. J2) |
|
| targetRef | string | Yes | Target connector reference (e.g. J2) |
|
||||||
@@ -141,27 +154,30 @@ Connects all pins of a source connector (e.g. J1) to matching pins of a target c
|
|||||||
**Usage Notes:** This is the most efficient way to wire passthrough adapters. For an N-pin connector, this replaces N individual connect_to_net calls with a single operation.
|
**Usage Notes:** This is the most efficient way to wire passthrough adapters. For an N-pin connector, this replaces N individual connect_to_net calls with a single operation.
|
||||||
|
|
||||||
### get_schematic_pin_locations
|
### get_schematic_pin_locations
|
||||||
|
|
||||||
Returns the exact x/y coordinates of every pin on a schematic component. Use this before add_schematic_net_label to place labels correctly on pin endpoints.
|
Returns the exact x/y coordinates of every pin on a schematic component. Use this before add_schematic_net_label to place labels correctly on pin endpoints.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ------------------------------------------------ |
|
||||||
| schematicPath | string | Yes | Path to the schematic file |
|
| schematicPath | string | Yes | Path to the schematic file |
|
||||||
| reference | string | Yes | Component reference designator (e.g. U1, R1, J2) |
|
| reference | string | Yes | Component reference designator (e.g. U1, R1, J2) |
|
||||||
|
|
||||||
### delete_schematic_wire
|
### delete_schematic_wire
|
||||||
|
|
||||||
Remove a wire from the schematic by start and end coordinates.
|
Remove a wire from the schematic by start and end coordinates.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | -------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| start | object | Yes | Wire start position with x and y coordinates |
|
| start | object | Yes | Wire start position with x and y coordinates |
|
||||||
| end | object | Yes | Wire end position with x and y coordinates |
|
| end | object | Yes | Wire end position with x and y coordinates |
|
||||||
|
|
||||||
### delete_schematic_net_label
|
### delete_schematic_net_label
|
||||||
|
|
||||||
Remove a net label from the schematic.
|
Remove a net label from the schematic.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | -------------------------------------------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| netName | string | Yes | Name of the net label to remove |
|
| netName | string | Yes | Name of the net label to remove |
|
||||||
| position | object | No | Position to disambiguate if multiple labels with same name (x and y coordinates) |
|
| position | object | No | Position to disambiguate if multiple labels with same name (x and y coordinates) |
|
||||||
@@ -169,79 +185,88 @@ Remove a net label from the schematic.
|
|||||||
## Net Analysis (4 tools)
|
## Net Analysis (4 tools)
|
||||||
|
|
||||||
### get_net_connections
|
### get_net_connections
|
||||||
|
|
||||||
Get all connections for a named net.
|
Get all connections for a named net.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | -------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the schematic file |
|
| schematicPath | string | Yes | Path to the schematic file |
|
||||||
| netName | string | Yes | Name of the net to query |
|
| netName | string | Yes | Name of the net to query |
|
||||||
|
|
||||||
**Usage Notes:** Uses wire graph analysis to find all component pins connected to the specified net. Returns a list of {component, pin} pairs.
|
**Usage Notes:** Uses wire graph analysis to find all component pins connected to the specified net. Returns a list of {component, pin} pairs.
|
||||||
|
|
||||||
### list_schematic_nets
|
### list_schematic_nets
|
||||||
|
|
||||||
List all nets in the schematic with their connections.
|
List all nets in the schematic with their connections.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | --------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
|
|
||||||
### list_schematic_wires
|
### list_schematic_wires
|
||||||
|
|
||||||
List all wires in the schematic with start/end coordinates.
|
List all wires in the schematic with start/end coordinates.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | --------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
|
|
||||||
### list_schematic_labels
|
### list_schematic_labels
|
||||||
|
|
||||||
List all net labels, global labels, and power flags in the schematic.
|
List all net labels, global labels, and power flags in the schematic.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | --------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
|
|
||||||
## Schematic Creation and Export (5 tools)
|
## Schematic Creation and Export (5 tools)
|
||||||
|
|
||||||
### create_schematic
|
### create_schematic
|
||||||
|
|
||||||
Create a new schematic.
|
Create a new schematic.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| --------- | ------ | -------- | -------------- |
|
||||||
| name | string | Yes | Schematic name |
|
| name | string | Yes | Schematic name |
|
||||||
| path | string | No | Optional path |
|
| path | string | No | Optional path |
|
||||||
|
|
||||||
### export_schematic_svg
|
### export_schematic_svg
|
||||||
|
|
||||||
Export schematic to SVG format using kicad-cli.
|
Export schematic to SVG format using kicad-cli.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------- | -------- | --------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| outputPath | string | Yes | Output SVG file path |
|
| outputPath | string | Yes | Output SVG file path |
|
||||||
| blackAndWhite | boolean | No | Export in black and white |
|
| blackAndWhite | boolean | No | Export in black and white |
|
||||||
|
|
||||||
### export_schematic_pdf
|
### export_schematic_pdf
|
||||||
|
|
||||||
Export schematic to PDF format using kicad-cli.
|
Export schematic to PDF format using kicad-cli.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------- | -------- | --------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| outputPath | string | Yes | Output PDF file path |
|
| outputPath | string | Yes | Output PDF file path |
|
||||||
| blackAndWhite | boolean | No | Export in black and white |
|
| blackAndWhite | boolean | No | Export in black and white |
|
||||||
|
|
||||||
### get_schematic_view
|
### get_schematic_view
|
||||||
|
|
||||||
Return a rasterized image of the schematic (PNG by default, or SVG). Uses kicad-cli to export SVG, then converts to PNG via cairosvg. Use this for visual feedback after placing or wiring components.
|
Return a rasterized image of the schematic (PNG by default, or SVG). Uses kicad-cli to export SVG, then converts to PNG via cairosvg. Use this for visual feedback after placing or wiring components.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | -------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
| schematicPath | string | Yes | Path to the .kicad_sch file |
|
||||||
| format | enum | No | Output format ("png" or "svg", default: png) |
|
| format | enum | No | Output format ("png" or "svg", default: png) |
|
||||||
| width | number | No | Image width in pixels (default: 1200) |
|
| width | number | No | Image width in pixels (default: 1200) |
|
||||||
| height | number | No | Image height in pixels (default: 900) |
|
| height | number | No | Image height in pixels (default: 900) |
|
||||||
|
|
||||||
### generate_netlist
|
### generate_netlist
|
||||||
|
|
||||||
Generate a netlist from the schematic.
|
Generate a netlist from the schematic.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | -------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the schematic file |
|
| schematicPath | string | Yes | Path to the schematic file |
|
||||||
|
|
||||||
**Usage Notes:** Returns a complete netlist with component information (reference, value, footprint) and net connections (net name with all connected component/pin pairs).
|
**Usage Notes:** Returns a complete netlist with component information (reference, value, footprint) and net connections (net name with all connected component/pin pairs).
|
||||||
@@ -249,19 +274,21 @@ Generate a netlist from the schematic.
|
|||||||
## Validation and Synchronization (3 tools)
|
## Validation and Synchronization (3 tools)
|
||||||
|
|
||||||
### run_erc
|
### run_erc
|
||||||
|
|
||||||
Runs the KiCAD Electrical Rules Check (ERC) on a schematic and returns all violations. Use after wiring to verify the schematic before generating a netlist.
|
Runs the KiCAD Electrical Rules Check (ERC) on a schematic and returns all violations. Use after wiring to verify the schematic before generating a netlist.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ------------------------------------- |
|
||||||
| schematicPath | string | Yes | Path to the .kicad_sch schematic file |
|
| schematicPath | string | Yes | Path to the .kicad_sch schematic file |
|
||||||
|
|
||||||
**Usage Notes:** Returns violations categorized by severity (error, warning, info) with location coordinates. Essential for catching design errors before PCB layout.
|
**Usage Notes:** Returns violations categorized by severity (error, warning, info) with location coordinates. Essential for catching design errors before PCB layout.
|
||||||
|
|
||||||
### sync_schematic_to_board
|
### sync_schematic_to_board
|
||||||
|
|
||||||
Import the schematic netlist into the PCB board — equivalent to pressing F8 in KiCAD (Tools → Update PCB from Schematic). MUST be called after the schematic is complete and before placing or routing components on the PCB. Without this step, the board has no footprints and no net assignments — place_component and route_pad_to_pad will produce an empty, unroutable board.
|
Import the schematic netlist into the PCB board — equivalent to pressing F8 in KiCAD (Tools → Update PCB from Schematic). MUST be called after the schematic is complete and before placing or routing components on the PCB. Without this step, the board has no footprints and no net assignments — place_component and route_pad_to_pad will produce an empty, unroutable board.
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
| ------------- | ------ | -------- | ---------------------------------------------- |
|
||||||
| schematicPath | string | Yes | Absolute path to the .kicad_sch schematic file |
|
| schematicPath | string | Yes | Absolute path to the .kicad_sch schematic file |
|
||||||
| boardPath | string | Yes | Absolute path to the .kicad_pcb board file |
|
| boardPath | string | Yes | Absolute path to the .kicad_pcb board file |
|
||||||
|
|
||||||
@@ -270,6 +297,7 @@ Import the schematic netlist into the PCB board — equivalent to pressing F8 in
|
|||||||
## Example Workflows
|
## Example Workflows
|
||||||
|
|
||||||
### Basic Circuit Design
|
### Basic Circuit Design
|
||||||
|
|
||||||
1. **Create project:** Use `create_schematic` to initialize a new schematic file
|
1. **Create project:** Use `create_schematic` to initialize a new schematic file
|
||||||
2. **Add components:** Use `add_schematic_component` to place resistors, capacitors, ICs, etc.
|
2. **Add components:** Use `add_schematic_component` to place resistors, capacitors, ICs, etc.
|
||||||
- Example: Add a resistor with `symbol: "Device:R"`, `reference: "R1"`, `value: "10k"`
|
- Example: Add a resistor with `symbol: "Device:R"`, `reference: "R1"`, `value: "10k"`
|
||||||
@@ -281,6 +309,7 @@ Import the schematic netlist into the PCB board — equivalent to pressing F8 in
|
|||||||
7. **Sync to PCB:** Use `sync_schematic_to_board` to transfer the design to the PCB layout
|
7. **Sync to PCB:** Use `sync_schematic_to_board` to transfer the design to the PCB layout
|
||||||
|
|
||||||
### FFC Passthrough Adapter
|
### FFC Passthrough Adapter
|
||||||
|
|
||||||
1. **Add connectors:** Place two FFC connectors using `add_schematic_component`
|
1. **Add connectors:** Place two FFC connectors using `add_schematic_component`
|
||||||
- Example: J1 and J2, both 20-pin FFC connectors
|
- Example: J1 and J2, both 20-pin FFC connectors
|
||||||
2. **Connect passthrough:** Use `connect_passthrough` with `sourceRef: "J1"`, `targetRef: "J2"`, `netPrefix: "CSI"`
|
2. **Connect passthrough:** Use `connect_passthrough` with `sourceRef: "J1"`, `targetRef: "J2"`, `netPrefix: "CSI"`
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
## Quick Stats
|
## Quick Stats
|
||||||
|
|
||||||
| Metric | Value |
|
| Metric | Value |
|
||||||
|--------|-------|
|
| -------------------- | --------------------------- |
|
||||||
| Total MCP Tools | 122 |
|
| Total MCP Tools | 122 |
|
||||||
| Tool Categories | 16 |
|
| Tool Categories | 16 |
|
||||||
| KiCAD 9.0 Compatible | Yes (verified) |
|
| KiCAD 9.0 Compatible | Yes (verified) |
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
## Feature Completion Matrix
|
## Feature Completion Matrix
|
||||||
|
|
||||||
| Feature Category | Status | Tool Count | Details |
|
| Feature Category | Status | Tool Count | Details |
|
||||||
|-----------------|--------|------------|---------|
|
| ------------------- | -------- | ---------- | ----------------------------------------------------------------------- |
|
||||||
| Project Management | Complete | 5 | Create, open, save, info, snapshot |
|
| Project Management | Complete | 5 | Create, open, save, info, snapshot |
|
||||||
| Board Setup | Complete | 12 | Size, outline, layers, mounting holes, zones, text, 2D view, SVG import |
|
| Board Setup | Complete | 12 | Size, outline, layers, mounting holes, zones, text, 2D view, SVG import |
|
||||||
| Component Placement | Complete | 16 | Place, move, rotate, delete, edit, find, pads, arrays, align, duplicate |
|
| Component Placement | Complete | 16 | Place, move, rotate, delete, edit, find, pads, arrays, align, duplicate |
|
||||||
@@ -48,6 +48,7 @@
|
|||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### SWIG Backend (File-based) -- Default
|
### SWIG Backend (File-based) -- Default
|
||||||
|
|
||||||
- **Status:** Stable
|
- **Status:** Stable
|
||||||
- Direct pcbnew API access via KiCAD's Python bindings
|
- Direct pcbnew API access via KiCAD's Python bindings
|
||||||
- Requires manual KiCAD UI reload to see changes
|
- Requires manual KiCAD UI reload to see changes
|
||||||
@@ -55,13 +56,16 @@
|
|||||||
- Auto-saves after every board-modifying command
|
- Auto-saves after every board-modifying command
|
||||||
|
|
||||||
### IPC Backend (Real-time) -- Experimental
|
### IPC Backend (Real-time) -- Experimental
|
||||||
|
|
||||||
- **Status:** Functional, 21 commands implemented
|
- **Status:** Functional, 21 commands implemented
|
||||||
- Real-time UI synchronization with KiCAD 9+
|
- Real-time UI synchronization with KiCAD 9+
|
||||||
- Requires KiCAD running with IPC API enabled
|
- Requires KiCAD running with IPC API enabled
|
||||||
- Automatic fallback to SWIG when unavailable
|
- Automatic fallback to SWIG when unavailable
|
||||||
|
|
||||||
### Hybrid Approach
|
### Hybrid Approach
|
||||||
|
|
||||||
The server automatically selects the best backend:
|
The server automatically selects the best backend:
|
||||||
|
|
||||||
- IPC when KiCAD is running with IPC enabled
|
- IPC when KiCAD is running with IPC enabled
|
||||||
- SWIG fallback when IPC is unavailable
|
- SWIG fallback when IPC is unavailable
|
||||||
- Some operations use both (e.g., footprint placement)
|
- Some operations use both (e.g., footprint placement)
|
||||||
@@ -71,18 +75,21 @@ The server automatically selects the best backend:
|
|||||||
## Platform Support
|
## Platform Support
|
||||||
|
|
||||||
### Linux -- Primary Platform
|
### Linux -- Primary Platform
|
||||||
|
|
||||||
- KiCAD 9.0 detection: Working
|
- KiCAD 9.0 detection: Working
|
||||||
- Process management: Working
|
- Process management: Working
|
||||||
- Library discovery: Working (153+ libraries)
|
- Library discovery: Working (153+ libraries)
|
||||||
- IPC backend: Working
|
- IPC backend: Working
|
||||||
|
|
||||||
### Windows -- Fully Supported
|
### Windows -- Fully Supported
|
||||||
|
|
||||||
- Automated setup script (setup-windows.ps1)
|
- Automated setup script (setup-windows.ps1)
|
||||||
- Process detection via Toolhelp32 API
|
- Process detection via Toolhelp32 API
|
||||||
- Library paths auto-detected
|
- Library paths auto-detected
|
||||||
- Troubleshooting guide available (WINDOWS_TROUBLESHOOTING.md)
|
- Troubleshooting guide available (WINDOWS_TROUBLESHOOTING.md)
|
||||||
|
|
||||||
### macOS -- Community Supported
|
### macOS -- Community Supported
|
||||||
|
|
||||||
- Configuration provided
|
- Configuration provided
|
||||||
- Process detection implemented
|
- Process detection implemented
|
||||||
- Library paths configured
|
- Library paths configured
|
||||||
@@ -93,6 +100,7 @@ The server automatically selects the best backend:
|
|||||||
## Recent Development Highlights
|
## Recent Development Highlights
|
||||||
|
|
||||||
### v2.2.3 (2026-03-11)
|
### v2.2.3 (2026-03-11)
|
||||||
|
|
||||||
- FFC/ribbon cable passthrough workflow (connect_passthrough, sync_schematic_to_board)
|
- FFC/ribbon cable passthrough workflow (connect_passthrough, sync_schematic_to_board)
|
||||||
- Project snapshot system
|
- Project snapshot system
|
||||||
- SVG logo import
|
- SVG logo import
|
||||||
@@ -101,20 +109,24 @@ The server automatically selects the best backend:
|
|||||||
- Critical B.Cu routing fixes
|
- Critical B.Cu routing fixes
|
||||||
|
|
||||||
### v2.2.2-alpha (2026-03-01)
|
### v2.2.2-alpha (2026-03-01)
|
||||||
|
|
||||||
- route_pad_to_pad with auto-via insertion
|
- route_pad_to_pad with auto-via insertion
|
||||||
- copy_routing_pattern for trace replication
|
- copy_routing_pattern for trace replication
|
||||||
- Project-local library resolution
|
- Project-local library resolution
|
||||||
|
|
||||||
### v2.2.1-alpha (2026-02-28)
|
### v2.2.1-alpha (2026-02-28)
|
||||||
|
|
||||||
- edit_schematic_component with field position support
|
- edit_schematic_component with field position support
|
||||||
- Footprint and symbol creator tools
|
- Footprint and symbol creator tools
|
||||||
|
|
||||||
### v2.2.0-alpha (2026-02-27)
|
### v2.2.0-alpha (2026-02-27)
|
||||||
|
|
||||||
- 13 new routing/component tools
|
- 13 new routing/component tools
|
||||||
- Datasheet enrichment tools
|
- Datasheet enrichment tools
|
||||||
- SWIG/UUID bug fixes
|
- SWIG/UUID bug fixes
|
||||||
|
|
||||||
### v2.1.0-alpha (2026-01-10)
|
### v2.1.0-alpha (2026-01-10)
|
||||||
|
|
||||||
- Complete schematic wiring system
|
- Complete schematic wiring system
|
||||||
- Dynamic symbol loading (~10,000 symbols)
|
- Dynamic symbol loading (~10,000 symbols)
|
||||||
- JLCPCB parts integration
|
- JLCPCB parts integration
|
||||||
@@ -125,7 +137,7 @@ The server automatically selects the best backend:
|
|||||||
## Community Contributors
|
## Community Contributors
|
||||||
|
|
||||||
| Contributor | Key Contributions |
|
| Contributor | Key Contributions |
|
||||||
|------------|-------------------|
|
| ------------- | ------------------------------------------------------------------------------ |
|
||||||
| Kletternaut | Routing tools, footprint/symbol creators, passthrough workflow, template fixes |
|
| Kletternaut | Routing tools, footprint/symbol creators, passthrough workflow, template fixes |
|
||||||
| Mehanik | Schematic inspection/editing tools, component field positions |
|
| Mehanik | Schematic inspection/editing tools, component field positions |
|
||||||
| jflaflamme | Freerouting autorouter integration with Docker/Podman |
|
| jflaflamme | Freerouting autorouter integration with Docker/Podman |
|
||||||
@@ -141,18 +153,21 @@ The server automatically selects the best backend:
|
|||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
**For Users:**
|
**For Users:**
|
||||||
|
|
||||||
1. Check [README.md](../README.md) for installation
|
1. Check [README.md](../README.md) for installation
|
||||||
2. Review [KNOWN_ISSUES.md](KNOWN_ISSUES.md) for common problems
|
2. Review [KNOWN_ISSUES.md](KNOWN_ISSUES.md) for common problems
|
||||||
3. Check logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
3. Check logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
||||||
|
|
||||||
**For Contributors:**
|
**For Contributors:**
|
||||||
|
|
||||||
1. Read [CONTRIBUTING.md](../CONTRIBUTING.md) for development setup
|
1. Read [CONTRIBUTING.md](../CONTRIBUTING.md) for development setup
|
||||||
2. Check [ARCHITECTURE.md](ARCHITECTURE.md) for system design
|
2. Check [ARCHITECTURE.md](ARCHITECTURE.md) for system design
|
||||||
3. Review the [Documentation Index](INDEX.md) for all available docs
|
3. Review the [Documentation Index](INDEX.md) for all available docs
|
||||||
|
|
||||||
**Issues:**
|
**Issues:**
|
||||||
|
|
||||||
- Open an issue on GitHub with OS, KiCAD version, and error details
|
- Open an issue on GitHub with OS, KiCAD version, and error details
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last Updated: 2026-03-21*
|
_Last Updated: 2026-03-21_
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Imports an SVG file as filled graphic polygons onto a PCB layer. Curves are line
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Default | Description |
|
| Parameter | Type | Required | Default | Description |
|
||||||
|-----------|------|----------|---------|-------------|
|
| ------------- | ------- | -------- | ------- | ----------------------------------------------------------------------- |
|
||||||
| `pcbPath` | string | Yes | -- | Path to the .kicad_pcb file |
|
| `pcbPath` | string | Yes | -- | Path to the .kicad_pcb file |
|
||||||
| `svgPath` | string | Yes | -- | Path to the SVG logo file |
|
| `svgPath` | string | Yes | -- | Path to the SVG logo file |
|
||||||
| `x` | number | Yes | -- | X position of the logo top-left corner in mm |
|
| `x` | number | Yes | -- | X position of the logo top-left corner in mm |
|
||||||
@@ -26,6 +26,7 @@ Imports an SVG file as filled graphic polygons onto a PCB layer. Curves are line
|
|||||||
| `filled` | boolean | No | true | Fill polygons with solid color |
|
| `filled` | boolean | No | true | Fill polygons with solid color |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
- Polygon count
|
- Polygon count
|
||||||
- Final dimensions (width x height in mm)
|
- Final dimensions (width x height in mm)
|
||||||
- Layer used
|
- Layer used
|
||||||
@@ -35,18 +36,21 @@ Imports an SVG file as filled graphic polygons onto a PCB layer. Curves are line
|
|||||||
## SVG Requirements
|
## SVG Requirements
|
||||||
|
|
||||||
### Supported Features
|
### Supported Features
|
||||||
|
|
||||||
- Path elements with M, L, H, V, C, S, Q, T, A, Z commands
|
- Path elements with M, L, H, V, C, S, Q, T, A, Z commands
|
||||||
- Filled shapes (polygons, rectangles, circles, ellipses)
|
- Filled shapes (polygons, rectangles, circles, ellipses)
|
||||||
- Nested groups and transforms
|
- Nested groups and transforms
|
||||||
- Cubic and quadratic Bezier curves (linearized automatically)
|
- Cubic and quadratic Bezier curves (linearized automatically)
|
||||||
|
|
||||||
### Recommendations
|
### Recommendations
|
||||||
|
|
||||||
- Use simple, solid shapes -- avoid complex gradients or filters
|
- Use simple, solid shapes -- avoid complex gradients or filters
|
||||||
- Convert text to paths/outlines before importing
|
- Convert text to paths/outlines before importing
|
||||||
- Ensure shapes are filled (not just stroked) for best results
|
- Ensure shapes are filled (not just stroked) for best results
|
||||||
- Keep the SVG clean -- remove unnecessary metadata and layers
|
- Keep the SVG clean -- remove unnecessary metadata and layers
|
||||||
|
|
||||||
### What Will Not Work
|
### What Will Not Work
|
||||||
|
|
||||||
- Raster images embedded in SVG
|
- Raster images embedded in SVG
|
||||||
- CSS-based styling (inline style attributes are preferred)
|
- CSS-based styling (inline style attributes are preferred)
|
||||||
- Complex SVG filters or effects
|
- Complex SVG filters or effects
|
||||||
@@ -59,11 +63,13 @@ Imports an SVG file as filled graphic polygons onto a PCB layer. Curves are line
|
|||||||
### 1. Prepare Your SVG
|
### 1. Prepare Your SVG
|
||||||
|
|
||||||
If starting from a raster image (PNG, JPG):
|
If starting from a raster image (PNG, JPG):
|
||||||
|
|
||||||
- Use a vector graphics editor (Inkscape, Illustrator, Figma) to trace the image
|
- Use a vector graphics editor (Inkscape, Illustrator, Figma) to trace the image
|
||||||
- In Inkscape: Path > Trace Bitmap to convert
|
- In Inkscape: Path > Trace Bitmap to convert
|
||||||
- Export as plain SVG
|
- Export as plain SVG
|
||||||
|
|
||||||
If starting from a vector logo:
|
If starting from a vector logo:
|
||||||
|
|
||||||
- Open in a vector editor
|
- Open in a vector editor
|
||||||
- Convert all text to paths (Object to Path / Create Outlines)
|
- Convert all text to paths (Object to Path / Create Outlines)
|
||||||
- Remove unnecessary layers and hidden elements
|
- Remove unnecessary layers and hidden elements
|
||||||
@@ -88,7 +94,7 @@ Re-run `import_svg_logo` with different position, width, or layer parameters.
|
|||||||
## Layer Options
|
## Layer Options
|
||||||
|
|
||||||
| Layer | Use Case |
|
| Layer | Use Case |
|
||||||
|-------|----------|
|
| --------- | ----------------------------------------------------- |
|
||||||
| `F.SilkS` | Front silkscreen (most common for logos) |
|
| `F.SilkS` | Front silkscreen (most common for logos) |
|
||||||
| `B.SilkS` | Back silkscreen |
|
| `B.SilkS` | Back silkscreen |
|
||||||
| `F.Cu` | Front copper (logo as exposed copper) |
|
| `F.Cu` | Front copper (logo as exposed copper) |
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Project Management (5 tools)
|
## Project Management (5 tools)
|
||||||
|
|
||||||
*Source: `src/tools/project.ts`*
|
_Source: `src/tools/project.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ------------------ | ---------------------------------------------------------------- | ------ |
|
||||||
| `create_project` | Create a new KiCAD project (.kicad_pro, .kicad_pcb, .kicad_sch) | Direct |
|
| `create_project` | Create a new KiCAD project (.kicad_pro, .kicad_pcb, .kicad_sch) | Direct |
|
||||||
| `open_project` | Open an existing KiCAD project | Direct |
|
| `open_project` | Open an existing KiCAD project | Direct |
|
||||||
| `save_project` | Save the current project | Direct |
|
| `save_project` | Save the current project | Direct |
|
||||||
@@ -30,10 +30,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Board Management (12 tools)
|
## Board Management (12 tools)
|
||||||
|
|
||||||
*Source: `src/tools/board.ts`*
|
_Source: `src/tools/board.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ------------------- | ----------------------------------------------------------------- | -------------- |
|
||||||
| `set_board_size` | Set PCB dimensions (width, height, unit) | Direct |
|
| `set_board_size` | Set PCB dimensions (width, height, unit) | Direct |
|
||||||
| `add_board_outline` | Add board outline (rectangle, circle, polygon, rounded_rectangle) | Direct |
|
| `add_board_outline` | Add board outline (rectangle, circle, polygon, rounded_rectangle) | Direct |
|
||||||
| `get_board_info` | Get board metadata and properties | Direct |
|
| `get_board_info` | Get board metadata and properties | Direct |
|
||||||
@@ -51,10 +51,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Component Management (16 tools)
|
## Component Management (16 tools)
|
||||||
|
|
||||||
*Source: `src/tools/component.ts`*
|
_Source: `src/tools/component.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| -------------------------- | ------------------------------------------------------------- | ------------------ |
|
||||||
| `place_component` | Place footprint on PCB (position, rotation, reference, value) | Direct |
|
| `place_component` | Place footprint on PCB (position, rotation, reference, value) | Direct |
|
||||||
| `move_component` | Move component to new position | Direct |
|
| `move_component` | Move component to new position | Direct |
|
||||||
| `rotate_component` | Rotate component (absolute angle) | Routed (component) |
|
| `rotate_component` | Rotate component (absolute angle) | Routed (component) |
|
||||||
@@ -76,10 +76,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Routing (13 tools)
|
## Routing (13 tools)
|
||||||
|
|
||||||
*Source: `src/tools/routing.ts`*
|
_Source: `src/tools/routing.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ------------------------- | ---------------------------------------------------- | ---------------- |
|
||||||
| `add_net` | Create a new net on the PCB | Direct |
|
| `add_net` | Create a new net on the PCB | Direct |
|
||||||
| `route_trace` | Route trace segment between XY points (single layer) | Direct |
|
| `route_trace` | Route trace segment between XY points (single layer) | Direct |
|
||||||
| `add_via` | Add via (through/blind/buried) | Routed (routing) |
|
| `add_via` | Add via (through/blind/buried) | Routed (routing) |
|
||||||
@@ -98,10 +98,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Design Rules and DRC (8 tools)
|
## Design Rules and DRC (8 tools)
|
||||||
|
|
||||||
*Source: `src/tools/design-rules.ts`*
|
_Source: `src/tools/design-rules.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ----------------------- | ----------------------------------------------------------- | ------------ |
|
||||||
| `set_design_rules` | Set global design rules (clearance, track width, via sizes) | Routed (drc) |
|
| `set_design_rules` | Set global design rules (clearance, track width, via sizes) | Routed (drc) |
|
||||||
| `get_design_rules` | Get current design rules | Routed (drc) |
|
| `get_design_rules` | Get current design rules | Routed (drc) |
|
||||||
| `run_drc` | Run design rule check | Routed (drc) |
|
| `run_drc` | Run design rule check | Routed (drc) |
|
||||||
@@ -115,10 +115,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Export (8 tools)
|
## Export (8 tools)
|
||||||
|
|
||||||
*Source: `src/tools/export.ts`*
|
_Source: `src/tools/export.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ---------------------- | ------------------------------------------------- | --------------- |
|
||||||
| `export_gerber` | Export Gerber files for fabrication | Routed (export) |
|
| `export_gerber` | Export Gerber files for fabrication | Routed (export) |
|
||||||
| `export_pdf` | Export PDF with layer selection and page size | Routed (export) |
|
| `export_pdf` | Export PDF with layer selection and page size | Routed (export) |
|
||||||
| `export_svg` | Export SVG vector graphics | Routed (export) |
|
| `export_svg` | Export SVG vector graphics | Routed (export) |
|
||||||
@@ -132,12 +132,12 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Schematic (27 tools)
|
## Schematic (27 tools)
|
||||||
|
|
||||||
*Source: `src/tools/schematic.ts`*
|
_Source: `src/tools/schematic.ts`_
|
||||||
|
|
||||||
### Component Operations
|
### Component Operations
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ---------------------------- | ------------------------------------------------------- | ------------------ |
|
||||||
| `add_schematic_component` | Add component to schematic (symbol from library) | Direct |
|
| `add_schematic_component` | Add component to schematic (symbol from library) | Direct |
|
||||||
| `delete_schematic_component` | Remove component from schematic | Additional |
|
| `delete_schematic_component` | Remove component from schematic | Additional |
|
||||||
| `edit_schematic_component` | Edit component properties (footprint, value, reference) | Additional |
|
| `edit_schematic_component` | Edit component properties (footprint, value, reference) | Additional |
|
||||||
@@ -150,7 +150,7 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
### Wiring and Connections
|
### Wiring and Connections
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ----------------------------- | ------------------------------------------------ | ------------------ |
|
||||||
| `add_wire` | Add wire connection between two points | Routed (schematic) |
|
| `add_wire` | Add wire connection between two points | Routed (schematic) |
|
||||||
| `delete_schematic_wire` | Delete wire segment | Routed (schematic) |
|
| `delete_schematic_wire` | Delete wire segment | Routed (schematic) |
|
||||||
| `add_schematic_connection` | Connect two component pins with wire | Routed (schematic) |
|
| `add_schematic_connection` | Connect two component pins with wire | Routed (schematic) |
|
||||||
@@ -163,7 +163,7 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
### Net Analysis
|
### Net Analysis
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ----------------------- | ----------------------------- | ------------------ |
|
||||||
| `get_net_connections` | Get all connections for a net | Routed (schematic) |
|
| `get_net_connections` | Get all connections for a net | Routed (schematic) |
|
||||||
| `list_schematic_nets` | List all nets in schematic | Routed (schematic) |
|
| `list_schematic_nets` | List all nets in schematic | Routed (schematic) |
|
||||||
| `list_schematic_wires` | List all wires in schematic | Routed (schematic) |
|
| `list_schematic_wires` | List all wires in schematic | Routed (schematic) |
|
||||||
@@ -172,7 +172,7 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
### Schematic Creation and Export
|
### Schematic Creation and Export
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ---------------------- | -------------------------------- | ------------------ |
|
||||||
| `create_schematic` | Create a new schematic file | Routed (schematic) |
|
| `create_schematic` | Create a new schematic file | Routed (schematic) |
|
||||||
| `get_schematic_view` | Get schematic as image (PNG/SVG) | Routed (schematic) |
|
| `get_schematic_view` | Get schematic as image (PNG/SVG) | Routed (schematic) |
|
||||||
| `export_schematic_svg` | Export schematic to SVG | Routed (schematic) |
|
| `export_schematic_svg` | Export schematic to SVG | Routed (schematic) |
|
||||||
@@ -181,7 +181,7 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
### Validation and Synchronization
|
### Validation and Synchronization
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ------------------------- | ----------------------------------------------------- | ------------------ |
|
||||||
| `run_erc` | Run electrical rule check | Additional |
|
| `run_erc` | Run electrical rule check | Additional |
|
||||||
| `generate_netlist` | Generate netlist from schematic | Routed (schematic) |
|
| `generate_netlist` | Generate netlist from schematic | Routed (schematic) |
|
||||||
| `sync_schematic_to_board` | Sync schematic components/nets to PCB (F8 equivalent) | Direct |
|
| `sync_schematic_to_board` | Sync schematic components/nets to PCB (F8 equivalent) | Direct |
|
||||||
@@ -190,10 +190,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Footprint Libraries (4 tools)
|
## Footprint Libraries (4 tools)
|
||||||
|
|
||||||
*Source: `src/tools/library.ts`*
|
_Source: `src/tools/library.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ------------------------- | ------------------------------------- | ---------------- |
|
||||||
| `list_libraries` | List all footprint libraries | Routed (library) |
|
| `list_libraries` | List all footprint libraries | Routed (library) |
|
||||||
| `search_footprints` | Search footprints across libraries | Routed (library) |
|
| `search_footprints` | Search footprints across libraries | Routed (library) |
|
||||||
| `list_library_footprints` | List footprints in a specific library | Routed (library) |
|
| `list_library_footprints` | List footprints in a specific library | Routed (library) |
|
||||||
@@ -203,10 +203,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Symbol Libraries (4 tools)
|
## Symbol Libraries (4 tools)
|
||||||
|
|
||||||
*Source: `src/tools/library-symbol.ts`*
|
_Source: `src/tools/library-symbol.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ----------------------- | ----------------------------------------------- | ---------- |
|
||||||
| `list_symbol_libraries` | List all symbol libraries from sym-lib-table | Additional |
|
| `list_symbol_libraries` | List all symbol libraries from sym-lib-table | Additional |
|
||||||
| `search_symbols` | Search symbols by name, LCSC ID, or description | Additional |
|
| `search_symbols` | Search symbols by name, LCSC ID, or description | Additional |
|
||||||
| `list_library_symbols` | List symbols in a specific library | Additional |
|
| `list_library_symbols` | List symbols in a specific library | Additional |
|
||||||
@@ -216,10 +216,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Footprint Creator (4 tools)
|
## Footprint Creator (4 tools)
|
||||||
|
|
||||||
*Source: `src/tools/footprint.ts`*
|
_Source: `src/tools/footprint.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ---------------------------- | ------------------------------------------------------------------------ | ---------- |
|
||||||
| `create_footprint` | Create custom .kicad_mod footprint (SMD/THT pads, courtyard, silkscreen) | Additional |
|
| `create_footprint` | Create custom .kicad_mod footprint (SMD/THT pads, courtyard, silkscreen) | Additional |
|
||||||
| `edit_footprint_pad` | Edit pad in existing footprint (size, position, drill, shape) | Additional |
|
| `edit_footprint_pad` | Edit pad in existing footprint (size, position, drill, shape) | Additional |
|
||||||
| `register_footprint_library` | Register .pretty library in fp-lib-table | Additional |
|
| `register_footprint_library` | Register .pretty library in fp-lib-table | Additional |
|
||||||
@@ -229,10 +229,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Symbol Creator (4 tools)
|
## Symbol Creator (4 tools)
|
||||||
|
|
||||||
*Source: `src/tools/symbol-creator.ts`*
|
_Source: `src/tools/symbol-creator.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ------------------------- | ------------------------------------------------------------- | ---------- |
|
||||||
| `create_symbol` | Create custom .kicad_sym symbol (pins, rectangles, polylines) | Additional |
|
| `create_symbol` | Create custom .kicad_sym symbol (pins, rectangles, polylines) | Additional |
|
||||||
| `delete_symbol` | Remove symbol from library | Additional |
|
| `delete_symbol` | Remove symbol from library | Additional |
|
||||||
| `list_symbols_in_library` | List all symbols in a .kicad_sym file | Additional |
|
| `list_symbols_in_library` | List all symbols in a .kicad_sym file | Additional |
|
||||||
@@ -242,10 +242,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Datasheet Tools (2 tools)
|
## Datasheet Tools (2 tools)
|
||||||
|
|
||||||
*Source: `src/tools/datasheet.ts`*
|
_Source: `src/tools/datasheet.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ------------------- | --------------------------------------------------- | ---------- |
|
||||||
| `enrich_datasheets` | Fill missing datasheet URLs using LCSC part numbers | Additional |
|
| `enrich_datasheets` | Fill missing datasheet URLs using LCSC part numbers | Additional |
|
||||||
| `get_datasheet_url` | Get LCSC datasheet URL for a component | Additional |
|
| `get_datasheet_url` | Get LCSC datasheet URL for a component | Additional |
|
||||||
|
|
||||||
@@ -253,10 +253,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## JLCPCB Integration (5 tools)
|
## JLCPCB Integration (5 tools)
|
||||||
|
|
||||||
*Source: `src/tools/jlcpcb-api.ts`*
|
_Source: `src/tools/jlcpcb-api.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ----------------------------- | ------------------------------------------------------- | ---------- |
|
||||||
| `download_jlcpcb_database` | Download 2.5M+ parts catalog to local SQLite database | Additional |
|
| `download_jlcpcb_database` | Download 2.5M+ parts catalog to local SQLite database | Additional |
|
||||||
| `search_jlcpcb_parts` | Search parts by specs (category, package, library type) | Additional |
|
| `search_jlcpcb_parts` | Search parts by specs (category, package, library type) | Additional |
|
||||||
| `get_jlcpcb_part` | Get detailed part info with pricing | Additional |
|
| `get_jlcpcb_part` | Get detailed part info with pricing | Additional |
|
||||||
@@ -267,10 +267,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Freerouting Autorouter (4 tools)
|
## Freerouting Autorouter (4 tools)
|
||||||
|
|
||||||
*Source: `src/tools/freerouting.ts`*
|
_Source: `src/tools/freerouting.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ------------------- | ---------------------------------------------------------- | ------------------ |
|
||||||
| `autoroute` | Run Freerouting autorouter (export DSN, route, import SES) | Routed (autoroute) |
|
| `autoroute` | Run Freerouting autorouter (export DSN, route, import SES) | Routed (autoroute) |
|
||||||
| `export_dsn` | Export Specctra DSN file for manual routing | Routed (autoroute) |
|
| `export_dsn` | Export Specctra DSN file for manual routing | Routed (autoroute) |
|
||||||
| `import_ses` | Import routed SES file back into PCB | Routed (autoroute) |
|
| `import_ses` | Import routed SES file back into PCB | Routed (autoroute) |
|
||||||
@@ -280,10 +280,10 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## UI Management (2 tools)
|
## UI Management (2 tools)
|
||||||
|
|
||||||
*Source: `src/tools/ui.ts`*
|
_Source: `src/tools/ui.ts`_
|
||||||
|
|
||||||
| Tool | Description | Access |
|
| Tool | Description | Access |
|
||||||
|------|-------------|--------|
|
| ----------------- | ----------------------------------------- | -------------- |
|
||||||
| `check_kicad_ui` | Check if KiCAD UI is running | Direct |
|
| `check_kicad_ui` | Check if KiCAD UI is running | Direct |
|
||||||
| `launch_kicad_ui` | Launch KiCAD UI (optionally with project) | Routed (board) |
|
| `launch_kicad_ui` | Launch KiCAD UI (optionally with project) | Routed (board) |
|
||||||
|
|
||||||
@@ -291,12 +291,12 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into
|
|||||||
|
|
||||||
## Router Tools (4 tools)
|
## Router Tools (4 tools)
|
||||||
|
|
||||||
*Source: `src/tools/router.ts`*
|
_Source: `src/tools/router.ts`_
|
||||||
|
|
||||||
These meta-tools provide discovery and execution of routed tools:
|
These meta-tools provide discovery and execution of routed tools:
|
||||||
|
|
||||||
| Tool | Description |
|
| Tool | Description |
|
||||||
|------|-------------|
|
| ---------------------- | ------------------------------------ |
|
||||||
| `list_tool_categories` | Browse all available tool categories |
|
| `list_tool_categories` | Browse all available tool categories |
|
||||||
| `get_category_tools` | View tools in a specific category |
|
| `get_category_tools` | View tools in a specific category |
|
||||||
| `search_tools` | Find tools by keyword |
|
| `search_tools` | Find tools by keyword |
|
||||||
@@ -307,7 +307,7 @@ These meta-tools provide discovery and execution of routed tools:
|
|||||||
## Summary by Access Type
|
## Summary by Access Type
|
||||||
|
|
||||||
| Access Type | Count | Description |
|
| Access Type | Count | Description |
|
||||||
|-------------|-------|-------------|
|
| ----------- | ------- | --------------------------------------------------- |
|
||||||
| Direct | 18 | Always visible, no router needed |
|
| Direct | 18 | Always visible, no router needed |
|
||||||
| Routed | 65 | Discovered via router, invoked via `execute_tool` |
|
| Routed | 65 | Discovered via router, invoked via `execute_tool` |
|
||||||
| Router | 4 | Meta-tools for discovering and running routed tools |
|
| Router | 4 | Meta-tools for discovering and running routed tools |
|
||||||
@@ -317,7 +317,7 @@ These meta-tools provide discovery and execution of routed tools:
|
|||||||
## Summary by Category
|
## Summary by Category
|
||||||
|
|
||||||
| Category | Tool Count |
|
| Category | Tool Count |
|
||||||
|----------|------------|
|
| -------------------- | ---------- |
|
||||||
| Project Management | 5 |
|
| Project Management | 5 |
|
||||||
| Board Management | 12 |
|
| Board Management | 12 |
|
||||||
| Component Management | 16 |
|
| Component Management | 16 |
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ Automatically detect and launch KiCAD UI when needed, providing seamless visual
|
|||||||
## 🎯 Overview
|
## 🎯 Overview
|
||||||
|
|
||||||
The KiCAD MCP server can now:
|
The KiCAD MCP server can now:
|
||||||
|
|
||||||
- ✅ Detect if KiCAD UI is running
|
- ✅ Detect if KiCAD UI is running
|
||||||
- ✅ Launch KiCAD automatically when needed
|
- ✅ Launch KiCAD automatically when needed
|
||||||
- ✅ Open projects directly in the UI
|
- ✅ Open projects directly in the UI
|
||||||
@@ -49,6 +50,7 @@ Check if KiCAD is currently running.
|
|||||||
**Parameters:** None
|
**Parameters:** None
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
{
|
{
|
||||||
"command": "check_kicad_ui",
|
"command": "check_kicad_ui",
|
||||||
@@ -57,6 +59,7 @@ Check if KiCAD is currently running.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Response:**
|
**Response:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -77,10 +80,12 @@ Check if KiCAD is currently running.
|
|||||||
Launch KiCAD UI, optionally with a project file.
|
Launch KiCAD UI, optionally with a project file.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `projectPath` (optional): Path to `.kicad_pcb` file to open
|
- `projectPath` (optional): Path to `.kicad_pcb` file to open
|
||||||
- `autoLaunch` (optional): Whether to launch if not running (default: true)
|
- `autoLaunch` (optional): Whether to launch if not running (default: true)
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
{
|
{
|
||||||
"command": "launch_kicad_ui",
|
"command": "launch_kicad_ui",
|
||||||
@@ -91,6 +96,7 @@ Launch KiCAD UI, optionally with a project file.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Response:**
|
**Response:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
@@ -158,7 +164,7 @@ Claude:
|
|||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
| ------------------- | ----------- | ------------------------------ |
|
||||||
| `KICAD_AUTO_LAUNCH` | `false` | Auto-launch KiCAD when needed |
|
| `KICAD_AUTO_LAUNCH` | `false` | Auto-launch KiCAD when needed |
|
||||||
| `KICAD_EXECUTABLE` | auto-detect | Override KiCAD executable path |
|
| `KICAD_EXECUTABLE` | auto-detect | Override KiCAD executable path |
|
||||||
|
|
||||||
@@ -182,16 +188,19 @@ If KiCAD is installed in a non-standard location:
|
|||||||
### Process Detection
|
### Process Detection
|
||||||
|
|
||||||
**Linux:**
|
**Linux:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pgrep -f "pcbnew|kicad"
|
pgrep -f "pcbnew|kicad"
|
||||||
```
|
```
|
||||||
|
|
||||||
**macOS:**
|
**macOS:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pgrep -f "KiCad|pcbnew"
|
pgrep -f "KiCad|pcbnew"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Windows:**
|
**Windows:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
tasklist /FI "IMAGENAME eq pcbnew.exe"
|
tasklist /FI "IMAGENAME eq pcbnew.exe"
|
||||||
```
|
```
|
||||||
@@ -201,15 +210,18 @@ tasklist /FI "IMAGENAME eq pcbnew.exe"
|
|||||||
The system searches for KiCAD in:
|
The system searches for KiCAD in:
|
||||||
|
|
||||||
**Linux:**
|
**Linux:**
|
||||||
|
|
||||||
- `/usr/bin/pcbnew`
|
- `/usr/bin/pcbnew`
|
||||||
- `/usr/local/bin/pcbnew`
|
- `/usr/local/bin/pcbnew`
|
||||||
- `/usr/bin/kicad`
|
- `/usr/bin/kicad`
|
||||||
|
|
||||||
**macOS:**
|
**macOS:**
|
||||||
|
|
||||||
- `/Applications/KiCad/KiCad.app/Contents/MacOS/kicad`
|
- `/Applications/KiCad/KiCad.app/Contents/MacOS/kicad`
|
||||||
- `/Applications/KiCad/pcbnew.app/Contents/MacOS/pcbnew`
|
- `/Applications/KiCad/pcbnew.app/Contents/MacOS/pcbnew`
|
||||||
|
|
||||||
**Windows:**
|
**Windows:**
|
||||||
|
|
||||||
- `C:/Program Files/KiCad/9.0/bin/pcbnew.exe`
|
- `C:/Program Files/KiCad/9.0/bin/pcbnew.exe`
|
||||||
- `C:/Program Files/KiCad/8.0/bin/pcbnew.exe`
|
- `C:/Program Files/KiCad/8.0/bin/pcbnew.exe`
|
||||||
|
|
||||||
@@ -229,6 +241,7 @@ The system searches for KiCAD in:
|
|||||||
### 1. Beginner-Friendly Workflow
|
### 1. Beginner-Friendly Workflow
|
||||||
|
|
||||||
User doesn't need to know how to launch KiCAD manually:
|
User doesn't need to know how to launch KiCAD manually:
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Help me design a simple LED board"
|
User: "Help me design a simple LED board"
|
||||||
Claude: [Auto-launches KiCAD, creates project, designs board]
|
Claude: [Auto-launches KiCAD, creates project, designs board]
|
||||||
@@ -237,6 +250,7 @@ Claude: [Auto-launches KiCAD, creates project, designs board]
|
|||||||
### 2. Streamlined Iteration
|
### 2. Streamlined Iteration
|
||||||
|
|
||||||
For rapid prototyping with visual feedback:
|
For rapid prototyping with visual feedback:
|
||||||
|
|
||||||
```
|
```
|
||||||
1. Claude creates board → KiCAD opens
|
1. Claude creates board → KiCAD opens
|
||||||
2. User sees board, requests changes
|
2. User sees board, requests changes
|
||||||
@@ -247,6 +261,7 @@ For rapid prototyping with visual feedback:
|
|||||||
### 3. Batch Processing
|
### 3. Batch Processing
|
||||||
|
|
||||||
Process multiple designs without manual intervention:
|
Process multiple designs without manual intervention:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
for design in designs:
|
for design in designs:
|
||||||
create_project(design)
|
create_project(design)
|
||||||
@@ -263,6 +278,7 @@ for design in designs:
|
|||||||
### KiCAD Doesn't Launch
|
### KiCAD Doesn't Launch
|
||||||
|
|
||||||
**Check executable path:**
|
**Check executable path:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Linux/macOS
|
# Linux/macOS
|
||||||
which pcbnew
|
which pcbnew
|
||||||
@@ -272,6 +288,7 @@ where pcbnew.exe
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Override if needed:**
|
**Override if needed:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
@@ -283,6 +300,7 @@ where pcbnew.exe
|
|||||||
### Process Detection Fails
|
### Process Detection Fails
|
||||||
|
|
||||||
**Manual check:**
|
**Manual check:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Linux/macOS
|
# Linux/macOS
|
||||||
ps aux | grep kicad
|
ps aux | grep kicad
|
||||||
@@ -292,6 +310,7 @@ tasklist | findstr kicad
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Verify permissions:**
|
**Verify permissions:**
|
||||||
|
|
||||||
- Ensure user can execute `pgrep` (Linux/macOS)
|
- Ensure user can execute `pgrep` (Linux/macOS)
|
||||||
- Ensure user can execute `tasklist` (Windows)
|
- Ensure user can execute `tasklist` (Windows)
|
||||||
|
|
||||||
@@ -309,17 +328,20 @@ tasklist | findstr kicad
|
|||||||
### Files Modified/Created
|
### Files Modified/Created
|
||||||
|
|
||||||
**New Files:**
|
**New Files:**
|
||||||
|
|
||||||
- `python/utils/kicad_process.py` - Process management utilities
|
- `python/utils/kicad_process.py` - Process management utilities
|
||||||
- `src/tools/ui.ts` - MCP tool definitions
|
- `src/tools/ui.ts` - MCP tool definitions
|
||||||
- `docs/UI_AUTO_LAUNCH.md` - This documentation
|
- `docs/UI_AUTO_LAUNCH.md` - This documentation
|
||||||
|
|
||||||
**Modified Files:**
|
**Modified Files:**
|
||||||
|
|
||||||
- `python/kicad_interface.py` - Added UI command handlers
|
- `python/kicad_interface.py` - Added UI command handlers
|
||||||
- `src/server.ts` - Registered UI tools
|
- `src/server.ts` - Registered UI tools
|
||||||
|
|
||||||
### API Reference
|
### API Reference
|
||||||
|
|
||||||
**Python:**
|
**Python:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from utils.kicad_process import KiCADProcessManager, check_and_launch_kicad
|
from utils.kicad_process import KiCADProcessManager, check_and_launch_kicad
|
||||||
|
|
||||||
@@ -341,6 +363,7 @@ result = check_and_launch_kicad(
|
|||||||
```
|
```
|
||||||
|
|
||||||
**MCP Tools:**
|
**MCP Tools:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Check status
|
// Check status
|
||||||
await callKicadScript("check_kicad_ui", {});
|
await callKicadScript("check_kicad_ui", {});
|
||||||
@@ -348,7 +371,7 @@ await callKicadScript("check_kicad_ui", {});
|
|||||||
// Launch
|
// Launch
|
||||||
await callKicadScript("launch_kicad_ui", {
|
await callKicadScript("launch_kicad_ui", {
|
||||||
projectPath: "/path/to/project.kicad_pcb",
|
projectPath: "/path/to/project.kicad_pcb",
|
||||||
autoLaunch: true
|
autoLaunch: true,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -367,6 +390,7 @@ await callKicadScript("launch_kicad_ui", {
|
|||||||
### IPC Mode (Coming Weeks 2-3)
|
### IPC Mode (Coming Weeks 2-3)
|
||||||
|
|
||||||
When IPC backend is fully implemented:
|
When IPC backend is fully implemented:
|
||||||
|
|
||||||
```
|
```
|
||||||
KiCAD runs in background → MCP connects via IPC → Real-time updates
|
KiCAD runs in background → MCP connects via IPC → Real-time updates
|
||||||
No file reloading needed! Changes appear instantly.
|
No file reloading needed! Changes appear instantly.
|
||||||
@@ -377,6 +401,7 @@ No file reloading needed! Changes appear instantly.
|
|||||||
## 📝 Summary
|
## 📝 Summary
|
||||||
|
|
||||||
**Before this feature:**
|
**Before this feature:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User manually launches KiCAD
|
User manually launches KiCAD
|
||||||
User manually opens project
|
User manually opens project
|
||||||
@@ -385,6 +410,7 @@ User manually reloads
|
|||||||
```
|
```
|
||||||
|
|
||||||
**After this feature:**
|
**After this feature:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Design a board"
|
User: "Design a board"
|
||||||
→ KiCAD auto-launches with project
|
→ KiCAD auto-launches with project
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ This document explains how to see changes made by the MCP server in the KiCAD UI
|
|||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
1. **Open your project in KiCAD PCB Editor**
|
1. **Open your project in KiCAD PCB Editor**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pcbnew /tmp/kicad_test_project/New_Project.kicad_pcb
|
pcbnew /tmp/kicad_test_project/New_Project.kicad_pcb
|
||||||
```
|
```
|
||||||
@@ -77,12 +78,14 @@ Claude MCP → IPC Socket → Running KiCAD → Instant UI Update
|
|||||||
- Restart KiCAD
|
- Restart KiCAD
|
||||||
|
|
||||||
2. **Install kicad-python** (Already installed ✓)
|
2. **Install kicad-python** (Already installed ✓)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install kicad-python
|
pip install kicad-python
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Configure MCP Server**
|
3. **Configure MCP Server**
|
||||||
Add to your MCP config:
|
Add to your MCP config:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
@@ -98,7 +101,7 @@ Claude MCP → IPC Socket → Running KiCAD → Instant UI Update
|
|||||||
### Current IPC Status
|
### Current IPC Status
|
||||||
|
|
||||||
| Feature | Status |
|
| Feature | Status |
|
||||||
|---------|--------|
|
| -------------------- | ----------- |
|
||||||
| Connection to KiCAD | ✅ Working |
|
| Connection to KiCAD | ✅ Working |
|
||||||
| Version checking | ✅ Working |
|
| Version checking | ✅ Working |
|
||||||
| Project operations | ⏳ Week 2-3 |
|
| Project operations | ⏳ Week 2-3 |
|
||||||
@@ -124,6 +127,7 @@ This will print a message each time the MCP server saves changes.
|
|||||||
## 💡 Tips for Best Experience
|
## 💡 Tips for Best Experience
|
||||||
|
|
||||||
### 1. Side-by-Side Windows
|
### 1. Side-by-Side Windows
|
||||||
|
|
||||||
```
|
```
|
||||||
┌──────────────────┬──────────────────┐
|
┌──────────────────┬──────────────────┐
|
||||||
│ Claude Code │ KiCAD PCB │
|
│ Claude Code │ KiCAD PCB │
|
||||||
@@ -134,16 +138,20 @@ This will print a message each time the MCP server saves changes.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 2. Quick Reload Workflow
|
### 2. Quick Reload Workflow
|
||||||
|
|
||||||
- Keep KiCAD focused in one window
|
- Keep KiCAD focused in one window
|
||||||
- Make changes via Claude in another
|
- Make changes via Claude in another
|
||||||
- Press Alt+Tab → Click "Reload" → See changes
|
- Press Alt+Tab → Click "Reload" → See changes
|
||||||
- Repeat
|
- Repeat
|
||||||
|
|
||||||
### 3. Save Frequently
|
### 3. Save Frequently
|
||||||
|
|
||||||
The MCP server auto-saves after each operation, so changes are immediately available for reload.
|
The MCP server auto-saves after each operation, so changes are immediately available for reload.
|
||||||
|
|
||||||
### 4. Verify Before Complex Operations
|
### 4. Verify Before Complex Operations
|
||||||
|
|
||||||
For complex changes (multiple components, routing, etc.):
|
For complex changes (multiple components, routing, etc.):
|
||||||
|
|
||||||
1. Make the change
|
1. Make the change
|
||||||
2. Reload in KiCAD
|
2. Reload in KiCAD
|
||||||
3. Verify it looks correct
|
3. Verify it looks correct
|
||||||
@@ -167,6 +175,7 @@ For complex changes (multiple components, routing, etc.):
|
|||||||
|
|
||||||
**Cause:** KiCAD has the file open exclusively
|
**Cause:** KiCAD has the file open exclusively
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
- KiCAD should allow external modifications
|
- KiCAD should allow external modifications
|
||||||
- If not, close the file in KiCAD, let MCP make changes, then reopen
|
- If not, close the file in KiCAD, let MCP make changes, then reopen
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ This guide helps diagnose and fix common issues when setting up KiCAD MCP Server
|
|||||||
```
|
```
|
||||||
|
|
||||||
This script will:
|
This script will:
|
||||||
|
|
||||||
- Detect your KiCAD installation
|
- Detect your KiCAD installation
|
||||||
- Verify all prerequisites
|
- Verify all prerequisites
|
||||||
- Install dependencies
|
- Install dependencies
|
||||||
@@ -34,12 +35,15 @@ If the automated setup fails, continue with the manual troubleshooting below.
|
|||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. **Check the log file** (this has the actual error):
|
1. **Check the log file** (this has the actual error):
|
||||||
|
|
||||||
```
|
```
|
||||||
%USERPROFILE%\.kicad-mcp\logs\kicad_interface.log
|
%USERPROFILE%\.kicad-mcp\logs\kicad_interface.log
|
||||||
```
|
```
|
||||||
|
|
||||||
Open in Notepad and look at the last 50-100 lines.
|
Open in Notepad and look at the last 50-100 lines.
|
||||||
|
|
||||||
2. **Test pcbnew import manually:**
|
2. **Test pcbnew import manually:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
||||||
```
|
```
|
||||||
@@ -73,6 +77,7 @@ If the automated setup fails, continue with the manual troubleshooting below.
|
|||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. **Check if KiCAD is installed:**
|
1. **Check if KiCAD is installed:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
Test-Path "C:\Program Files\KiCad\9.0"
|
Test-Path "C:\Program Files\KiCad\9.0"
|
||||||
```
|
```
|
||||||
@@ -99,6 +104,7 @@ If the automated setup fails, continue with the manual troubleshooting below.
|
|||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. **Check if Node.js is installed:**
|
1. **Check if Node.js is installed:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
node --version
|
node --version
|
||||||
npm --version
|
npm --version
|
||||||
@@ -124,6 +130,7 @@ If the automated setup fails, continue with the manual troubleshooting below.
|
|||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. **Clean and reinstall dependencies:**
|
1. **Clean and reinstall dependencies:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
Remove-Item node_modules -Recurse -Force
|
Remove-Item node_modules -Recurse -Force
|
||||||
Remove-Item package-lock.json -Force
|
Remove-Item package-lock.json -Force
|
||||||
@@ -132,6 +139,7 @@ If the automated setup fails, continue with the manual troubleshooting below.
|
|||||||
```
|
```
|
||||||
|
|
||||||
2. **Check Node.js version:**
|
2. **Check Node.js version:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
node --version # Should be v18.0.0 or higher
|
node --version # Should be v18.0.0 or higher
|
||||||
```
|
```
|
||||||
@@ -152,11 +160,13 @@ If the automated setup fails, continue with the manual troubleshooting below.
|
|||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. **Install with KiCAD's Python:**
|
1. **Install with KiCAD's Python:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
& "C:\Program Files\KiCad\9.0\bin\python.exe" -m pip install -r requirements.txt
|
& "C:\Program Files\KiCad\9.0\bin\python.exe" -m pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **If pip is not available:**
|
2. **If pip is not available:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Download get-pip.py
|
# Download get-pip.py
|
||||||
Invoke-WebRequest -Uri https://bootstrap.pypa.io/get-pip.py -OutFile get-pip.py
|
Invoke-WebRequest -Uri https://bootstrap.pypa.io/get-pip.py -OutFile get-pip.py
|
||||||
@@ -197,6 +207,7 @@ If the automated setup fails, continue with the manual troubleshooting below.
|
|||||||
**Symptom:** Config file paths not working
|
**Symptom:** Config file paths not working
|
||||||
|
|
||||||
**Common mistakes:**
|
**Common mistakes:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
// ❌ Wrong - single backslashes
|
// ❌ Wrong - single backslashes
|
||||||
"args": ["C:\Users\Name\KiCAD-MCP-Server\dist\index.js"]
|
"args": ["C:\Users\Name\KiCAD-MCP-Server\dist\index.js"]
|
||||||
@@ -224,6 +235,7 @@ If the automated setup fails, continue with the manual troubleshooting below.
|
|||||||
KiCAD MCP requires Python 3.10+. KiCAD 9.0 includes Python 3.11, which is perfect.
|
KiCAD MCP requires Python 3.10+. KiCAD 9.0 includes Python 3.11, which is perfect.
|
||||||
|
|
||||||
**Always use KiCAD's bundled Python:**
|
**Always use KiCAD's bundled Python:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
@@ -315,6 +327,7 @@ print('SUCCESS!')
|
|||||||
```
|
```
|
||||||
|
|
||||||
Expected output:
|
Expected output:
|
||||||
|
|
||||||
```
|
```
|
||||||
Python version: 3.11.x ...
|
Python version: 3.11.x ...
|
||||||
pcbnew version: 9.0.0
|
pcbnew version: 9.0.0
|
||||||
@@ -364,6 +377,7 @@ Should show successful initialization with no errors.
|
|||||||
### Enable Verbose Logging
|
### Enable Verbose Logging
|
||||||
|
|
||||||
Add to your MCP config:
|
Add to your MCP config:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
@@ -412,9 +426,11 @@ if ($process.HasExited) {
|
|||||||
If none of the above solutions work:
|
If none of the above solutions work:
|
||||||
|
|
||||||
1. **Run the diagnostic script:**
|
1. **Run the diagnostic script:**
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\setup-windows.ps1
|
.\setup-windows.ps1
|
||||||
```
|
```
|
||||||
|
|
||||||
Copy the entire output.
|
Copy the entire output.
|
||||||
|
|
||||||
2. **Collect log files:**
|
2. **Collect log files:**
|
||||||
@@ -437,12 +453,14 @@ If none of the above solutions work:
|
|||||||
1. **File paths are case-insensitive** but should match actual casing for best results
|
1. **File paths are case-insensitive** but should match actual casing for best results
|
||||||
|
|
||||||
2. **Long path support** may be needed for deeply nested projects:
|
2. **Long path support** may be needed for deeply nested projects:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Enable long paths (requires admin)
|
# Enable long paths (requires admin)
|
||||||
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
|
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Windows Defender** may slow down file operations. Add exclusion:
|
3. **Windows Defender** may slow down file operations. Add exclusion:
|
||||||
|
|
||||||
```
|
```
|
||||||
Settings → Windows Security → Virus & threat protection → Exclusions
|
Settings → Windows Security → Virus & threat protection → Exclusions
|
||||||
Add: C:\Users\YourName\KiCAD-MCP-Server
|
Add: C:\Users\YourName\KiCAD-MCP-Server
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Build and Test Session Summary
|
# Build and Test Session Summary
|
||||||
|
|
||||||
**Date:** October 25, 2025 (Evening)
|
**Date:** October 25, 2025 (Evening)
|
||||||
**Status:** ✅ **SUCCESS**
|
**Status:** ✅ **SUCCESS**
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ Complete the MCP server build and test it with various MCP clients (Claude Deskt
|
|||||||
**Problem:** Missing TypeScript source files preventing build
|
**Problem:** Missing TypeScript source files preventing build
|
||||||
|
|
||||||
**Files Created:**
|
**Files Created:**
|
||||||
|
|
||||||
- `src/tools/project.ts` (80 lines)
|
- `src/tools/project.ts` (80 lines)
|
||||||
- Registers MCP tools: `create_project`, `open_project`, `save_project`, `get_project_info`
|
- Registers MCP tools: `create_project`, `open_project`, `save_project`, `get_project_info`
|
||||||
|
|
||||||
@@ -40,6 +42,7 @@ Complete the MCP server build and test it with various MCP clients (Claude Deskt
|
|||||||
**Problem:** Both `component.ts` and `library.ts` registered a resource named "component_details"
|
**Problem:** Both `component.ts` and `library.ts` registered a resource named "component_details"
|
||||||
|
|
||||||
**Fix Applied:**
|
**Fix Applied:**
|
||||||
|
|
||||||
- Renamed library resource to `library_component_details`
|
- Renamed library resource to `library_component_details`
|
||||||
- Updated URI template from `kicad://component/{componentId}` to `kicad://library/component/{componentId}`
|
- Updated URI template from `kicad://component/{componentId}` to `kicad://library/component/{componentId}`
|
||||||
|
|
||||||
@@ -52,11 +55,13 @@ Complete the MCP server build and test it with various MCP clients (Claude Deskt
|
|||||||
### 3. **Successful Server Startup Test** 🚀
|
### 3. **Successful Server Startup Test** 🚀
|
||||||
|
|
||||||
**Test Command:**
|
**Test Command:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
timeout --signal=TERM 3 node dist/index.js
|
timeout --signal=TERM 3 node dist/index.js
|
||||||
```
|
```
|
||||||
|
|
||||||
**Server Output (All Green):**
|
**Server Output (All Green):**
|
||||||
|
|
||||||
```
|
```
|
||||||
[INFO] Using STDIO transport for local communication
|
[INFO] Using STDIO transport for local communication
|
||||||
[INFO] Registering KiCAD tools, resources, and prompts...
|
[INFO] Registering KiCAD tools, resources, and prompts...
|
||||||
@@ -101,6 +106,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
**File Created:** `docs/CLIENT_CONFIGURATION.md` (500+ lines)
|
**File Created:** `docs/CLIENT_CONFIGURATION.md` (500+ lines)
|
||||||
|
|
||||||
**Contents:**
|
**Contents:**
|
||||||
|
|
||||||
- Platform-specific configurations:
|
- Platform-specific configurations:
|
||||||
- Linux (Ubuntu/Debian, Arch)
|
- Linux (Ubuntu/Debian, Arch)
|
||||||
- macOS (with KiCAD.app paths)
|
- macOS (with KiCAD.app paths)
|
||||||
@@ -153,6 +159,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
**Addition:** New "Configuration for Other Clients" section after Quick Start
|
**Addition:** New "Configuration for Other Clients" section after Quick Start
|
||||||
|
|
||||||
**Changes:**
|
**Changes:**
|
||||||
|
|
||||||
- Added links to CLIENT_CONFIGURATION.md guide
|
- Added links to CLIENT_CONFIGURATION.md guide
|
||||||
- Listed all supported MCP clients (Claude Desktop, Cline, Claude Code)
|
- Listed all supported MCP clients (Claude Desktop, Cline, Claude Code)
|
||||||
- Highlighted that KiCAD MCP works with ANY MCP-compatible client
|
- Highlighted that KiCAD MCP works with ANY MCP-compatible client
|
||||||
@@ -167,6 +174,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
### Files Created/Modified (This Session)
|
### Files Created/Modified (This Session)
|
||||||
|
|
||||||
**New Files (5):**
|
**New Files (5):**
|
||||||
|
|
||||||
```
|
```
|
||||||
src/tools/project.ts # 80 lines
|
src/tools/project.ts # 80 lines
|
||||||
src/tools/routing.ts # 100 lines
|
src/tools/routing.ts # 100 lines
|
||||||
@@ -177,6 +185,7 @@ docs/BUILD_AND_TEST_SESSION.md # This file
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Modified Files (5):**
|
**Modified Files (5):**
|
||||||
|
|
||||||
```
|
```
|
||||||
src/resources/library.ts # Fixed duplicate registration
|
src/resources/library.ts # Fixed duplicate registration
|
||||||
config/linux-config.example.json # Updated format
|
config/linux-config.example.json # Updated format
|
||||||
@@ -194,11 +203,13 @@ README.md # Added config guide section
|
|||||||
### Generated Files
|
### Generated Files
|
||||||
|
|
||||||
**TypeScript Compilation:**
|
**TypeScript Compilation:**
|
||||||
|
|
||||||
- 72 JavaScript files in `dist/`
|
- 72 JavaScript files in `dist/`
|
||||||
- 24 declaration files (`.d.ts`)
|
- 24 declaration files (`.d.ts`)
|
||||||
- 24 source maps (`.js.map`)
|
- 24 source maps (`.js.map`)
|
||||||
|
|
||||||
**Directory Structure:**
|
**Directory Structure:**
|
||||||
|
|
||||||
```
|
```
|
||||||
dist/
|
dist/
|
||||||
├── index.js (entry point)
|
├── index.js (entry point)
|
||||||
@@ -215,12 +226,14 @@ dist/
|
|||||||
## Verification Tests
|
## Verification Tests
|
||||||
|
|
||||||
### ✅ Test 1: TypeScript Compilation
|
### ✅ Test 1: TypeScript Compilation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
# Result: SUCCESS (no errors)
|
# Result: SUCCESS (no errors)
|
||||||
```
|
```
|
||||||
|
|
||||||
### ✅ Test 2: Server Startup
|
### ✅ Test 2: Server Startup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
timeout --signal=TERM 3 node dist/index.js
|
timeout --signal=TERM 3 node dist/index.js
|
||||||
# Result: SUCCESS (exit code 0)
|
# Result: SUCCESS (exit code 0)
|
||||||
@@ -233,6 +246,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
```
|
```
|
||||||
|
|
||||||
### ✅ Test 3: Python Integration
|
### ✅ Test 3: Python Integration
|
||||||
|
|
||||||
- Python process successfully spawned: `/home/chris/MCP/KiCAD-MCP-Server/python/kicad_interface.py`
|
- Python process successfully spawned: `/home/chris/MCP/KiCAD-MCP-Server/python/kicad_interface.py`
|
||||||
- Using system Python: `python` (resolved to Python 3.12)
|
- Using system Python: `python` (resolved to Python 3.12)
|
||||||
- No Python import errors during startup
|
- No Python import errors during startup
|
||||||
@@ -244,6 +258,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
### MCP Server Capabilities
|
### MCP Server Capabilities
|
||||||
|
|
||||||
**Registered Tools (20+):**
|
**Registered Tools (20+):**
|
||||||
|
|
||||||
- Project: create_project, open_project, save_project, get_project_info
|
- Project: create_project, open_project, save_project, get_project_info
|
||||||
- Board: set_board_size, add_board_outline, get_board_properties
|
- Board: set_board_size, add_board_outline, get_board_properties
|
||||||
- Component: add_component, move_component, rotate_component, get_component_list
|
- Component: add_component, move_component, rotate_component, get_component_list
|
||||||
@@ -253,6 +268,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
- Export: export_gerber, export_pdf, export_svg, export_3d_model
|
- Export: export_gerber, export_pdf, export_svg, export_3d_model
|
||||||
|
|
||||||
**Registered Resources (15+):**
|
**Registered Resources (15+):**
|
||||||
|
|
||||||
- Project info and metadata
|
- Project info and metadata
|
||||||
- Board info, layers, extents
|
- Board info, layers, extents
|
||||||
- Board 2D/3D views (PNG, SVG)
|
- Board 2D/3D views (PNG, SVG)
|
||||||
@@ -260,6 +276,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
- Statistics and analytics
|
- Statistics and analytics
|
||||||
|
|
||||||
**Registered Prompts (10+):**
|
**Registered Prompts (10+):**
|
||||||
|
|
||||||
- Component selection guidance
|
- Component selection guidance
|
||||||
- Routing strategy suggestions
|
- Routing strategy suggestions
|
||||||
- Design best practices
|
- Design best practices
|
||||||
@@ -271,6 +288,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
### Immediate Testing (Ready Now)
|
### Immediate Testing (Ready Now)
|
||||||
|
|
||||||
1. **Test with Claude Code CLI:**
|
1. **Test with Claude Code CLI:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create config
|
# Create config
|
||||||
mkdir -p ~/.config/claude-code
|
mkdir -p ~/.config/claude-code
|
||||||
@@ -295,6 +313,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
### Integration Testing
|
### Integration Testing
|
||||||
|
|
||||||
**Test basic workflow:**
|
**Test basic workflow:**
|
||||||
|
|
||||||
```
|
```
|
||||||
1. Create new project
|
1. Create new project
|
||||||
2. Set board size
|
2. Set board size
|
||||||
@@ -304,6 +323,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Test resources:**
|
**Test resources:**
|
||||||
|
|
||||||
```
|
```
|
||||||
1. Request board info
|
1. Request board info
|
||||||
2. View 2D board rendering
|
2. View 2D board rendering
|
||||||
@@ -318,6 +338,7 @@ timeout --signal=TERM 3 node dist/index.js
|
|||||||
### 1. **Modular Tool Registration**
|
### 1. **Modular Tool Registration**
|
||||||
|
|
||||||
Each tool module follows consistent pattern:
|
Each tool module follows consistent pattern:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export function registerXxxTools(server: McpServer, callKicadScript: Function) {
|
export function registerXxxTools(server: McpServer, callKicadScript: Function) {
|
||||||
server.tool("tool_name", "Description", schema, async (args) => {
|
server.tool("tool_name", "Description", schema, async (args) => {
|
||||||
@@ -328,6 +349,7 @@ export function registerXxxTools(server: McpServer, callKicadScript: Function) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Benefits:**
|
**Benefits:**
|
||||||
|
|
||||||
- Easy to add new tools
|
- Easy to add new tools
|
||||||
- Consistent error handling
|
- Consistent error handling
|
||||||
- Clean separation of concerns
|
- Clean separation of concerns
|
||||||
@@ -335,13 +357,15 @@ export function registerXxxTools(server: McpServer, callKicadScript: Function) {
|
|||||||
### 2. **Resource Helper Utilities**
|
### 2. **Resource Helper Utilities**
|
||||||
|
|
||||||
Abstracted common response patterns:
|
Abstracted common response patterns:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
createJsonResponse(data, uri) // For JSON data
|
createJsonResponse(data, uri); // For JSON data
|
||||||
createBinaryResponse(data, mime) // For images/binary
|
createBinaryResponse(data, mime); // For images/binary
|
||||||
createErrorResponse(error, msg) // For errors
|
createErrorResponse(error, msg); // For errors
|
||||||
```
|
```
|
||||||
|
|
||||||
**Benefits:**
|
**Benefits:**
|
||||||
|
|
||||||
- DRY principle (Don't Repeat Yourself)
|
- DRY principle (Don't Repeat Yourself)
|
||||||
- Consistent response format
|
- Consistent response format
|
||||||
- Easy to modify response structure
|
- Easy to modify response structure
|
||||||
@@ -349,6 +373,7 @@ createErrorResponse(error, msg) // For errors
|
|||||||
### 3. **STDIO Transport**
|
### 3. **STDIO Transport**
|
||||||
|
|
||||||
Using standard STDIO (stdin/stdout) for MCP protocol:
|
Using standard STDIO (stdin/stdout) for MCP protocol:
|
||||||
|
|
||||||
- No network ports required
|
- No network ports required
|
||||||
- Maximum security (process isolation)
|
- Maximum security (process isolation)
|
||||||
- Works with all MCP clients
|
- Works with all MCP clients
|
||||||
@@ -357,6 +382,7 @@ Using standard STDIO (stdin/stdout) for MCP protocol:
|
|||||||
### 4. **Python Subprocess Integration**
|
### 4. **Python Subprocess Integration**
|
||||||
|
|
||||||
Server spawns Python process for KiCAD operations:
|
Server spawns Python process for KiCAD operations:
|
||||||
|
|
||||||
- Persistent Python process (faster than per-call spawn)
|
- Persistent Python process (faster than per-call spawn)
|
||||||
- JSON-RPC communication over stdin/stdout
|
- JSON-RPC communication over stdin/stdout
|
||||||
- Proper error propagation
|
- Proper error propagation
|
||||||
@@ -367,12 +393,14 @@ Server spawns Python process for KiCAD operations:
|
|||||||
## Achievements
|
## Achievements
|
||||||
|
|
||||||
### Development Infrastructure ✅
|
### Development Infrastructure ✅
|
||||||
|
|
||||||
- ✅ TypeScript build pipeline working
|
- ✅ TypeScript build pipeline working
|
||||||
- ✅ All source files complete
|
- ✅ All source files complete
|
||||||
- ✅ No compilation errors
|
- ✅ No compilation errors
|
||||||
- ✅ Source maps generated for debugging
|
- ✅ Source maps generated for debugging
|
||||||
|
|
||||||
### Server Functionality ✅
|
### Server Functionality ✅
|
||||||
|
|
||||||
- ✅ MCP protocol implementation working
|
- ✅ MCP protocol implementation working
|
||||||
- ✅ STDIO transport connected
|
- ✅ STDIO transport connected
|
||||||
- ✅ Python subprocess integration
|
- ✅ Python subprocess integration
|
||||||
@@ -380,12 +408,14 @@ Server spawns Python process for KiCAD operations:
|
|||||||
- ✅ Graceful startup and shutdown
|
- ✅ Graceful startup and shutdown
|
||||||
|
|
||||||
### Documentation ✅
|
### Documentation ✅
|
||||||
|
|
||||||
- ✅ Comprehensive client configuration guide
|
- ✅ Comprehensive client configuration guide
|
||||||
- ✅ Platform-specific examples
|
- ✅ Platform-specific examples
|
||||||
- ✅ Troubleshooting section
|
- ✅ Troubleshooting section
|
||||||
- ✅ Advanced configuration options
|
- ✅ Advanced configuration options
|
||||||
|
|
||||||
### Configuration ✅
|
### Configuration ✅
|
||||||
|
|
||||||
- ✅ Linux config example
|
- ✅ Linux config example
|
||||||
- ✅ Windows config example
|
- ✅ Windows config example
|
||||||
- ✅ macOS config example
|
- ✅ macOS config example
|
||||||
@@ -398,7 +428,7 @@ Server spawns Python process for KiCAD operations:
|
|||||||
**Week 1 Progress:** 100% ✅
|
**Week 1 Progress:** 100% ✅
|
||||||
|
|
||||||
| Category | Status |
|
| Category | Status |
|
||||||
|----------|--------|
|
| ---------------------- | ------------- |
|
||||||
| TypeScript compilation | ✅ Complete |
|
| TypeScript compilation | ✅ Complete |
|
||||||
| Server startup | ✅ Working |
|
| Server startup | ✅ Working |
|
||||||
| STDIO transport | ✅ Connected |
|
| STDIO transport | ✅ Connected |
|
||||||
@@ -445,6 +475,7 @@ Server spawns Python process for KiCAD operations:
|
|||||||
## Code Quality
|
## Code Quality
|
||||||
|
|
||||||
**Metrics:**
|
**Metrics:**
|
||||||
|
|
||||||
- TypeScript strict mode: ✅ Enabled
|
- TypeScript strict mode: ✅ Enabled
|
||||||
- ESLint compliance: ✅ Clean
|
- ESLint compliance: ✅ Clean
|
||||||
- Type coverage: ✅ 100% (all exports typed)
|
- Type coverage: ✅ 100% (all exports typed)
|
||||||
@@ -457,12 +488,14 @@ Server spawns Python process for KiCAD operations:
|
|||||||
## Session Impact
|
## Session Impact
|
||||||
|
|
||||||
### Before This Session:
|
### Before This Session:
|
||||||
|
|
||||||
- TypeScript wouldn't compile (missing files)
|
- TypeScript wouldn't compile (missing files)
|
||||||
- Server had duplicate resource registration bug
|
- Server had duplicate resource registration bug
|
||||||
- No client configuration documentation
|
- No client configuration documentation
|
||||||
- Unclear how to use with different MCP clients
|
- Unclear how to use with different MCP clients
|
||||||
|
|
||||||
### After This Session:
|
### After This Session:
|
||||||
|
|
||||||
- Complete TypeScript build working
|
- Complete TypeScript build working
|
||||||
- Server starts cleanly with all features registered
|
- Server starts cleanly with all features registered
|
||||||
- Comprehensive 500+ line configuration guide
|
- Comprehensive 500+ line configuration guide
|
||||||
|
|||||||
@@ -5,12 +5,14 @@
|
|||||||
Replace the template-based schematic workflow with dynamic symbol loading from KiCad's installed symbol libraries. This would eliminate the 13-component limitation and provide access to ALL KiCad symbols (~10,000+ symbols from standard libraries).
|
Replace the template-based schematic workflow with dynamic symbol loading from KiCad's installed symbol libraries. This would eliminate the 13-component limitation and provide access to ALL KiCad symbols (~10,000+ symbols from standard libraries).
|
||||||
|
|
||||||
**Current Status (Option 1):**
|
**Current Status (Option 1):**
|
||||||
|
|
||||||
- ✅ Template-based approach working
|
- ✅ Template-based approach working
|
||||||
- ✅ 13 component types supported
|
- ✅ 13 component types supported
|
||||||
- ❌ Limited symbol variety
|
- ❌ Limited symbol variety
|
||||||
- ❌ Requires manual template updates for new types
|
- ❌ Requires manual template updates for new types
|
||||||
|
|
||||||
**Proposed (Option 2):**
|
**Proposed (Option 2):**
|
||||||
|
|
||||||
- 🎯 Dynamic loading from `.kicad_sym` library files
|
- 🎯 Dynamic loading from `.kicad_sym` library files
|
||||||
- 🎯 Access to ~10,000+ KiCad symbols
|
- 🎯 Access to ~10,000+ KiCad symbols
|
||||||
- 🎯 No template maintenance required
|
- 🎯 No template maintenance required
|
||||||
@@ -23,6 +25,7 @@ Replace the template-based schematic workflow with dynamic symbol loading from K
|
|||||||
### kicad-skip Library Limitation
|
### kicad-skip Library Limitation
|
||||||
|
|
||||||
**Core Issue:** kicad-skip **cannot create symbols from scratch**. It can only:
|
**Core Issue:** kicad-skip **cannot create symbols from scratch**. It can only:
|
||||||
|
|
||||||
1. Clone existing symbols from a loaded schematic
|
1. Clone existing symbols from a loaded schematic
|
||||||
2. Modify properties of cloned symbols
|
2. Modify properties of cloned symbols
|
||||||
|
|
||||||
@@ -62,20 +65,24 @@ KiCad symbol libraries are S-expression files containing symbol definitions:
|
|||||||
### Standard KiCad Library Locations
|
### Standard KiCad Library Locations
|
||||||
|
|
||||||
**Linux:**
|
**Linux:**
|
||||||
|
|
||||||
- System libraries: `/usr/share/kicad/symbols/`
|
- System libraries: `/usr/share/kicad/symbols/`
|
||||||
- User libraries: `~/.local/share/kicad/8.0/symbols/` or `~/.config/kicad/8.0/symbols/`
|
- User libraries: `~/.local/share/kicad/8.0/symbols/` or `~/.config/kicad/8.0/symbols/`
|
||||||
|
|
||||||
**Windows:**
|
**Windows:**
|
||||||
|
|
||||||
- System libraries: `C:\Program Files\KiCad\9.0\share\kicad\symbols\`
|
- System libraries: `C:\Program Files\KiCad\9.0\share\kicad\symbols\`
|
||||||
- User libraries: `%APPDATA%\kicad\8.0\symbols\`
|
- User libraries: `%APPDATA%\kicad\8.0\symbols\`
|
||||||
|
|
||||||
**macOS:**
|
**macOS:**
|
||||||
|
|
||||||
- System libraries: `/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/`
|
- System libraries: `/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/`
|
||||||
- User libraries: `~/Library/Preferences/kicad/8.0/symbols/`
|
- User libraries: `~/Library/Preferences/kicad/8.0/symbols/`
|
||||||
|
|
||||||
### Standard Library Files
|
### Standard Library Files
|
||||||
|
|
||||||
Common libraries (each containing 50-500 symbols):
|
Common libraries (each containing 50-500 symbols):
|
||||||
|
|
||||||
- `Device.kicad_sym` - Passives (R, C, L, D, LED, Crystal, etc.)
|
- `Device.kicad_sym` - Passives (R, C, L, D, LED, Crystal, etc.)
|
||||||
- `Connector.kicad_sym` - Connectors (headers, USB, etc.)
|
- `Connector.kicad_sym` - Connectors (headers, USB, etc.)
|
||||||
- `Connector_Generic.kicad_sym` - Generic connectors
|
- `Connector_Generic.kicad_sym` - Generic connectors
|
||||||
@@ -96,6 +103,7 @@ Common libraries (each containing 50-500 symbols):
|
|||||||
**Goal:** Build an index of all available symbols and their locations
|
**Goal:** Build an index of all available symbols and their locations
|
||||||
|
|
||||||
**Implementation:**
|
**Implementation:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class SymbolLibraryManager:
|
class SymbolLibraryManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -288,16 +296,19 @@ def add_schematic_component_dynamic(params):
|
|||||||
## Advantages Over Template Approach
|
## Advantages Over Template Approach
|
||||||
|
|
||||||
### ✅ Unlimited Symbol Access
|
### ✅ Unlimited Symbol Access
|
||||||
|
|
||||||
- Access to ~10,000+ standard KiCad symbols
|
- Access to ~10,000+ standard KiCad symbols
|
||||||
- Support for custom user libraries
|
- Support for custom user libraries
|
||||||
- Support for 3rd-party libraries (JLCPCB, Espressif, etc.)
|
- Support for 3rd-party libraries (JLCPCB, Espressif, etc.)
|
||||||
|
|
||||||
### ✅ No Maintenance Required
|
### ✅ No Maintenance Required
|
||||||
|
|
||||||
- Template doesn't need updates for new component types
|
- Template doesn't need updates for new component types
|
||||||
- Automatically supports new KiCad library additions
|
- Automatically supports new KiCad library additions
|
||||||
- Works with custom symbol libraries
|
- Works with custom symbol libraries
|
||||||
|
|
||||||
### ✅ Better User Experience
|
### ✅ Better User Experience
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Add an STM32F103C8T6 microcontroller at position 100,100"
|
User: "Add an STM32F103C8T6 microcontroller at position 100,100"
|
||||||
AI: *Searches symbol index*
|
AI: *Searches symbol index*
|
||||||
@@ -309,6 +320,7 @@ AI: *Searches symbol index*
|
|||||||
```
|
```
|
||||||
|
|
||||||
### ✅ Flexible Symbol Search
|
### ✅ Flexible Symbol Search
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Find all resistors
|
# Find all resistors
|
||||||
symbols = lib_manager.search_symbols(query="resistor")
|
symbols = lib_manager.search_symbols(query="resistor")
|
||||||
@@ -327,6 +339,7 @@ symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1")
|
|||||||
**Problem:** Directly manipulating S-expression data is error-prone
|
**Problem:** Directly manipulating S-expression data is error-prone
|
||||||
|
|
||||||
**Mitigation:**
|
**Mitigation:**
|
||||||
|
|
||||||
- Use `sexpdata` library (already a dependency)
|
- Use `sexpdata` library (already a dependency)
|
||||||
- Create helper functions for common operations
|
- Create helper functions for common operations
|
||||||
- Add comprehensive validation and error handling
|
- Add comprehensive validation and error handling
|
||||||
@@ -337,6 +350,7 @@ symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1")
|
|||||||
**Problem:** Loading/reloading schematics after injection could be slow
|
**Problem:** Loading/reloading schematics after injection could be slow
|
||||||
|
|
||||||
**Mitigation:**
|
**Mitigation:**
|
||||||
|
|
||||||
- **Cache loaded symbols**: Once injected, symbol stays in schematic
|
- **Cache loaded symbols**: Once injected, symbol stays in schematic
|
||||||
- **Batch injection**: Inject multiple symbols at once
|
- **Batch injection**: Inject multiple symbols at once
|
||||||
- **Lazy loading**: Only inject symbols when first used
|
- **Lazy loading**: Only inject symbols when first used
|
||||||
@@ -346,6 +360,7 @@ symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1")
|
|||||||
**Problem:** Some symbols may have complex pin configurations or multiple units
|
**Problem:** Some symbols may have complex pin configurations or multiple units
|
||||||
|
|
||||||
**Mitigation:**
|
**Mitigation:**
|
||||||
|
|
||||||
- Start with simple 2-pin passives (R, C, L)
|
- Start with simple 2-pin passives (R, C, L)
|
||||||
- Gradually add support for multi-pin ICs
|
- Gradually add support for multi-pin ICs
|
||||||
- Handle multi-unit symbols (gates, OpAmp sections) explicitly
|
- Handle multi-unit symbols (gates, OpAmp sections) explicitly
|
||||||
@@ -356,6 +371,7 @@ symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1")
|
|||||||
**Problem:** KiCad symbol format may change between versions
|
**Problem:** KiCad symbol format may change between versions
|
||||||
|
|
||||||
**Mitigation:**
|
**Mitigation:**
|
||||||
|
|
||||||
- Parse KiCad version from library files
|
- Parse KiCad version from library files
|
||||||
- Version-specific handling if needed
|
- Version-specific handling if needed
|
||||||
- Fallback to template approach for unsupported formats
|
- Fallback to template approach for unsupported formats
|
||||||
@@ -365,6 +381,7 @@ symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1")
|
|||||||
## Implementation Phases
|
## Implementation Phases
|
||||||
|
|
||||||
### Phase A: Proof of Concept (1-2 weeks)
|
### Phase A: Proof of Concept (1-2 weeks)
|
||||||
|
|
||||||
- [ ] Create `SymbolLibraryManager` class
|
- [ ] Create `SymbolLibraryManager` class
|
||||||
- [ ] Implement library discovery (Linux paths only)
|
- [ ] Implement library discovery (Linux paths only)
|
||||||
- [ ] Implement symbol indexing
|
- [ ] Implement symbol indexing
|
||||||
@@ -373,6 +390,7 @@ symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1")
|
|||||||
- [ ] Test end-to-end with simple components
|
- [ ] Test end-to-end with simple components
|
||||||
|
|
||||||
### Phase B: Core Functionality (2-3 weeks)
|
### Phase B: Core Functionality (2-3 weeks)
|
||||||
|
|
||||||
- [ ] Cross-platform library discovery (Windows, macOS)
|
- [ ] Cross-platform library discovery (Windows, macOS)
|
||||||
- [ ] Symbol search functionality
|
- [ ] Symbol search functionality
|
||||||
- [ ] Template instance creation automation
|
- [ ] Template instance creation automation
|
||||||
@@ -381,6 +399,7 @@ symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1")
|
|||||||
- [ ] Unit tests for all operations
|
- [ ] Unit tests for all operations
|
||||||
|
|
||||||
### Phase C: MCP Integration (1 week)
|
### Phase C: MCP Integration (1 week)
|
||||||
|
|
||||||
- [ ] Create `add_schematic_component_dynamic` tool
|
- [ ] Create `add_schematic_component_dynamic` tool
|
||||||
- [ ] Update `search_symbols` to use library index
|
- [ ] Update `search_symbols` to use library index
|
||||||
- [ ] Add `list_available_symbols` tool
|
- [ ] Add `list_available_symbols` tool
|
||||||
@@ -388,6 +407,7 @@ symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1")
|
|||||||
- [ ] Documentation and examples
|
- [ ] Documentation and examples
|
||||||
|
|
||||||
### Phase D: Advanced Features (2-3 weeks)
|
### Phase D: Advanced Features (2-3 weeks)
|
||||||
|
|
||||||
- [ ] Multi-unit symbol support (e.g., quad OpAmps)
|
- [ ] Multi-unit symbol support (e.g., quad OpAmps)
|
||||||
- [ ] Custom library registration
|
- [ ] Custom library registration
|
||||||
- [ ] Symbol caching and optimization
|
- [ ] Symbol caching and optimization
|
||||||
@@ -428,18 +448,21 @@ def add_schematic_component(params):
|
|||||||
## Success Criteria
|
## Success Criteria
|
||||||
|
|
||||||
### Must Have
|
### Must Have
|
||||||
|
|
||||||
- [ ] Load symbols from Device.kicad_sym (passives)
|
- [ ] Load symbols from Device.kicad_sym (passives)
|
||||||
- [ ] Support R, C, L, D, LED (5 core types)
|
- [ ] Support R, C, L, D, LED (5 core types)
|
||||||
- [ ] Cross-platform library discovery
|
- [ ] Cross-platform library discovery
|
||||||
- [ ] Proper error handling
|
- [ ] Proper error handling
|
||||||
|
|
||||||
### Should Have
|
### Should Have
|
||||||
|
|
||||||
- [ ] Support for all Device.kicad_sym symbols (~50 symbols)
|
- [ ] Support for all Device.kicad_sym symbols (~50 symbols)
|
||||||
- [ ] Support for Connector.kicad_sym symbols
|
- [ ] Support for Connector.kicad_sym symbols
|
||||||
- [ ] Symbol search by name/keyword
|
- [ ] Symbol search by name/keyword
|
||||||
- [ ] Performance: < 1 second per symbol injection
|
- [ ] Performance: < 1 second per symbol injection
|
||||||
|
|
||||||
### Nice to Have
|
### Nice to Have
|
||||||
|
|
||||||
- [ ] Support for all standard libraries (~10,000 symbols)
|
- [ ] Support for all standard libraries (~10,000 symbols)
|
||||||
- [ ] Multi-unit symbol support
|
- [ ] Multi-unit symbol support
|
||||||
- [ ] Custom library registration
|
- [ ] Custom library registration
|
||||||
@@ -450,7 +473,7 @@ def add_schematic_component(params):
|
|||||||
## Risk Assessment
|
## Risk Assessment
|
||||||
|
|
||||||
| Risk | Probability | Impact | Mitigation |
|
| Risk | Probability | Impact | Mitigation |
|
||||||
|------|-------------|--------|------------|
|
| ------------------------------- | ----------- | ------ | ------------------------------------------------ |
|
||||||
| S-expression parsing complexity | High | High | Use proven `sexpdata` library, extensive testing |
|
| S-expression parsing complexity | High | High | Use proven `sexpdata` library, extensive testing |
|
||||||
| Performance degradation | Medium | Medium | Implement caching, lazy loading |
|
| Performance degradation | Medium | Medium | Implement caching, lazy loading |
|
||||||
| KiCad version incompatibility | Low | High | Version detection, format validation |
|
| KiCad version incompatibility | Low | High | Version detection, format validation |
|
||||||
@@ -469,6 +492,7 @@ Dynamic library loading is **feasible and highly beneficial** for the schematic
|
|||||||
4. **Enable true "natural language PCB design"**
|
4. **Enable true "natural language PCB design"**
|
||||||
|
|
||||||
**Recommendation:**
|
**Recommendation:**
|
||||||
|
|
||||||
- ✅ **Keep Option 1 (expanded template) for immediate use**
|
- ✅ **Keep Option 1 (expanded template) for immediate use**
|
||||||
- ✅ **Implement Option 2 (dynamic loading) over 6-8 weeks**
|
- ✅ **Implement Option 2 (dynamic loading) over 6-8 weeks**
|
||||||
- ✅ **Maintain template fallback for compatibility**
|
- ✅ **Maintain template fallback for compatibility**
|
||||||
|
|||||||
@@ -18,30 +18,35 @@ The dynamic symbol loading is now **FULLY OPERATIONAL** and accessible through t
|
|||||||
## What's Working (Core Functionality)
|
## What's Working (Core Functionality)
|
||||||
|
|
||||||
### ✅ Symbol Extraction
|
### ✅ Symbol Extraction
|
||||||
|
|
||||||
- Parse `.kicad_sym` library files using S-expression parser
|
- Parse `.kicad_sym` library files using S-expression parser
|
||||||
- Extract specific symbol definitions by name
|
- Extract specific symbol definitions by name
|
||||||
- Cache parsed libraries for performance
|
- Cache parsed libraries for performance
|
||||||
- Tested with Device.kicad_sym (533 symbols)
|
- Tested with Device.kicad_sym (533 symbols)
|
||||||
|
|
||||||
### ✅ S-Expression Manipulation
|
### ✅ S-Expression Manipulation
|
||||||
|
|
||||||
- Load schematic files as S-expression trees
|
- Load schematic files as S-expression trees
|
||||||
- Inject symbol definitions into `lib_symbols` section
|
- Inject symbol definitions into `lib_symbols` section
|
||||||
- Preserve schematic structure and formatting
|
- Preserve schematic structure and formatting
|
||||||
- Write modified schematics back to disk
|
- Write modified schematics back to disk
|
||||||
|
|
||||||
### ✅ Template Instance Creation
|
### ✅ Template Instance Creation
|
||||||
|
|
||||||
- Create offscreen template instances at negative Y coordinates
|
- Create offscreen template instances at negative Y coordinates
|
||||||
- Generate unique UUIDs for each template
|
- Generate unique UUIDs for each template
|
||||||
- Set proper properties (Reference, Value, Footprint, Datasheet)
|
- Set proper properties (Reference, Value, Footprint, Datasheet)
|
||||||
- Templates marked as: `in_bom: no`, `on_board: no`, `dnp: yes`
|
- Templates marked as: `in_bom: no`, `on_board: no`, `dnp: yes`
|
||||||
|
|
||||||
### ✅ Component Cloning
|
### ✅ Component Cloning
|
||||||
|
|
||||||
- kicad-skip successfully clones from dynamic templates
|
- kicad-skip successfully clones from dynamic templates
|
||||||
- Components inherit symbol structure from injected definitions
|
- Components inherit symbol structure from injected definitions
|
||||||
- Properties can be modified after cloning
|
- Properties can be modified after cloning
|
||||||
- Full integration with existing ComponentManager
|
- Full integration with existing ComponentManager
|
||||||
|
|
||||||
### ✅ Cross-Platform Library Discovery
|
### ✅ Cross-Platform Library Discovery
|
||||||
|
|
||||||
- Linux: `/usr/share/kicad/symbols`, `~/.local/share/kicad/*/symbols`
|
- Linux: `/usr/share/kicad/symbols`, `~/.local/share/kicad/*/symbols`
|
||||||
- Windows: `C:/Program Files/KiCad/*/share/kicad/symbols`
|
- Windows: `C:/Program Files/KiCad/*/share/kicad/symbols`
|
||||||
- macOS: `/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols`
|
- macOS: `/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols`
|
||||||
@@ -91,6 +96,7 @@ Results:
|
|||||||
**Class:** `DynamicSymbolLoader`
|
**Class:** `DynamicSymbolLoader`
|
||||||
|
|
||||||
**Key Methods:**
|
**Key Methods:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Library Discovery
|
# Library Discovery
|
||||||
find_kicad_symbol_libraries() -> List[Path]
|
find_kicad_symbol_libraries() -> List[Path]
|
||||||
@@ -109,6 +115,7 @@ load_symbol_dynamically(schematic_path: Path, library: str, symbol: str) -> str
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Caching:**
|
**Caching:**
|
||||||
|
|
||||||
- `library_cache`: Parsed library files (path → S-expression data)
|
- `library_cache`: Parsed library files (path → S-expression data)
|
||||||
- `symbol_cache`: Extracted symbols (lib:symbol → symbol definition)
|
- `symbol_cache`: Extracted symbols (lib:symbol → symbol definition)
|
||||||
|
|
||||||
@@ -117,16 +124,19 @@ load_symbol_dynamically(schematic_path: Path, library: str, symbol: str) -> str
|
|||||||
## What's NOT Yet Done (Integration Layer)
|
## What's NOT Yet Done (Integration Layer)
|
||||||
|
|
||||||
### ⏳ MCP Tool Integration
|
### ⏳ MCP Tool Integration
|
||||||
|
|
||||||
- Need to create `add_schematic_component_dynamic` MCP tool
|
- Need to create `add_schematic_component_dynamic` MCP tool
|
||||||
- Wire dynamic loader through MCP interface (has schematic path)
|
- Wire dynamic loader through MCP interface (has schematic path)
|
||||||
- Update existing `add_schematic_component` to auto-detect and use dynamic loading
|
- Update existing `add_schematic_component` to auto-detect and use dynamic loading
|
||||||
|
|
||||||
### ⏳ Smart Symbol Discovery
|
### ⏳ Smart Symbol Discovery
|
||||||
|
|
||||||
- Automatic library detection from component type
|
- Automatic library detection from component type
|
||||||
- Search across all libraries for symbol names
|
- Search across all libraries for symbol names
|
||||||
- Fuzzy matching for symbol names
|
- Fuzzy matching for symbol names
|
||||||
|
|
||||||
### ⏳ Advanced Features
|
### ⏳ Advanced Features
|
||||||
|
|
||||||
- Multi-unit symbol support (e.g., quad op-amps)
|
- Multi-unit symbol support (e.g., quad op-amps)
|
||||||
- Pin configuration handling
|
- Pin configuration handling
|
||||||
- Custom library registration
|
- Custom library registration
|
||||||
@@ -137,21 +147,25 @@ load_symbol_dynamically(schematic_path: Path, library: str, symbol: str) -> str
|
|||||||
## Technical Challenges Solved
|
## Technical Challenges Solved
|
||||||
|
|
||||||
### Challenge 1: S-Expression Parsing
|
### Challenge 1: S-Expression Parsing
|
||||||
|
|
||||||
**Problem:** KiCad files use Lisp-style S-expressions, complex to parse
|
**Problem:** KiCad files use Lisp-style S-expressions, complex to parse
|
||||||
**Solution:** Used `sexpdata` library (already a dependency of kicad-skip)
|
**Solution:** Used `sexpdata` library (already a dependency of kicad-skip)
|
||||||
**Result:** ✅ Robust parsing with proper handling of nested structures
|
**Result:** ✅ Robust parsing with proper handling of nested structures
|
||||||
|
|
||||||
### Challenge 2: Symbol Structure Complexity
|
### Challenge 2: Symbol Structure Complexity
|
||||||
|
|
||||||
**Problem:** Symbols have complex nested structure with multiple sub-symbols
|
**Problem:** Symbols have complex nested structure with multiple sub-symbols
|
||||||
**Solution:** Extract entire symbol tree as-is, inject without modification
|
**Solution:** Extract entire symbol tree as-is, inject without modification
|
||||||
**Result:** ✅ Preserves all symbol details (graphics, pins, properties)
|
**Result:** ✅ Preserves all symbol details (graphics, pins, properties)
|
||||||
|
|
||||||
### Challenge 3: kicad-skip Integration
|
### Challenge 3: kicad-skip Integration
|
||||||
|
|
||||||
**Problem:** kicad-skip can only clone existing symbols, can't create from scratch
|
**Problem:** kicad-skip can only clone existing symbols, can't create from scratch
|
||||||
**Solution:** Inject symbol into lib_symbols, create template instance, then clone
|
**Solution:** Inject symbol into lib_symbols, create template instance, then clone
|
||||||
**Result:** ✅ Seamless integration, kicad-skip unaware of dynamic loading
|
**Result:** ✅ Seamless integration, kicad-skip unaware of dynamic loading
|
||||||
|
|
||||||
### Challenge 4: Schematic File Path Access
|
### Challenge 4: Schematic File Path Access
|
||||||
|
|
||||||
**Problem:** kicad-skip Schematic object doesn't expose file path
|
**Problem:** kicad-skip Schematic object doesn't expose file path
|
||||||
**Solution:** Pass schematic path explicitly at MCP interface layer
|
**Solution:** Pass schematic path explicitly at MCP interface layer
|
||||||
**Result:** ⏳ Workaround identified, integration pending
|
**Result:** ⏳ Workaround identified, integration pending
|
||||||
@@ -192,7 +206,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
reference: "U1",
|
reference: "U1",
|
||||||
x: 100,
|
x: 100,
|
||||||
y: 100,
|
y: 100,
|
||||||
footprint: "Package_QFP:LQFP-48_7x7mm_P0.5mm"
|
footprint: "Package_QFP:LQFP-48_7x7mm_P0.5mm",
|
||||||
});
|
});
|
||||||
|
|
||||||
// The tool will:
|
// The tool will:
|
||||||
@@ -210,7 +224,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
## Comparison: Before vs After
|
## Comparison: Before vs After
|
||||||
|
|
||||||
| Feature | Static Templates (Current) | Dynamic Loading (New) |
|
| Feature | Static Templates (Current) | Dynamic Loading (New) |
|
||||||
|---------|---------------------------|----------------------|
|
| --------------------- | -------------------------- | ------------------------------ |
|
||||||
| **Available Symbols** | 13 types | ~10,000+ types |
|
| **Available Symbols** | 13 types | ~10,000+ types |
|
||||||
| **Maintenance** | Manual template updates | Zero maintenance |
|
| **Maintenance** | Manual template updates | Zero maintenance |
|
||||||
| **Custom Symbols** | Not supported | Fully supported |
|
| **Custom Symbols** | Not supported | Fully supported |
|
||||||
@@ -224,6 +238,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
## Phase Progress
|
## Phase Progress
|
||||||
|
|
||||||
### ✅ Phase A: Proof of Concept (COMPLETE)
|
### ✅ Phase A: Proof of Concept (COMPLETE)
|
||||||
|
|
||||||
- [x] Create `DynamicSymbolLoader` class
|
- [x] Create `DynamicSymbolLoader` class
|
||||||
- [x] Implement library discovery (Linux paths)
|
- [x] Implement library discovery (Linux paths)
|
||||||
- [x] Implement symbol indexing
|
- [x] Implement symbol indexing
|
||||||
@@ -235,6 +250,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
**Actual Time:** 4 hours! 🎉
|
**Actual Time:** 4 hours! 🎉
|
||||||
|
|
||||||
### ⏳ Phase B: Core Functionality (IN PROGRESS)
|
### ⏳ Phase B: Core Functionality (IN PROGRESS)
|
||||||
|
|
||||||
- [ ] Cross-platform library discovery (Windows, macOS)
|
- [ ] Cross-platform library discovery (Windows, macOS)
|
||||||
- [ ] Symbol search functionality
|
- [ ] Symbol search functionality
|
||||||
- [ ] Template instance creation automation
|
- [ ] Template instance creation automation
|
||||||
@@ -246,6 +262,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
**Progress:** 25% (cross-platform discovery done)
|
**Progress:** 25% (cross-platform discovery done)
|
||||||
|
|
||||||
### ✅ Phase C: MCP Integration (COMPLETE!)
|
### ✅ Phase C: MCP Integration (COMPLETE!)
|
||||||
|
|
||||||
- [x] Integrate dynamic loading into `add_schematic_component` MCP handler
|
- [x] Integrate dynamic loading into `add_schematic_component` MCP handler
|
||||||
- [x] Implement save → inject → reload → clone orchestration
|
- [x] Implement save → inject → reload → clone orchestration
|
||||||
- [x] Add schematic_path parameter throughout component chain
|
- [x] Add schematic_path parameter throughout component chain
|
||||||
@@ -258,6 +275,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
**Status:** PRODUCTION READY!
|
**Status:** PRODUCTION READY!
|
||||||
|
|
||||||
**What Works Now:**
|
**What Works Now:**
|
||||||
|
|
||||||
- ✅ Users can add ANY symbol from KiCad libraries via MCP interface
|
- ✅ Users can add ANY symbol from KiCad libraries via MCP interface
|
||||||
- ✅ Automatic detection and dynamic loading
|
- ✅ Automatic detection and dynamic loading
|
||||||
- ✅ Seamless fallback to static templates
|
- ✅ Seamless fallback to static templates
|
||||||
@@ -265,6 +283,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
- ✅ Compatible with all existing MCP clients
|
- ✅ Compatible with all existing MCP clients
|
||||||
|
|
||||||
### ⏸️ Phase D: Advanced Features (PENDING)
|
### ⏸️ Phase D: Advanced Features (PENDING)
|
||||||
|
|
||||||
- [ ] Multi-unit symbol support (e.g., quad OpAmps)
|
- [ ] Multi-unit symbol support (e.g., quad OpAmps)
|
||||||
- [ ] Custom library registration
|
- [ ] Custom library registration
|
||||||
- [ ] Symbol caching and optimization
|
- [ ] Symbol caching and optimization
|
||||||
@@ -299,18 +318,21 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
## Success Metrics
|
## Success Metrics
|
||||||
|
|
||||||
### Phase A Metrics (All Achieved ✅)
|
### Phase A Metrics (All Achieved ✅)
|
||||||
|
|
||||||
- [x] Load symbols from Device.kicad_sym (passives)
|
- [x] Load symbols from Device.kicad_sym (passives)
|
||||||
- [x] Support R, C, L, D, LED (5 core types)
|
- [x] Support R, C, L, D, LED (5 core types)
|
||||||
- [x] Cross-platform library discovery
|
- [x] Cross-platform library discovery
|
||||||
- [x] Proper error handling
|
- [x] Proper error handling
|
||||||
|
|
||||||
### Phase B Metrics (Target)
|
### Phase B Metrics (Target)
|
||||||
|
|
||||||
- [ ] Support for all Device.kicad_sym symbols (~500 symbols)
|
- [ ] Support for all Device.kicad_sym symbols (~500 symbols)
|
||||||
- [ ] Support for Connector.kicad_sym symbols
|
- [ ] Support for Connector.kicad_sym symbols
|
||||||
- [ ] Symbol search by name/keyword
|
- [ ] Symbol search by name/keyword
|
||||||
- [ ] Performance: < 1 second per symbol injection
|
- [ ] Performance: < 1 second per symbol injection
|
||||||
|
|
||||||
### Overall Success Criteria
|
### Overall Success Criteria
|
||||||
|
|
||||||
- [ ] Access to all standard libraries (~10,000 symbols)
|
- [ ] Access to all standard libraries (~10,000 symbols)
|
||||||
- [ ] Works on Linux, Windows, macOS
|
- [ ] Works on Linux, Windows, macOS
|
||||||
- [ ] <100ms latency for cached symbols
|
- [ ] <100ms latency for cached symbols
|
||||||
@@ -322,7 +344,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
## Risks & Mitigations
|
## Risks & Mitigations
|
||||||
|
|
||||||
| Risk | Status | Mitigation |
|
| Risk | Status | Mitigation |
|
||||||
|------|--------|------------|
|
| --------------------------- | -------------- | --------------------------------------- |
|
||||||
| S-expression complexity | ✅ RESOLVED | Used proven sexpdata library |
|
| S-expression complexity | ✅ RESOLVED | Used proven sexpdata library |
|
||||||
| Performance degradation | ✅ RESOLVED | Caching works great (<30ms cached) |
|
| Performance degradation | ✅ RESOLVED | Caching works great (<30ms cached) |
|
||||||
| KiCad version compatibility | ⚠️ TESTING | Version detection, format validation |
|
| KiCad version compatibility | ⚠️ TESTING | Version detection, format validation |
|
||||||
@@ -354,7 +376,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
### Test Components
|
### Test Components
|
||||||
|
|
||||||
| Component | Type | Library | Dynamic? | Result |
|
| Component | Type | Library | Dynamic? | Result |
|
||||||
|-----------|------|---------|----------|--------|
|
| --------- | ----------------- | ------- | -------- | --------------------------- |
|
||||||
| R1 | Resistor | Device | Yes | ✅ Added successfully |
|
| R1 | Resistor | Device | Yes | ✅ Added successfully |
|
||||||
| C1 | Capacitor | Device | Yes | ✅ Added successfully |
|
| C1 | Capacitor | Device | Yes | ✅ Added successfully |
|
||||||
| BT1 | Battery | Device | **Yes** | ✅ **Dynamic load + clone** |
|
| BT1 | Battery | Device | **Yes** | ✅ **Dynamic load + clone** |
|
||||||
@@ -375,6 +397,7 @@ await mcpServer.callTool("add_schematic_component_dynamic", {
|
|||||||
✅ Users can now add **ANY symbol from ~10,000 KiCad symbols** through the MCP interface!
|
✅ Users can now add **ANY symbol from ~10,000 KiCad symbols** through the MCP interface!
|
||||||
|
|
||||||
✅ The system automatically:
|
✅ The system automatically:
|
||||||
|
|
||||||
1. Detects if symbol needs dynamic loading
|
1. Detects if symbol needs dynamic loading
|
||||||
2. Saves current schematic
|
2. Saves current schematic
|
||||||
3. Injects symbol definition from library
|
3. Injects symbol definition from library
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ The current KiCAD MCP Server uses SWIG-based Python bindings (`import pcbnew`) w
|
|||||||
### Why Migrate?
|
### Why Migrate?
|
||||||
|
|
||||||
| SWIG API (Current) | IPC API (Future) |
|
| SWIG API (Current) | IPC API (Future) |
|
||||||
|-------------------|------------------|
|
| -------------------------------- | ------------------------------------ |
|
||||||
| ❌ Deprecated | ✅ Official & Supported |
|
| ❌ Deprecated | ✅ Official & Supported |
|
||||||
| ❌ Will be removed in KiCAD 10.0 | ✅ Long-term stability |
|
| ❌ Will be removed in KiCAD 10.0 | ✅ Long-term stability |
|
||||||
| ❌ Python-only | ✅ Multi-language (Python, JS, etc.) |
|
| ❌ Python-only | ✅ Multi-language (Python, JS, etc.) |
|
||||||
@@ -72,11 +72,13 @@ The current KiCAD MCP Server uses SWIG-based Python bindings (`import pcbnew`) w
|
|||||||
### Phase 1: Research & Preparation (Days 1-2)
|
### Phase 1: Research & Preparation (Days 1-2)
|
||||||
|
|
||||||
**Goals:**
|
**Goals:**
|
||||||
|
|
||||||
- Understand kicad-python library
|
- Understand kicad-python library
|
||||||
- Test IPC connection
|
- Test IPC connection
|
||||||
- Document API differences
|
- Document API differences
|
||||||
|
|
||||||
**Tasks:**
|
**Tasks:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install kicad-python
|
# Install kicad-python
|
||||||
pip install kicad-python>=0.5.0
|
pip install kicad-python>=0.5.0
|
||||||
@@ -93,6 +95,7 @@ EOF
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
- [ ] kicad-python installed and tested
|
- [ ] kicad-python installed and tested
|
||||||
- [ ] Connection test script
|
- [ ] Connection test script
|
||||||
- [ ] API comparison document (SWIG vs IPC)
|
- [ ] API comparison document (SWIG vs IPC)
|
||||||
@@ -104,6 +107,7 @@ EOF
|
|||||||
**Goal:** Create an abstraction layer to support both APIs during transition
|
**Goal:** Create an abstraction layer to support both APIs during transition
|
||||||
|
|
||||||
**File Structure:**
|
**File Structure:**
|
||||||
|
|
||||||
```
|
```
|
||||||
python/kicad_api/
|
python/kicad_api/
|
||||||
├── __init__.py
|
├── __init__.py
|
||||||
@@ -114,6 +118,7 @@ python/kicad_api/
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Abstract Interface:**
|
**Abstract Interface:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# python/kicad_api/base.py
|
# python/kicad_api/base.py
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
@@ -157,6 +162,7 @@ class KiCADBackend(ABC):
|
|||||||
```
|
```
|
||||||
|
|
||||||
**IPC Implementation:**
|
**IPC Implementation:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# python/kicad_api/ipc_backend.py
|
# python/kicad_api/ipc_backend.py
|
||||||
from kicad import KiCad
|
from kicad import KiCad
|
||||||
@@ -187,6 +193,7 @@ class IPCBackend(KiCADBackend):
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Backend Factory:**
|
**Backend Factory:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# python/kicad_api/factory.py
|
# python/kicad_api/factory.py
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -222,6 +229,7 @@ def create_backend(backend_type: Optional[str] = None) -> KiCADBackend:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
- [ ] Abstract base class defined
|
- [ ] Abstract base class defined
|
||||||
- [ ] IPC backend implemented
|
- [ ] IPC backend implemented
|
||||||
- [ ] SWIG backend (wrapper around existing code)
|
- [ ] SWIG backend (wrapper around existing code)
|
||||||
@@ -262,6 +270,7 @@ def create_backend(backend_type: Optional[str] = None) -> KiCADBackend:
|
|||||||
**Total Estimated Time: 30 hours (~4 days)**
|
**Total Estimated Time: 30 hours (~4 days)**
|
||||||
|
|
||||||
**Migration Template:**
|
**Migration Template:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# OLD (SWIG)
|
# OLD (SWIG)
|
||||||
import pcbnew
|
import pcbnew
|
||||||
@@ -277,6 +286,7 @@ board_api.set_size(width, height)
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
- [ ] project.py migrated
|
- [ ] project.py migrated
|
||||||
- [ ] board.py migrated
|
- [ ] board.py migrated
|
||||||
- [ ] component.py migrated
|
- [ ] component.py migrated
|
||||||
@@ -291,6 +301,7 @@ board_api.set_size(width, height)
|
|||||||
**Testing Strategy:**
|
**Testing Strategy:**
|
||||||
|
|
||||||
1. **Unit Tests**
|
1. **Unit Tests**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@pytest.mark.parametrize("backend_type", ["ipc", "swig"])
|
@pytest.mark.parametrize("backend_type", ["ipc", "swig"])
|
||||||
def test_create_project(backend_type):
|
def test_create_project(backend_type):
|
||||||
@@ -311,6 +322,7 @@ board_api.set_size(width, height)
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
- [ ] 50+ unit tests passing for IPC backend
|
- [ ] 50+ unit tests passing for IPC backend
|
||||||
- [ ] Side-by-side comparison tests
|
- [ ] Side-by-side comparison tests
|
||||||
- [ ] Performance benchmarks documented
|
- [ ] Performance benchmarks documented
|
||||||
@@ -322,7 +334,7 @@ board_api.set_size(width, height)
|
|||||||
### Project Operations
|
### Project Operations
|
||||||
|
|
||||||
| Operation | SWIG | IPC |
|
| Operation | SWIG | IPC |
|
||||||
|-----------|------|-----|
|
| -------------- | -------------------- | ------------------------ |
|
||||||
| Create project | Custom file creation | `kicad.create_project()` |
|
| Create project | Custom file creation | `kicad.create_project()` |
|
||||||
| Open project | `pcbnew.LoadBoard()` | `kicad.open_project()` |
|
| Open project | `pcbnew.LoadBoard()` | `kicad.open_project()` |
|
||||||
| Save project | `board.Save()` | `board.save()` |
|
| Save project | `board.Save()` | `board.save()` |
|
||||||
@@ -330,7 +342,7 @@ board_api.set_size(width, height)
|
|||||||
### Board Operations
|
### Board Operations
|
||||||
|
|
||||||
| Operation | SWIG | IPC |
|
| Operation | SWIG | IPC |
|
||||||
|-----------|------|-----|
|
| --------- | ----------------------- | -------------------- |
|
||||||
| Get board | `pcbnew.LoadBoard()` | `kicad.get_board()` |
|
| Get board | `pcbnew.LoadBoard()` | `kicad.get_board()` |
|
||||||
| Set size | `board.SetBoardSize()` | `board.set_size()` |
|
| Set size | `board.SetBoardSize()` | `board.set_size()` |
|
||||||
| Add layer | `board.GetLayerCount()` | `board.layers.add()` |
|
| Add layer | `board.GetLayerCount()` | `board.layers.add()` |
|
||||||
@@ -338,7 +350,7 @@ board_api.set_size(width, height)
|
|||||||
### Component Operations
|
### Component Operations
|
||||||
|
|
||||||
| Operation | SWIG | IPC |
|
| Operation | SWIG | IPC |
|
||||||
|-----------|------|-----|
|
| ---------------- | --------------------- | -------------------------- |
|
||||||
| Place component | `pcbnew.FOOTPRINT()` | `board.add_footprint()` |
|
| Place component | `pcbnew.FOOTPRINT()` | `board.add_footprint()` |
|
||||||
| Move component | `fp.SetPosition()` | `footprint.set_position()` |
|
| Move component | `fp.SetPosition()` | `footprint.set_position()` |
|
||||||
| Rotate component | `fp.SetOrientation()` | `footprint.set_rotation()` |
|
| Rotate component | `fp.SetOrientation()` | `footprint.set_rotation()` |
|
||||||
@@ -346,7 +358,7 @@ board_api.set_size(width, height)
|
|||||||
### Routing Operations
|
### Routing Operations
|
||||||
|
|
||||||
| Operation | SWIG | IPC |
|
| Operation | SWIG | IPC |
|
||||||
|-----------|------|-----|
|
| ----------- | --------------------- | ------------------- |
|
||||||
| Add net | `board.GetNetCount()` | `board.nets.add()` |
|
| Add net | `board.GetNetCount()` | `board.nets.add()` |
|
||||||
| Route trace | `pcbnew.PCB_TRACK()` | `board.add_track()` |
|
| Route trace | `pcbnew.PCB_TRACK()` | `board.add_track()` |
|
||||||
| Add via | `pcbnew.PCB_VIA()` | `board.add_via()` |
|
| Add via | `pcbnew.PCB_VIA()` | `board.add_via()` |
|
||||||
@@ -378,6 +390,7 @@ export KICAD_BACKEND=ipc # or 'swig' or 'auto'
|
|||||||
### User Migration Guide
|
### User Migration Guide
|
||||||
|
|
||||||
Create `docs/MIGRATING_TO_IPC.md`:
|
Create `docs/MIGRATING_TO_IPC.md`:
|
||||||
|
|
||||||
- How to enable IPC in KiCAD
|
- How to enable IPC in KiCAD
|
||||||
- What changes for users
|
- What changes for users
|
||||||
- Troubleshooting IPC connection issues
|
- Troubleshooting IPC connection issues
|
||||||
@@ -409,7 +422,7 @@ If IPC migration fails:
|
|||||||
## Timeline
|
## Timeline
|
||||||
|
|
||||||
| Week | Days | Tasks |
|
| Week | Days | Tasks |
|
||||||
|------|------|-------|
|
| ---------- | ------- | ----------------------------------------------- |
|
||||||
| **Week 2** | Mon-Tue | Research, install kicad-python, test connection |
|
| **Week 2** | Mon-Tue | Research, install kicad-python, test connection |
|
||||||
| | Wed-Thu | Build abstraction layer |
|
| | Wed-Thu | Build abstraction layer |
|
||||||
| | Fri | Port project.py and board.py |
|
| | Fri | Port project.py and board.py |
|
||||||
@@ -449,11 +462,13 @@ If IPC migration fails:
|
|||||||
## Next Steps (This Week)
|
## Next Steps (This Week)
|
||||||
|
|
||||||
1. **Install kicad-python**
|
1. **Install kicad-python**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install kicad-python
|
pip install kicad-python
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Test IPC connection**
|
2. **Test IPC connection**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Launch KiCAD
|
# Launch KiCAD
|
||||||
# Enable IPC in preferences
|
# Enable IPC in preferences
|
||||||
@@ -461,6 +476,7 @@ If IPC migration fails:
|
|||||||
```
|
```
|
||||||
|
|
||||||
3. **Create abstraction layer structure**
|
3. **Create abstraction layer structure**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p python/kicad_api
|
mkdir -p python/kicad_api
|
||||||
touch python/kicad_api/{__init__,base,ipc_backend,swig_backend,factory}.py
|
touch python/kicad_api/{__init__,base,ipc_backend,swig_backend,factory}.py
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Integrate JLCPCB's SMT assembly parts library (~100k+ parts) into the KiCAD MCP server, enabling:
|
Integrate JLCPCB's SMT assembly parts library (~100k+ parts) into the KiCAD MCP server, enabling:
|
||||||
|
|
||||||
- Component search by specifications (e.g., "10k resistor 0603 1%")
|
- Component search by specifications (e.g., "10k resistor 0603 1%")
|
||||||
- Automatic part selection optimized for cost (prefer Basic parts)
|
- Automatic part selection optimized for cost (prefer Basic parts)
|
||||||
- Real stock and pricing information
|
- Real stock and pricing information
|
||||||
@@ -83,12 +84,14 @@ docs/
|
|||||||
**File:** `python/commands/jlcpcb.py`
|
**File:** `python/commands/jlcpcb.py`
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
|
|
||||||
- Authenticate with JLCPCB API (requires user-provided key/secret)
|
- Authenticate with JLCPCB API (requires user-provided key/secret)
|
||||||
- Download parts database (paginated, ~100k parts)
|
- Download parts database (paginated, ~100k parts)
|
||||||
- Handle rate limiting and retries
|
- Handle rate limiting and retries
|
||||||
- Save to SQLite database
|
- Save to SQLite database
|
||||||
|
|
||||||
**API Endpoints:**
|
**API Endpoints:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Get auth token
|
# Get auth token
|
||||||
POST https://jlcpcb.com/external/genToken
|
POST https://jlcpcb.com/external/genToken
|
||||||
@@ -104,6 +107,7 @@ Body: { "lastKey": "PAGINATION_KEY" } # Optional, for next page
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Database Schema:**
|
**Database Schema:**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE components (
|
CREATE TABLE components (
|
||||||
lcsc TEXT PRIMARY KEY, -- "C12345"
|
lcsc TEXT PRIMARY KEY, -- "C12345"
|
||||||
@@ -128,6 +132,7 @@ CREATE INDEX idx_library_type ON components(library_type);
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Environment Variables:**
|
**Environment Variables:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ~/.bashrc or .env
|
# ~/.bashrc or .env
|
||||||
export JLCPCB_API_KEY="your_key_here"
|
export JLCPCB_API_KEY="your_key_here"
|
||||||
@@ -135,6 +140,7 @@ export JLCPCB_API_SECRET="your_secret_here"
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Python Implementation Outline:**
|
**Python Implementation Outline:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class JLCPCBClient:
|
class JLCPCBClient:
|
||||||
def __init__(self, api_key: str, api_secret: str):
|
def __init__(self, api_key: str, api_secret: str):
|
||||||
@@ -162,6 +168,7 @@ class JLCPCBClient:
|
|||||||
**File:** `python/commands/jlcpcb_parts.py`
|
**File:** `python/commands/jlcpcb_parts.py`
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
|
|
||||||
- Initialize/load SQLite database
|
- Initialize/load SQLite database
|
||||||
- Parametric search (resistance, capacitance, voltage, etc.)
|
- Parametric search (resistance, capacitance, voltage, etc.)
|
||||||
- Filter by library type (Basic/Extended)
|
- Filter by library type (Basic/Extended)
|
||||||
@@ -169,6 +176,7 @@ class JLCPCBClient:
|
|||||||
- Map package names to KiCAD footprints
|
- Map package names to KiCAD footprints
|
||||||
|
|
||||||
**Python Implementation Outline:**
|
**Python Implementation Outline:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class JLCPCBPartsManager:
|
class JLCPCBPartsManager:
|
||||||
def __init__(self, db_path: str = "data/jlcpcb_parts.db"):
|
def __init__(self, db_path: str = "data/jlcpcb_parts.db"):
|
||||||
@@ -203,6 +211,7 @@ class JLCPCBPartsManager:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Package to Footprint Mapping:**
|
**Package to Footprint Mapping:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"0402": [
|
"0402": [
|
||||||
@@ -215,17 +224,9 @@ class JLCPCBPartsManager:
|
|||||||
"Capacitor_SMD:C_0603_1608Metric",
|
"Capacitor_SMD:C_0603_1608Metric",
|
||||||
"LED_SMD:LED_0603_1608Metric"
|
"LED_SMD:LED_0603_1608Metric"
|
||||||
],
|
],
|
||||||
"0805": [
|
"0805": ["Resistor_SMD:R_0805_2012Metric", "Capacitor_SMD:C_0805_2012Metric"],
|
||||||
"Resistor_SMD:R_0805_2012Metric",
|
"SOT-23": ["Package_TO_SOT_SMD:SOT-23", "Package_TO_SOT_SMD:SOT-23-3"],
|
||||||
"Capacitor_SMD:C_0805_2012Metric"
|
"SOIC-8": ["Package_SO:SOIC-8_3.9x4.9mm_P1.27mm"]
|
||||||
],
|
|
||||||
"SOT-23": [
|
|
||||||
"Package_TO_SOT_SMD:SOT-23",
|
|
||||||
"Package_TO_SOT_SMD:SOT-23-3"
|
|
||||||
],
|
|
||||||
"SOIC-8": [
|
|
||||||
"Package_SO:SOIC-8_3.9x4.9mm_P1.27mm"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -238,6 +239,7 @@ class JLCPCBPartsManager:
|
|||||||
**New MCP Tools:**
|
**New MCP Tools:**
|
||||||
|
|
||||||
#### 1. `search_jlcpcb_parts`
|
#### 1. `search_jlcpcb_parts`
|
||||||
|
|
||||||
Search JLCPCB parts library by specifications.
|
Search JLCPCB parts library by specifications.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@@ -280,6 +282,7 @@ Search JLCPCB parts library by specifications.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Find me a 10k resistor, 0603 package, JLCPCB basic part"
|
User: "Find me a 10k resistor, 0603 package, JLCPCB basic part"
|
||||||
Claude: [uses search_jlcpcb_parts]
|
Claude: [uses search_jlcpcb_parts]
|
||||||
@@ -291,6 +294,7 @@ Recommended: C58972 (cheapest Basic part with high stock)
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### 2. `get_jlcpcb_part`
|
#### 2. `get_jlcpcb_part`
|
||||||
|
|
||||||
Get detailed information about a specific JLCPCB part.
|
Get detailed information about a specific JLCPCB part.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@@ -311,6 +315,7 @@ Get detailed information about a specific JLCPCB part.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"lcsc": "C25804",
|
"lcsc": "C25804",
|
||||||
@@ -322,18 +327,17 @@ Get detailed information about a specific JLCPCB part.
|
|||||||
"library_type": "Basic",
|
"library_type": "Basic",
|
||||||
"stock": 15000,
|
"stock": 15000,
|
||||||
"price_breaks": [
|
"price_breaks": [
|
||||||
{"qty": 1, "price": "$0.002"},
|
{ "qty": 1, "price": "$0.002" },
|
||||||
{"qty": 10, "price": "$0.0018"},
|
{ "qty": 10, "price": "$0.0018" },
|
||||||
{"qty": 100, "price": "$0.0015"}
|
{ "qty": 100, "price": "$0.0015" }
|
||||||
],
|
],
|
||||||
"datasheet": "https://datasheet.lcsc.com/...",
|
"datasheet": "https://datasheet.lcsc.com/...",
|
||||||
"kicad_footprints": [
|
"kicad_footprints": ["Resistor_SMD:R_0603_1608Metric"]
|
||||||
"Resistor_SMD:R_0603_1608Metric"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3. Enhanced `place_component`
|
#### 3. Enhanced `place_component`
|
||||||
|
|
||||||
Add JLCPCB integration to existing component placement.
|
Add JLCPCB integration to existing component placement.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@@ -347,6 +351,7 @@ Add JLCPCB integration to existing component placement.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Place a 10k resistor at 50, 40mm using JLCPCB part C25804"
|
User: "Place a 10k resistor at 50, 40mm using JLCPCB part C25804"
|
||||||
Claude: [uses place_component with jlcpcb_part="C25804"]
|
Claude: [uses place_component with jlcpcb_part="C25804"]
|
||||||
@@ -364,6 +369,7 @@ Claude: [uses place_component with jlcpcb_part="C25804"]
|
|||||||
### Phase 4: Testing & Documentation (Day 4)
|
### Phase 4: Testing & Documentation (Day 4)
|
||||||
|
|
||||||
**Testing:**
|
**Testing:**
|
||||||
|
|
||||||
1. Download JLCPCB database (verify ~100k parts loaded)
|
1. Download JLCPCB database (verify ~100k parts loaded)
|
||||||
2. Test parametric search (resistors, capacitors, ICs)
|
2. Test parametric search (resistors, capacitors, ICs)
|
||||||
3. Test package mapping (0603 → correct footprints)
|
3. Test package mapping (0603 → correct footprints)
|
||||||
@@ -371,6 +377,7 @@ Claude: [uses place_component with jlcpcb_part="C25804"]
|
|||||||
5. Verify BOM export includes LCSC part numbers
|
5. Verify BOM export includes LCSC part numbers
|
||||||
|
|
||||||
**Documentation:**
|
**Documentation:**
|
||||||
|
|
||||||
- User guide: How to get JLCPCB API key
|
- User guide: How to get JLCPCB API key
|
||||||
- Usage examples for each MCP tool
|
- Usage examples for each MCP tool
|
||||||
- Best practices (prefer Basic parts, check stock)
|
- Best practices (prefer Basic parts, check stock)
|
||||||
@@ -381,6 +388,7 @@ Claude: [uses place_component with jlcpcb_part="C25804"]
|
|||||||
## User Workflow Examples
|
## User Workflow Examples
|
||||||
|
|
||||||
### Example 1: Find and Place a Resistor
|
### Example 1: Find and Place a Resistor
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "I need a 10k pull-up resistor, 0603 size, cheapest JLCPCB basic part"
|
User: "I need a 10k pull-up resistor, 0603 size, cheapest JLCPCB basic part"
|
||||||
|
|
||||||
@@ -409,6 +417,7 @@ Claude: [uses place_component]
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Example 2: Design a Cost-Optimized LED Circuit
|
### Example 2: Design a Cost-Optimized LED Circuit
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Design an LED circuit with current-limiting resistor, use only JLCPCB basic parts"
|
User: "Design an LED circuit with current-limiting resistor, use only JLCPCB basic parts"
|
||||||
|
|
||||||
@@ -428,6 +437,7 @@ Claude: [searches for LED]
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Example 3: Check Stock Before Ordering
|
### Example 3: Check Stock Before Ordering
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "I need 100 of part C25804, is there enough stock?"
|
User: "I need 100 of part C25804, is there enough stock?"
|
||||||
|
|
||||||
@@ -453,12 +463,14 @@ Claude: [uses get_jlcpcb_part lcsc_number="C25804"]
|
|||||||
**Configure in MCP:**
|
**Configure in MCP:**
|
||||||
|
|
||||||
Option A: Environment variables (recommended)
|
Option A: Environment variables (recommended)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export JLCPCB_API_KEY="your_app_key"
|
export JLCPCB_API_KEY="your_app_key"
|
||||||
export JLCPCB_API_SECRET="your_app_secret"
|
export JLCPCB_API_SECRET="your_app_secret"
|
||||||
```
|
```
|
||||||
|
|
||||||
Option B: Config file
|
Option B: Config file
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"jlcpcb": {
|
"jlcpcb": {
|
||||||
@@ -470,6 +482,7 @@ Option B: Config file
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Initial Setup:**
|
**Initial Setup:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Download the JLCPCB parts database"
|
User: "Download the JLCPCB parts database"
|
||||||
|
|
||||||
@@ -543,11 +556,13 @@ This BOM can be directly uploaded to JLCPCB for assembly!
|
|||||||
**Initial Download:** ~5-10 minutes (108k parts)
|
**Initial Download:** ~5-10 minutes (108k parts)
|
||||||
|
|
||||||
**Incremental Updates:**
|
**Incremental Updates:**
|
||||||
|
|
||||||
- Run daily via cron/scheduled task
|
- Run daily via cron/scheduled task
|
||||||
- Only fetch parts modified since last update
|
- Only fetch parts modified since last update
|
||||||
- Much faster (~30 seconds)
|
- Much faster (~30 seconds)
|
||||||
|
|
||||||
**Update Command:**
|
**Update Command:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# In Python
|
# In Python
|
||||||
jlcpcb_client.update_database(db_path)
|
jlcpcb_client.update_database(db_path)
|
||||||
@@ -562,6 +577,7 @@ update_jlcpcb_database(force=True) # Full re-download
|
|||||||
## Success Metrics
|
## Success Metrics
|
||||||
|
|
||||||
**Implementation Complete When:**
|
**Implementation Complete When:**
|
||||||
|
|
||||||
- ✅ Can download/cache full JLCPCB parts database
|
- ✅ Can download/cache full JLCPCB parts database
|
||||||
- ✅ Parametric search works (resistors, capacitors, ICs)
|
- ✅ Parametric search works (resistors, capacitors, ICs)
|
||||||
- ✅ Package → footprint mapping covers 90%+ of common parts
|
- ✅ Package → footprint mapping covers 90%+ of common parts
|
||||||
@@ -570,6 +586,7 @@ update_jlcpcb_database(force=True) # Full re-download
|
|||||||
- ✅ Documentation complete with examples
|
- ✅ Documentation complete with examples
|
||||||
|
|
||||||
**User Experience Goal:**
|
**User Experience Goal:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Design a board with an ESP32, USB-C connector, and LED,
|
User: "Design a board with an ESP32, USB-C connector, and LED,
|
||||||
use only JLCPCB basic parts under $10 BOM"
|
use only JLCPCB basic parts under $10 BOM"
|
||||||
@@ -588,6 +605,7 @@ Claude: [searches JLCPCB database]
|
|||||||
## Future Enhancements
|
## Future Enhancements
|
||||||
|
|
||||||
**Post-MVP (v2.1+):**
|
**Post-MVP (v2.1+):**
|
||||||
|
|
||||||
- LCSC API integration for extended parametric data
|
- LCSC API integration for extended parametric data
|
||||||
- Digikey/Mouser fallback for non-JLCPCB parts
|
- Digikey/Mouser fallback for non-JLCPCB parts
|
||||||
- Part substitution suggestions (out of stock → alternatives)
|
- Part substitution suggestions (out of stock → alternatives)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
### What Was Implemented
|
### What Was Implemented
|
||||||
|
|
||||||
#### 1. Tool Registry (`src/tools/registry.ts`)
|
#### 1. Tool Registry (`src/tools/registry.ts`)
|
||||||
|
|
||||||
- ✅ Complete tool categorization (59 tools → 7 categories)
|
- ✅ Complete tool categorization (59 tools → 7 categories)
|
||||||
- ✅ Direct tools list (12 high-frequency tools)
|
- ✅ Direct tools list (12 high-frequency tools)
|
||||||
- ✅ Category lookup maps for O(1) access
|
- ✅ Category lookup maps for O(1) access
|
||||||
@@ -14,17 +15,20 @@
|
|||||||
- ✅ Registry statistics and metadata
|
- ✅ Registry statistics and metadata
|
||||||
|
|
||||||
#### 2. Router Tools (`src/tools/router.ts`)
|
#### 2. Router Tools (`src/tools/router.ts`)
|
||||||
|
|
||||||
- ✅ `list_tool_categories` - Browse all categories
|
- ✅ `list_tool_categories` - Browse all categories
|
||||||
- ✅ `get_category_tools` - View tools in a category
|
- ✅ `get_category_tools` - View tools in a category
|
||||||
- ✅ `execute_tool` - Execute any routed tool
|
- ✅ `execute_tool` - Execute any routed tool
|
||||||
- ✅ `search_tools` - Search tools by keyword
|
- ✅ `search_tools` - Search tools by keyword
|
||||||
|
|
||||||
#### 3. Server Integration (`src/server.ts`)
|
#### 3. Server Integration (`src/server.ts`)
|
||||||
|
|
||||||
- ✅ Router tools registered at server startup
|
- ✅ Router tools registered at server startup
|
||||||
- ✅ All tools remain functional (backwards compatible)
|
- ✅ All tools remain functional (backwards compatible)
|
||||||
- ✅ Logging added for router pattern status
|
- ✅ Logging added for router pattern status
|
||||||
|
|
||||||
#### 4. Documentation
|
#### 4. Documentation
|
||||||
|
|
||||||
- ✅ `TOOL_INVENTORY.md` - Complete tool catalog
|
- ✅ `TOOL_INVENTORY.md` - Complete tool catalog
|
||||||
- ✅ `ROUTER_ARCHITECTURE.md` - Design specification
|
- ✅ `ROUTER_ARCHITECTURE.md` - Design specification
|
||||||
- ✅ `ROUTER_IMPLEMENTATION_STATUS.md` - This file
|
- ✅ `ROUTER_IMPLEMENTATION_STATUS.md` - This file
|
||||||
@@ -36,6 +40,7 @@
|
|||||||
**Build:** ✅ Compiles successfully (`npm run build`)
|
**Build:** ✅ Compiles successfully (`npm run build`)
|
||||||
|
|
||||||
**Tool Count:**
|
**Tool Count:**
|
||||||
|
|
||||||
- Total Tools: 59 (ALL still registered and visible)
|
- Total Tools: 59 (ALL still registered and visible)
|
||||||
- Direct Tools: 12
|
- Direct Tools: 12
|
||||||
- Routed Tools: 47
|
- Routed Tools: 47
|
||||||
@@ -43,6 +48,7 @@
|
|||||||
- **Currently Visible to Claude:** 63 tools (59 + 4 router)
|
- **Currently Visible to Claude:** 63 tools (59 + 4 router)
|
||||||
|
|
||||||
**Token Impact:**
|
**Token Impact:**
|
||||||
|
|
||||||
- **Current:** ~42K tokens (still showing all tools)
|
- **Current:** ~42K tokens (still showing all tools)
|
||||||
- **Target:** ~12K tokens (Phase 2 optimization)
|
- **Target:** ~12K tokens (Phase 2 optimization)
|
||||||
- **Potential Savings:** ~30K tokens (71% reduction)
|
- **Potential Savings:** ~30K tokens (71% reduction)
|
||||||
@@ -50,46 +56,55 @@
|
|||||||
## 🔄 Phase 2: Token Optimization (Next Step)
|
## 🔄 Phase 2: Token Optimization (Next Step)
|
||||||
|
|
||||||
### Objective
|
### Objective
|
||||||
|
|
||||||
Hide routed tools from Claude's context while keeping them accessible via `execute_tool`.
|
Hide routed tools from Claude's context while keeping them accessible via `execute_tool`.
|
||||||
|
|
||||||
### Two Approaches
|
### Two Approaches
|
||||||
|
|
||||||
#### Option A: Registration Filtering (Recommended)
|
#### Option A: Registration Filtering (Recommended)
|
||||||
|
|
||||||
Modify tool registration to conditionally register tools based on whether they're in the direct list.
|
Modify tool registration to conditionally register tools based on whether they're in the direct list.
|
||||||
|
|
||||||
**Changes needed:**
|
**Changes needed:**
|
||||||
|
|
||||||
1. Update each `register*Tools` function to check `isDirectTool()`
|
1. Update each `register*Tools` function to check `isDirectTool()`
|
||||||
2. Only call `server.tool()` for direct tools
|
2. Only call `server.tool()` for direct tools
|
||||||
3. Routed tools remain accessible via `execute_tool` calling `callKicadScript`
|
3. Routed tools remain accessible via `execute_tool` calling `callKicadScript`
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
|
|
||||||
- Clean separation
|
- Clean separation
|
||||||
- True token savings
|
- True token savings
|
||||||
- No behavior changes
|
- No behavior changes
|
||||||
|
|
||||||
**Cons:**
|
**Cons:**
|
||||||
|
|
||||||
- Requires modifying 9 tool files
|
- Requires modifying 9 tool files
|
||||||
|
|
||||||
#### Option B: MCP Filter (If Supported)
|
#### Option B: MCP Filter (If Supported)
|
||||||
|
|
||||||
If MCP SDK supports tool filtering/hiding, use that instead.
|
If MCP SDK supports tool filtering/hiding, use that instead.
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
|
|
||||||
- No tool file changes
|
- No tool file changes
|
||||||
- Centralized control
|
- Centralized control
|
||||||
|
|
||||||
**Cons:**
|
**Cons:**
|
||||||
|
|
||||||
- May not be supported by SDK
|
- May not be supported by SDK
|
||||||
- Needs investigation
|
- Needs investigation
|
||||||
|
|
||||||
### Implementation Plan for Phase 2
|
### Implementation Plan for Phase 2
|
||||||
|
|
||||||
1. **Create Helper Function** (`src/tools/conditional-register.ts`)
|
1. **Create Helper Function** (`src/tools/conditional-register.ts`)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export function registerToolConditionally(
|
export function registerToolConditionally(
|
||||||
server: McpServer,
|
server: McpServer,
|
||||||
toolName: string,
|
toolName: string,
|
||||||
definition: ToolDefinition,
|
definition: ToolDefinition,
|
||||||
handler: Function
|
handler: Function,
|
||||||
) {
|
) {
|
||||||
if (isDirectTool(toolName)) {
|
if (isDirectTool(toolName)) {
|
||||||
// Register with MCP (visible to Claude)
|
// Register with MCP (visible to Claude)
|
||||||
@@ -115,7 +130,7 @@ If MCP SDK supports tool filtering/hiding, use that instead.
|
|||||||
## 📊 Categories & Distribution
|
## 📊 Categories & Distribution
|
||||||
|
|
||||||
| Category | Tools | Description |
|
| Category | Tools | Description |
|
||||||
|----------|-------|-------------|
|
| ------------- | ------ | ------------------------------------------------- |
|
||||||
| **board** | 9 | Board configuration, layers, zones, visualization |
|
| **board** | 9 | Board configuration, layers, zones, visualization |
|
||||||
| **component** | 8 | Advanced component operations |
|
| **component** | 8 | Advanced component operations |
|
||||||
| **export** | 8 | Manufacturing file generation |
|
| **export** | 8 | Manufacturing file generation |
|
||||||
@@ -130,6 +145,7 @@ If MCP SDK supports tool filtering/hiding, use that instead.
|
|||||||
## 🧪 Testing the Router
|
## 🧪 Testing the Router
|
||||||
|
|
||||||
### Test 1: List Categories
|
### Test 1: List Categories
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "What tool categories are available?"
|
User: "What tool categories are available?"
|
||||||
|
|
||||||
@@ -138,6 +154,7 @@ Result: Returns 7 categories with descriptions
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Test 2: Browse Category
|
### Test 2: Browse Category
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "What export tools are available?"
|
User: "What export tools are available?"
|
||||||
|
|
||||||
@@ -146,6 +163,7 @@ Result: Returns 8 export tools
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Test 3: Search Tools
|
### Test 3: Search Tools
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "How do I export gerber files?"
|
User: "How do I export gerber files?"
|
||||||
|
|
||||||
@@ -154,6 +172,7 @@ Result: Finds export_gerber in export category
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Test 4: Execute Tool
|
### Test 4: Execute Tool
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Export gerbers to ./output"
|
User: "Export gerbers to ./output"
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,12 @@ This plan outlines the implementation of complete schematic wiring functionality
|
|||||||
### What Exists ✅
|
### What Exists ✅
|
||||||
|
|
||||||
**Files:**
|
**Files:**
|
||||||
|
|
||||||
- `python/commands/connection_schematic.py` - ConnectionManager class with wire/label methods
|
- `python/commands/connection_schematic.py` - ConnectionManager class with wire/label methods
|
||||||
- MCP handlers in `kicad_interface.py` for 6 connection-related tools
|
- MCP handlers in `kicad_interface.py` for 6 connection-related tools
|
||||||
|
|
||||||
**MCP Tools (Registered):**
|
**MCP Tools (Registered):**
|
||||||
|
|
||||||
1. `add_schematic_wire` - Add wire between two points
|
1. `add_schematic_wire` - Add wire between two points
|
||||||
2. `add_schematic_connection` - Connect two component pins
|
2. `add_schematic_connection` - Connect two component pins
|
||||||
3. `add_schematic_net_label` - Add net label
|
3. `add_schematic_net_label` - Add net label
|
||||||
@@ -31,6 +33,7 @@ This plan outlines the implementation of complete schematic wiring functionality
|
|||||||
6. `generate_netlist` - Generate netlist from schematic
|
6. `generate_netlist` - Generate netlist from schematic
|
||||||
|
|
||||||
**ConnectionManager Methods:**
|
**ConnectionManager Methods:**
|
||||||
|
|
||||||
- `add_wire(schematic, start_point, end_point)` - Add wire between coordinates
|
- `add_wire(schematic, start_point, end_point)` - Add wire between coordinates
|
||||||
- `add_connection(schematic, source_ref, source_pin, target_ref, target_pin)` - Connect pins
|
- `add_connection(schematic, source_ref, source_pin, target_ref, target_pin)` - Connect pins
|
||||||
- `add_net_label(schematic, net_name, position)` - Add label
|
- `add_net_label(schematic, net_name, position)` - Add label
|
||||||
@@ -42,28 +45,33 @@ This plan outlines the implementation of complete schematic wiring functionality
|
|||||||
### What's Broken/Missing ❌
|
### What's Broken/Missing ❌
|
||||||
|
|
||||||
**Problem 1: kicad-skip API Uncertainty**
|
**Problem 1: kicad-skip API Uncertainty**
|
||||||
|
|
||||||
- Code assumes `schematic.wire.append()` exists
|
- Code assumes `schematic.wire.append()` exists
|
||||||
- Code assumes `schematic.label.append()` exists
|
- Code assumes `schematic.label.append()` exists
|
||||||
- Code assumes pins have `.name` and `.location` attributes
|
- Code assumes pins have `.name` and `.location` attributes
|
||||||
- **Need to verify what kicad-skip actually supports**
|
- **Need to verify what kicad-skip actually supports**
|
||||||
|
|
||||||
**Problem 2: Pin Location Calculation**
|
**Problem 2: Pin Location Calculation**
|
||||||
|
|
||||||
- Current implementation tries to calculate absolute pin positions
|
- Current implementation tries to calculate absolute pin positions
|
||||||
- May not account for symbol rotation
|
- May not account for symbol rotation
|
||||||
- May not work with multi-unit symbols
|
- May not work with multi-unit symbols
|
||||||
- Pin numbering vs pin naming confusion
|
- Pin numbering vs pin naming confusion
|
||||||
|
|
||||||
**Problem 3: No Visual Feedback**
|
**Problem 3: No Visual Feedback**
|
||||||
|
|
||||||
- No way to verify wires were created correctly
|
- No way to verify wires were created correctly
|
||||||
- No validation of wire endpoints
|
- No validation of wire endpoints
|
||||||
- No checks for overlapping wires or junctions
|
- No checks for overlapping wires or junctions
|
||||||
|
|
||||||
**Problem 4: Limited Testing**
|
**Problem 4: Limited Testing**
|
||||||
|
|
||||||
- No integration tests for wiring functionality
|
- No integration tests for wiring functionality
|
||||||
- No validation with real KiCad schematics
|
- No validation with real KiCad schematics
|
||||||
- User reported `add_schematic_wire` fails
|
- User reported `add_schematic_wire` fails
|
||||||
|
|
||||||
**Problem 5: Missing Features**
|
**Problem 5: Missing Features**
|
||||||
|
|
||||||
- No junction (wire intersection) support
|
- No junction (wire intersection) support
|
||||||
- No bus support (multi-bit signals)
|
- No bus support (multi-bit signals)
|
||||||
- No no-connect flags
|
- No no-connect flags
|
||||||
@@ -77,11 +85,13 @@ This plan outlines the implementation of complete schematic wiring functionality
|
|||||||
### Challenge 1: kicad-skip Wire API
|
### Challenge 1: kicad-skip Wire API
|
||||||
|
|
||||||
**Issue:** The kicad-skip library documentation is sparse. We need to determine:
|
**Issue:** The kicad-skip library documentation is sparse. We need to determine:
|
||||||
|
|
||||||
- Does `schematic.wire` exist?
|
- Does `schematic.wire` exist?
|
||||||
- What's the correct API to add wires?
|
- What's the correct API to add wires?
|
||||||
- How are wires stored in .kicad_sch files?
|
- How are wires stored in .kicad_sch files?
|
||||||
|
|
||||||
**S-Expression Format (KiCad 8/9):**
|
**S-Expression Format (KiCad 8/9):**
|
||||||
|
|
||||||
```lisp
|
```lisp
|
||||||
(wire (pts (xy 100 100) (xy 200 100))
|
(wire (pts (xy 100 100) (xy 200 100))
|
||||||
(stroke (width 0) (type default))
|
(stroke (width 0) (type default))
|
||||||
@@ -90,6 +100,7 @@ This plan outlines the implementation of complete schematic wiring functionality
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Approach:**
|
**Approach:**
|
||||||
|
|
||||||
1. Examine kicad-skip source code
|
1. Examine kicad-skip source code
|
||||||
2. Test wire creation manually with kicad-skip
|
2. Test wire creation manually with kicad-skip
|
||||||
3. Fall back to S-expression manipulation if necessary (similar to dynamic symbol loading)
|
3. Fall back to S-expression manipulation if necessary (similar to dynamic symbol loading)
|
||||||
@@ -102,12 +113,14 @@ This plan outlines the implementation of complete schematic wiring functionality
|
|||||||
Pins are defined within symbol definitions in lib_symbols, with coordinates relative to symbol origin. When symbol is placed, pins move with it.
|
Pins are defined within symbol definitions in lib_symbols, with coordinates relative to symbol origin. When symbol is placed, pins move with it.
|
||||||
|
|
||||||
**Required Information:**
|
**Required Information:**
|
||||||
|
|
||||||
- Symbol position (x, y)
|
- Symbol position (x, y)
|
||||||
- Symbol rotation angle
|
- Symbol rotation angle
|
||||||
- Pin offset from symbol origin
|
- Pin offset from symbol origin
|
||||||
- Pin number/name mapping
|
- Pin number/name mapping
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Parse symbol definition to find pin definitions
|
1. Parse symbol definition to find pin definitions
|
||||||
2. Apply transformation matrix (position + rotation) to pin coordinates
|
2. Apply transformation matrix (position + rotation) to pin coordinates
|
||||||
3. Return absolute pin position in schematic space
|
3. Return absolute pin position in schematic space
|
||||||
@@ -117,6 +130,7 @@ Pins are defined within symbol definitions in lib_symbols, with coordinates rela
|
|||||||
**Issue:** Users don't want to manually specify every wire segment.
|
**Issue:** Users don't want to manually specify every wire segment.
|
||||||
|
|
||||||
**Desired Behavior:**
|
**Desired Behavior:**
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Connect R1 pin 1 to C1 pin 1"
|
User: "Connect R1 pin 1 to C1 pin 1"
|
||||||
System:
|
System:
|
||||||
@@ -128,6 +142,7 @@ System:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Auto-Routing Options:**
|
**Auto-Routing Options:**
|
||||||
|
|
||||||
1. **Direct** - Single wire segment (diagonal if needed)
|
1. **Direct** - Single wire segment (diagonal if needed)
|
||||||
2. **Orthogonal** - Only horizontal/vertical segments (2 segments)
|
2. **Orthogonal** - Only horizontal/vertical segments (2 segments)
|
||||||
3. **Manhattan** - Complex path avoiding components (3+ segments)
|
3. **Manhattan** - Complex path avoiding components (3+ segments)
|
||||||
@@ -139,11 +154,13 @@ System:
|
|||||||
**Issue:** Labels need to attach to wires, not float in space.
|
**Issue:** Labels need to attach to wires, not float in space.
|
||||||
|
|
||||||
**KiCad Behavior:**
|
**KiCad Behavior:**
|
||||||
|
|
||||||
- Labels must touch a wire or pin
|
- Labels must touch a wire or pin
|
||||||
- Labels create electrical connections at their attachment point
|
- Labels create electrical connections at their attachment point
|
||||||
- Multiple labels with same name = connected net
|
- Multiple labels with same name = connected net
|
||||||
|
|
||||||
**Implementation:**
|
**Implementation:**
|
||||||
|
|
||||||
- When adding label, find nearest wire endpoint
|
- When adding label, find nearest wire endpoint
|
||||||
- Attach label to that coordinate
|
- Attach label to that coordinate
|
||||||
- Or create short wire stub for label attachment
|
- Or create short wire stub for label attachment
|
||||||
@@ -190,6 +207,7 @@ System:
|
|||||||
- Verify electrical connectivity
|
- Verify electrical connectivity
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
- Working `add_schematic_wire` tool
|
- Working `add_schematic_wire` tool
|
||||||
- Working `add_schematic_connection` tool
|
- Working `add_schematic_connection` tool
|
||||||
- Pin location discovery working
|
- Pin location discovery working
|
||||||
@@ -197,6 +215,7 @@ System:
|
|||||||
- Documentation updated
|
- Documentation updated
|
||||||
|
|
||||||
**Success Criteria:**
|
**Success Criteria:**
|
||||||
|
|
||||||
- User can connect two resistor pins with MCP command
|
- User can connect two resistor pins with MCP command
|
||||||
- Wire appears in KiCad schematic viewer
|
- Wire appears in KiCad schematic viewer
|
||||||
- Netlist shows electrical connection
|
- Netlist shows electrical connection
|
||||||
@@ -240,6 +259,7 @@ System:
|
|||||||
- Generate and validate netlist
|
- Generate and validate netlist
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
- Working `add_schematic_net_label` tool
|
- Working `add_schematic_net_label` tool
|
||||||
- Working `connect_to_net` tool
|
- Working `connect_to_net` tool
|
||||||
- Working `get_net_connections` tool
|
- Working `get_net_connections` tool
|
||||||
@@ -247,6 +267,7 @@ System:
|
|||||||
- Netlist generation working
|
- Netlist generation working
|
||||||
|
|
||||||
**Success Criteria:**
|
**Success Criteria:**
|
||||||
|
|
||||||
- User can label nets VCC, GND
|
- User can label nets VCC, GND
|
||||||
- Multiple components connect to same net
|
- Multiple components connect to same net
|
||||||
- Netlist correctly shows net membership
|
- Netlist correctly shows net membership
|
||||||
@@ -284,12 +305,14 @@ System:
|
|||||||
- Sheet connections
|
- Sheet connections
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
- Junction creation
|
- Junction creation
|
||||||
- No-connect support
|
- No-connect support
|
||||||
- Smart orthogonal routing
|
- Smart orthogonal routing
|
||||||
- Bus and hierarchical label support
|
- Bus and hierarchical label support
|
||||||
|
|
||||||
**Success Criteria:**
|
**Success Criteria:**
|
||||||
|
|
||||||
- Wires route cleanly around components
|
- Wires route cleanly around components
|
||||||
- Junctions appear at wire intersections
|
- Junctions appear at wire intersections
|
||||||
- Unused pins marked with no-connect
|
- Unused pins marked with no-connect
|
||||||
@@ -332,12 +355,14 @@ System:
|
|||||||
- Add to CHANGELOG
|
- Add to CHANGELOG
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
- ERC validation
|
- ERC validation
|
||||||
- Comprehensive test suite
|
- Comprehensive test suite
|
||||||
- Error handling
|
- Error handling
|
||||||
- Complete documentation
|
- Complete documentation
|
||||||
|
|
||||||
**Success Criteria:**
|
**Success Criteria:**
|
||||||
|
|
||||||
- 95%+ test pass rate
|
- 95%+ test pass rate
|
||||||
- Users can create functional circuits
|
- Users can create functional circuits
|
||||||
- Clear error messages on failures
|
- Clear error messages on failures
|
||||||
@@ -365,11 +390,13 @@ label = schematic.label.new(
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
|
|
||||||
- Clean, maintainable code
|
- Clean, maintainable code
|
||||||
- Follows library patterns
|
- Follows library patterns
|
||||||
- Less likely to break
|
- Less likely to break
|
||||||
|
|
||||||
**Cons:**
|
**Cons:**
|
||||||
|
|
||||||
- Depends on kicad-skip having these features
|
- Depends on kicad-skip having these features
|
||||||
- May be limited in functionality
|
- May be limited in functionality
|
||||||
|
|
||||||
@@ -407,11 +434,13 @@ with open(schematic_path, 'w') as f:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
|
|
||||||
- Complete control
|
- Complete control
|
||||||
- Can implement any feature
|
- Can implement any feature
|
||||||
- Works around library limitations
|
- Works around library limitations
|
||||||
|
|
||||||
**Cons:**
|
**Cons:**
|
||||||
|
|
||||||
- More complex
|
- More complex
|
||||||
- Requires deep KiCad format knowledge
|
- Requires deep KiCad format knowledge
|
||||||
- More maintenance
|
- More maintenance
|
||||||
@@ -447,6 +476,7 @@ Symbols are stored in `lib_symbols` section:
|
|||||||
### Step 2: Extract Pin Information
|
### Step 2: Extract Pin Information
|
||||||
|
|
||||||
For each pin:
|
For each pin:
|
||||||
|
|
||||||
- Number (e.g., "1", "2")
|
- Number (e.g., "1", "2")
|
||||||
- Name (e.g., "GND", "VCC", "~" for unnamed)
|
- Name (e.g., "GND", "VCC", "~" for unnamed)
|
||||||
- Position relative to symbol origin: `(at x y angle)`
|
- Position relative to symbol origin: `(at x y angle)`
|
||||||
@@ -462,6 +492,7 @@ From symbol instance in schematic:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Extract:
|
Extract:
|
||||||
|
|
||||||
- Position: `(at 100 100 0)` = x=100, y=100, rotation=0°
|
- Position: `(at 100 100 0)` = x=100, y=100, rotation=0°
|
||||||
- Reference: "R1"
|
- Reference: "R1"
|
||||||
|
|
||||||
@@ -518,6 +549,7 @@ R1 pin 2 C1 pin 1
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Algorithm:**
|
**Algorithm:**
|
||||||
|
|
||||||
1. Calculate midpoint
|
1. Calculate midpoint
|
||||||
2. Route horizontal to midpoint
|
2. Route horizontal to midpoint
|
||||||
3. Route vertical to target
|
3. Route vertical to target
|
||||||
@@ -540,6 +572,7 @@ Complex multi-segment paths avoiding components.
|
|||||||
### Unit Tests
|
### Unit Tests
|
||||||
|
|
||||||
Test individual functions:
|
Test individual functions:
|
||||||
|
|
||||||
- `test_add_wire()` - Wire creation
|
- `test_add_wire()` - Wire creation
|
||||||
- `test_get_pin_location()` - Pin discovery
|
- `test_get_pin_location()` - Pin discovery
|
||||||
- `test_add_net_label()` - Label creation
|
- `test_add_net_label()` - Label creation
|
||||||
@@ -548,6 +581,7 @@ Test individual functions:
|
|||||||
### Integration Tests
|
### Integration Tests
|
||||||
|
|
||||||
Test complete workflows:
|
Test complete workflows:
|
||||||
|
|
||||||
- `test_connect_two_resistors()` - Wire R1 to R2
|
- `test_connect_two_resistors()` - Wire R1 to R2
|
||||||
- `test_connect_to_vcc_net()` - Multiple components to VCC
|
- `test_connect_to_vcc_net()` - Multiple components to VCC
|
||||||
- `test_generate_netlist()` - Netlist accuracy
|
- `test_generate_netlist()` - Netlist accuracy
|
||||||
@@ -565,6 +599,7 @@ Test complete workflows:
|
|||||||
## Success Metrics
|
## Success Metrics
|
||||||
|
|
||||||
### Phase 1 Success:
|
### Phase 1 Success:
|
||||||
|
|
||||||
- [ ] `add_schematic_wire` works (coordinates)
|
- [ ] `add_schematic_wire` works (coordinates)
|
||||||
- [ ] `add_schematic_connection` works (pin to pin)
|
- [ ] `add_schematic_connection` works (pin to pin)
|
||||||
- [ ] Wires appear in KiCad schematic
|
- [ ] Wires appear in KiCad schematic
|
||||||
@@ -572,6 +607,7 @@ Test complete workflows:
|
|||||||
- [ ] 3+ integration tests passing
|
- [ ] 3+ integration tests passing
|
||||||
|
|
||||||
### Phase 2 Success:
|
### Phase 2 Success:
|
||||||
|
|
||||||
- [ ] Net labels work (VCC, GND, etc.)
|
- [ ] Net labels work (VCC, GND, etc.)
|
||||||
- [ ] Multiple components on same net
|
- [ ] Multiple components on same net
|
||||||
- [ ] `get_net_connections` returns correct results
|
- [ ] `get_net_connections` returns correct results
|
||||||
@@ -579,12 +615,14 @@ Test complete workflows:
|
|||||||
- [ ] 5+ integration tests passing
|
- [ ] 5+ integration tests passing
|
||||||
|
|
||||||
### Phase 3 Success:
|
### Phase 3 Success:
|
||||||
|
|
||||||
- [ ] Junctions at wire intersections
|
- [ ] Junctions at wire intersections
|
||||||
- [ ] Orthogonal routing preferred
|
- [ ] Orthogonal routing preferred
|
||||||
- [ ] No-connect flags on unused pins
|
- [ ] No-connect flags on unused pins
|
||||||
- [ ] 10+ integration tests passing
|
- [ ] 10+ integration tests passing
|
||||||
|
|
||||||
### Phase 4 Success:
|
### Phase 4 Success:
|
||||||
|
|
||||||
- [ ] ERC detects errors
|
- [ ] ERC detects errors
|
||||||
- [ ] 95%+ test coverage
|
- [ ] 95%+ test coverage
|
||||||
- [ ] Complete documentation
|
- [ ] Complete documentation
|
||||||
@@ -595,7 +633,7 @@ Test complete workflows:
|
|||||||
## Risk Assessment
|
## Risk Assessment
|
||||||
|
|
||||||
| Risk | Probability | Impact | Mitigation |
|
| Risk | Probability | Impact | Mitigation |
|
||||||
|------|------------|--------|------------|
|
| ------------------------- | ----------- | ------ | -------------------------------- |
|
||||||
| kicad-skip lacks wire API | High | High | Use S-expression fallback |
|
| kicad-skip lacks wire API | High | High | Use S-expression fallback |
|
||||||
| Pin discovery complex | Medium | Medium | Test with multiple symbol types |
|
| Pin discovery complex | Medium | Medium | Test with multiple symbol types |
|
||||||
| Rotation math errors | Medium | High | Extensive testing, validation |
|
| Rotation math errors | Medium | High | Extensive testing, validation |
|
||||||
@@ -607,11 +645,13 @@ Test complete workflows:
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
**Required:**
|
**Required:**
|
||||||
|
|
||||||
- kicad-skip >= 0.1.0 (or compatible)
|
- kicad-skip >= 0.1.0 (or compatible)
|
||||||
- sexpdata (already dependency for dynamic loading)
|
- sexpdata (already dependency for dynamic loading)
|
||||||
- Python 3.8+
|
- Python 3.8+
|
||||||
|
|
||||||
**Optional:**
|
**Optional:**
|
||||||
|
|
||||||
- KiCad CLI for validation (`kicad-cli sch export netlist`)
|
- KiCad CLI for validation (`kicad-cli sch export netlist`)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -658,6 +698,7 @@ Test complete workflows:
|
|||||||
**For Issue #26:**
|
**For Issue #26:**
|
||||||
|
|
||||||
Update users that:
|
Update users that:
|
||||||
|
|
||||||
- ✅ Component placement is DONE (with 10,000+ symbols)
|
- ✅ Component placement is DONE (with 10,000+ symbols)
|
||||||
- ⏳ Wire/connection tools are IN PROGRESS
|
- ⏳ Wire/connection tools are IN PROGRESS
|
||||||
- 📅 Estimated completion: 2-3 weeks for core functionality
|
- 📅 Estimated completion: 2-3 weeks for core functionality
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ The schematic workflow was completely broken due to incorrect usage of the kicad
|
|||||||
The kicad-skip library **does not support creating symbols from scratch**. The only way to add symbols is by **cloning existing symbol instances**.
|
The kicad-skip library **does not support creating symbols from scratch**. The only way to add symbols is by **cloning existing symbol instances**.
|
||||||
|
|
||||||
From kicad-skip documentation:
|
From kicad-skip documentation:
|
||||||
|
|
||||||
> "symbols: these don't have a new()" because they require complex mappings to library elements, pins, and properties.
|
> "symbols: these don't have a new()" because they require complex mappings to library elements, pins, and properties.
|
||||||
|
|
||||||
## Solution
|
## Solution
|
||||||
@@ -21,6 +22,7 @@ From kicad-skip documentation:
|
|||||||
### 1. Template-Based Approach
|
### 1. Template-Based Approach
|
||||||
|
|
||||||
Created a template schematic (`python/templates/template_with_symbols.kicad_sch`) with:
|
Created a template schematic (`python/templates/template_with_symbols.kicad_sch`) with:
|
||||||
|
|
||||||
- Complete `lib_symbols` section defining R, C, LED symbols
|
- Complete `lib_symbols` section defining R, C, LED symbols
|
||||||
- Three template symbol instances placed off-screen at (-100, -110, -120)
|
- Three template symbol instances placed off-screen at (-100, -110, -120)
|
||||||
- Template symbols marked as `dnp yes`, `in_bom no`, `on_board no` so they don't interfere
|
- Template symbols marked as `dnp yes`, `in_bom no`, `on_board no` so they don't interfere
|
||||||
@@ -28,15 +30,18 @@ Created a template schematic (`python/templates/template_with_symbols.kicad_sch`
|
|||||||
### 2. Updated Files
|
### 2. Updated Files
|
||||||
|
|
||||||
**python/commands/project.py:**
|
**python/commands/project.py:**
|
||||||
|
|
||||||
- Now creates both `.kicad_pcb` AND `.kicad_sch` files
|
- Now creates both `.kicad_pcb` AND `.kicad_sch` files
|
||||||
- Project file includes schematic reference in `sheets` array
|
- Project file includes schematic reference in `sheets` array
|
||||||
- Copies template schematic with cloneable symbols
|
- Copies template schematic with cloneable symbols
|
||||||
|
|
||||||
**python/commands/schematic.py:**
|
**python/commands/schematic.py:**
|
||||||
|
|
||||||
- Uses template file instead of creating from scratch
|
- Uses template file instead of creating from scratch
|
||||||
- Proper minimal schematic structure when template unavailable
|
- Proper minimal schematic structure when template unavailable
|
||||||
|
|
||||||
**python/commands/component_schematic.py:**
|
**python/commands/component_schematic.py:**
|
||||||
|
|
||||||
- Completely rewritten to use `clone()` API
|
- Completely rewritten to use `clone()` API
|
||||||
- Maps component types to template symbols
|
- Maps component types to template symbols
|
||||||
- Proper UUID generation for each cloned symbol
|
- Proper UUID generation for each cloned symbol
|
||||||
@@ -78,17 +83,20 @@ SchematicManager.save_schematic(sch, result['project']['schematicPath'])
|
|||||||
## Supported Component Types
|
## Supported Component Types
|
||||||
|
|
||||||
Currently supported template symbols:
|
Currently supported template symbols:
|
||||||
|
|
||||||
- `R` - Resistor (maps to `_TEMPLATE_R`)
|
- `R` - Resistor (maps to `_TEMPLATE_R`)
|
||||||
- `C` - Capacitor (maps to `_TEMPLATE_C`)
|
- `C` - Capacitor (maps to `_TEMPLATE_C`)
|
||||||
- `D` or `LED` - LED (maps to `_TEMPLATE_D`)
|
- `D` or `LED` - LED (maps to `_TEMPLATE_D`)
|
||||||
|
|
||||||
To add more component types, update:
|
To add more component types, update:
|
||||||
|
|
||||||
1. `python/templates/template_with_symbols.kicad_sch` - Add lib_symbol definition and template instance
|
1. `python/templates/template_with_symbols.kicad_sch` - Add lib_symbol definition and template instance
|
||||||
2. `python/commands/component_schematic.py` - Add mapping in `TEMPLATE_MAP`
|
2. `python/commands/component_schematic.py` - Add mapping in `TEMPLATE_MAP`
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Comprehensive test created at `/tmp/test_schematic_workflow.py`:
|
Comprehensive test created at `/tmp/test_schematic_workflow.py`:
|
||||||
|
|
||||||
- Creates project with schematic
|
- Creates project with schematic
|
||||||
- Loads schematic
|
- Loads schematic
|
||||||
- Adds R, C, LED components
|
- Adds R, C, LED components
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Week 1 - Session 1 Summary
|
# Week 1 - Session 1 Summary
|
||||||
|
|
||||||
**Date:** October 25, 2025
|
**Date:** October 25, 2025
|
||||||
**Status:** ✅ **EXCELLENT PROGRESS**
|
**Status:** ✅ **EXCELLENT PROGRESS**
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
Resurrect the KiCAD MCP Server and transform it from a Windows-only "KiCAD automation wrapper" into a **true AI-assisted PCB design companion** for hobbyist users (novice to intermediate).
|
Resurrect the KiCAD MCP Server and transform it from a Windows-only "KiCAD automation wrapper" into a **true AI-assisted PCB design companion** for hobbyist users (novice to intermediate).
|
||||||
|
|
||||||
**Strategic Focus:**
|
**Strategic Focus:**
|
||||||
|
|
||||||
- Linux-first platform support
|
- Linux-first platform support
|
||||||
- JLCPCB & Digikey integration
|
- JLCPCB & Digikey integration
|
||||||
- End-to-end PCB design workflow
|
- End-to-end PCB design workflow
|
||||||
@@ -21,12 +23,14 @@ Resurrect the KiCAD MCP Server and transform it from a Windows-only "KiCAD autom
|
|||||||
### 1. **Complete Project Analysis** 📊
|
### 1. **Complete Project Analysis** 📊
|
||||||
|
|
||||||
Created comprehensive documentation:
|
Created comprehensive documentation:
|
||||||
|
|
||||||
- ✅ Full codebase exploration (6 tool categories, 9 Python command modules)
|
- ✅ Full codebase exploration (6 tool categories, 9 Python command modules)
|
||||||
- ✅ Identified critical issues (deprecated SWIG API, Windows-only paths)
|
- ✅ Identified critical issues (deprecated SWIG API, Windows-only paths)
|
||||||
- ✅ Researched KiCAD IPC API, JLCPCB API, Digikey API
|
- ✅ Researched KiCAD IPC API, JLCPCB API, Digikey API
|
||||||
- ✅ Researched MCP best practices
|
- ✅ Researched MCP best practices
|
||||||
|
|
||||||
**Key Findings:**
|
**Key Findings:**
|
||||||
|
|
||||||
- SWIG Python bindings are DEPRECATED (will be removed in KiCAD 10.0)
|
- SWIG Python bindings are DEPRECATED (will be removed in KiCAD 10.0)
|
||||||
- Current architecture works but is Windows-centric
|
- Current architecture works but is Windows-centric
|
||||||
- Missing core AI-assisted features (part selection, BOM management)
|
- Missing core AI-assisted features (part selection, BOM management)
|
||||||
@@ -38,22 +42,26 @@ Created comprehensive documentation:
|
|||||||
Designed comprehensive roadmap in 4 phases:
|
Designed comprehensive roadmap in 4 phases:
|
||||||
|
|
||||||
#### **Phase 1: Foundation & Migration (Weeks 1-4)**
|
#### **Phase 1: Foundation & Migration (Weeks 1-4)**
|
||||||
|
|
||||||
- Linux compatibility
|
- Linux compatibility
|
||||||
- KiCAD IPC API migration
|
- KiCAD IPC API migration
|
||||||
- Performance improvements (caching, async)
|
- Performance improvements (caching, async)
|
||||||
|
|
||||||
#### **Phase 2: Core AI Features (Weeks 5-8)**
|
#### **Phase 2: Core AI Features (Weeks 5-8)**
|
||||||
|
|
||||||
- JLCPCB integration (parts library + pricing)
|
- JLCPCB integration (parts library + pricing)
|
||||||
- Digikey integration (parametric search)
|
- Digikey integration (parametric search)
|
||||||
- Smart BOM management
|
- Smart BOM management
|
||||||
- Design pattern library
|
- Design pattern library
|
||||||
|
|
||||||
#### **Phase 3: Novice-Friendly Workflows (Weeks 9-11)**
|
#### **Phase 3: Novice-Friendly Workflows (Weeks 9-11)**
|
||||||
|
|
||||||
- Guided step-by-step workflows
|
- Guided step-by-step workflows
|
||||||
- Visual feedback system
|
- Visual feedback system
|
||||||
- Intelligent error recovery
|
- Intelligent error recovery
|
||||||
|
|
||||||
#### **Phase 4: Polish & Launch (Week 12)**
|
#### **Phase 4: Polish & Launch (Week 12)**
|
||||||
|
|
||||||
- Testing, documentation, community building
|
- Testing, documentation, community building
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -63,6 +71,7 @@ Designed comprehensive roadmap in 4 phases:
|
|||||||
Created complete cross-platform support:
|
Created complete cross-platform support:
|
||||||
|
|
||||||
**Files Created:**
|
**Files Created:**
|
||||||
|
|
||||||
- ✅ `docs/LINUX_COMPATIBILITY_AUDIT.md` - Comprehensive audit report
|
- ✅ `docs/LINUX_COMPATIBILITY_AUDIT.md` - Comprehensive audit report
|
||||||
- ✅ `python/utils/platform_helper.py` - Cross-platform path detection
|
- ✅ `python/utils/platform_helper.py` - Cross-platform path detection
|
||||||
- ✅ `config/linux-config.example.json` - Linux configuration template
|
- ✅ `config/linux-config.example.json` - Linux configuration template
|
||||||
@@ -70,6 +79,7 @@ Created complete cross-platform support:
|
|||||||
- ✅ `config/macos-config.example.json` - macOS configuration template
|
- ✅ `config/macos-config.example.json` - macOS configuration template
|
||||||
|
|
||||||
**Platform Helper Features:**
|
**Platform Helper Features:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
PlatformHelper.get_config_dir() # ~/.config/kicad-mcp on Linux
|
PlatformHelper.get_config_dir() # ~/.config/kicad-mcp on Linux
|
||||||
PlatformHelper.get_log_dir() # ~/.config/kicad-mcp/logs
|
PlatformHelper.get_log_dir() # ~/.config/kicad-mcp/logs
|
||||||
@@ -86,6 +96,7 @@ Created GitHub Actions workflow:
|
|||||||
**File:** `.github/workflows/ci.yml`
|
**File:** `.github/workflows/ci.yml`
|
||||||
|
|
||||||
**Testing Matrix:**
|
**Testing Matrix:**
|
||||||
|
|
||||||
- TypeScript build on Ubuntu 24.04, 22.04, Windows, macOS
|
- TypeScript build on Ubuntu 24.04, 22.04, Windows, macOS
|
||||||
- Python tests on Python 3.10, 3.11, 3.12
|
- Python tests on Python 3.10, 3.11, 3.12
|
||||||
- Integration tests with KiCAD 9.0 installation
|
- Integration tests with KiCAD 9.0 installation
|
||||||
@@ -102,12 +113,14 @@ Created GitHub Actions workflow:
|
|||||||
Set up comprehensive testing infrastructure:
|
Set up comprehensive testing infrastructure:
|
||||||
|
|
||||||
**Files Created:**
|
**Files Created:**
|
||||||
|
|
||||||
- ✅ `pytest.ini` - Pytest configuration
|
- ✅ `pytest.ini` - Pytest configuration
|
||||||
- ✅ `requirements.txt` - Production dependencies
|
- ✅ `requirements.txt` - Production dependencies
|
||||||
- ✅ `requirements-dev.txt` - Development dependencies
|
- ✅ `requirements-dev.txt` - Development dependencies
|
||||||
- ✅ `tests/test_platform_helper.py` - 20+ unit tests
|
- ✅ `tests/test_platform_helper.py` - 20+ unit tests
|
||||||
|
|
||||||
**Test Categories:**
|
**Test Categories:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@pytest.mark.unit # Fast, no external dependencies
|
@pytest.mark.unit # Fast, no external dependencies
|
||||||
@pytest.mark.integration # Requires KiCAD
|
@pytest.mark.integration # Requires KiCAD
|
||||||
@@ -116,6 +129,7 @@ Set up comprehensive testing infrastructure:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Test Results:**
|
**Test Results:**
|
||||||
|
|
||||||
```
|
```
|
||||||
✅ Platform detection works correctly
|
✅ Platform detection works correctly
|
||||||
✅ Config directories follow XDG spec on Linux
|
✅ Config directories follow XDG spec on Linux
|
||||||
@@ -132,6 +146,7 @@ Created contributor guide:
|
|||||||
**File:** `CONTRIBUTING.md`
|
**File:** `CONTRIBUTING.md`
|
||||||
|
|
||||||
**Includes:**
|
**Includes:**
|
||||||
|
|
||||||
- Platform-specific setup instructions (Linux/Windows/macOS)
|
- Platform-specific setup instructions (Linux/Windows/macOS)
|
||||||
- Project structure overview
|
- Project structure overview
|
||||||
- Development workflow
|
- Development workflow
|
||||||
@@ -144,6 +159,7 @@ Created contributor guide:
|
|||||||
### 7. **Dependencies Management** 📦
|
### 7. **Dependencies Management** 📦
|
||||||
|
|
||||||
**Production Dependencies (requirements.txt):**
|
**Production Dependencies (requirements.txt):**
|
||||||
|
|
||||||
```
|
```
|
||||||
kicad-skip>=0.1.0 # Schematic manipulation
|
kicad-skip>=0.1.0 # Schematic manipulation
|
||||||
Pillow>=9.0.0 # Image processing
|
Pillow>=9.0.0 # Image processing
|
||||||
@@ -154,6 +170,7 @@ python-dotenv>=1.0.0 # Config management
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Development Dependencies:**
|
**Development Dependencies:**
|
||||||
|
|
||||||
```
|
```
|
||||||
pytest>=7.4.0 # Testing
|
pytest>=7.4.0 # Testing
|
||||||
black>=23.7.0 # Code formatting
|
black>=23.7.0 # Code formatting
|
||||||
@@ -323,6 +340,7 @@ Node: 18.x, 20.x, 22.x
|
|||||||
## 🚀 Impact Assessment
|
## 🚀 Impact Assessment
|
||||||
|
|
||||||
### Before Today
|
### Before Today
|
||||||
|
|
||||||
- ❌ Windows-only
|
- ❌ Windows-only
|
||||||
- ❌ No CI/CD
|
- ❌ No CI/CD
|
||||||
- ❌ No tests
|
- ❌ No tests
|
||||||
@@ -330,6 +348,7 @@ Node: 18.x, 20.x, 22.x
|
|||||||
- ❌ No developer documentation
|
- ❌ No developer documentation
|
||||||
|
|
||||||
### After Today
|
### After Today
|
||||||
|
|
||||||
- ✅ Cross-platform (Linux/Windows/macOS)
|
- ✅ Cross-platform (Linux/Windows/macOS)
|
||||||
- ✅ GitHub Actions CI/CD
|
- ✅ GitHub Actions CI/CD
|
||||||
- ✅ 20+ unit tests with pytest
|
- ✅ 20+ unit tests with pytest
|
||||||
@@ -346,24 +365,28 @@ Node: 18.x, 20.x, 22.x
|
|||||||
## 💡 Key Decisions Made
|
## 💡 Key Decisions Made
|
||||||
|
|
||||||
### 1. **IPC API Migration: Proceed Immediately** ✅
|
### 1. **IPC API Migration: Proceed Immediately** ✅
|
||||||
|
|
||||||
- SWIG is deprecated, will be removed in KiCAD 10.0
|
- SWIG is deprecated, will be removed in KiCAD 10.0
|
||||||
- IPC API is stable, officially supported
|
- IPC API is stable, officially supported
|
||||||
- Better performance and cross-language support
|
- Better performance and cross-language support
|
||||||
- Decision: Migrate in Week 2-3
|
- Decision: Migrate in Week 2-3
|
||||||
|
|
||||||
### 2. **Linux-First Approach** ✅
|
### 2. **Linux-First Approach** ✅
|
||||||
|
|
||||||
- Hobbyists often use Linux
|
- Hobbyists often use Linux
|
||||||
- Better for open-source development
|
- Better for open-source development
|
||||||
- Easier CI/CD with GitHub Actions
|
- Easier CI/CD with GitHub Actions
|
||||||
- Decision: Linux is primary development platform
|
- Decision: Linux is primary development platform
|
||||||
|
|
||||||
### 3. **JLCPCB Integration Priority** ✅
|
### 3. **JLCPCB Integration Priority** ✅
|
||||||
|
|
||||||
- Hobbyists love JLCPCB for cheap assembly
|
- Hobbyists love JLCPCB for cheap assembly
|
||||||
- "Basic parts" filter is critical
|
- "Basic parts" filter is critical
|
||||||
- Better stock than Digikey for hobbyists
|
- Better stock than Digikey for hobbyists
|
||||||
- Decision: JLCPCB before Digikey
|
- Decision: JLCPCB before Digikey
|
||||||
|
|
||||||
### 4. **Pytest over unittest** ✅
|
### 4. **Pytest over unittest** ✅
|
||||||
|
|
||||||
- More Pythonic
|
- More Pythonic
|
||||||
- Better fixtures and parametrization
|
- Better fixtures and parametrization
|
||||||
- Industry standard
|
- Industry standard
|
||||||
@@ -392,15 +415,19 @@ Node: 18.x, 20.x, 22.x
|
|||||||
## 🎉 Highlights
|
## 🎉 Highlights
|
||||||
|
|
||||||
### Biggest Win
|
### Biggest Win
|
||||||
|
|
||||||
✨ **Complete cross-platform infrastructure in one session**
|
✨ **Complete cross-platform infrastructure in one session**
|
||||||
|
|
||||||
### Most Valuable Addition
|
### Most Valuable Addition
|
||||||
|
|
||||||
🔧 **PlatformHelper utility** - Solves path issues elegantly
|
🔧 **PlatformHelper utility** - Solves path issues elegantly
|
||||||
|
|
||||||
### Best Decision
|
### Best Decision
|
||||||
|
|
||||||
🎯 **Creating comprehensive plan first** - Clear roadmap for 12 weeks
|
🎯 **Creating comprehensive plan first** - Clear roadmap for 12 weeks
|
||||||
|
|
||||||
### Unexpected Discovery
|
### Unexpected Discovery
|
||||||
|
|
||||||
⚠️ **SWIG deprecation** - Would have been a nasty surprise later!
|
⚠️ **SWIG deprecation** - Would have been a nasty surprise later!
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -408,11 +435,13 @@ Node: 18.x, 20.x, 22.x
|
|||||||
## 🤝 Collaboration Notes
|
## 🤝 Collaboration Notes
|
||||||
|
|
||||||
### What Went Well
|
### What Went Well
|
||||||
|
|
||||||
- Clear requirements from user
|
- Clear requirements from user
|
||||||
- Good research phase before coding
|
- Good research phase before coding
|
||||||
- Incremental progress with testing
|
- Incremental progress with testing
|
||||||
|
|
||||||
### What to Improve
|
### What to Improve
|
||||||
|
|
||||||
- Need actual Ubuntu 24.04 testing
|
- Need actual Ubuntu 24.04 testing
|
||||||
- Should run pytest suite
|
- Should run pytest suite
|
||||||
- Need to test KiCAD 9.0 integration
|
- Need to test KiCAD 9.0 integration
|
||||||
@@ -422,6 +451,7 @@ Node: 18.x, 20.x, 22.x
|
|||||||
## 📅 Schedule Status
|
## 📅 Schedule Status
|
||||||
|
|
||||||
### Week 1 Goals
|
### Week 1 Goals
|
||||||
|
|
||||||
- [x] Linux compatibility audit (**100% complete**)
|
- [x] Linux compatibility audit (**100% complete**)
|
||||||
- [x] CI/CD setup (**100% complete**)
|
- [x] CI/CD setup (**100% complete**)
|
||||||
- [x] Development infrastructure (**100% complete**)
|
- [x] Development infrastructure (**100% complete**)
|
||||||
@@ -448,16 +478,19 @@ Node: 18.x, 20.x, 22.x
|
|||||||
## 📝 Notes for Future
|
## 📝 Notes for Future
|
||||||
|
|
||||||
### Architecture Decisions to Make
|
### Architecture Decisions to Make
|
||||||
|
|
||||||
- [ ] Redis vs in-memory cache?
|
- [ ] Redis vs in-memory cache?
|
||||||
- [ ] Session storage approach?
|
- [ ] Session storage approach?
|
||||||
- [ ] WebSocket vs STDIO for future scaling?
|
- [ ] WebSocket vs STDIO for future scaling?
|
||||||
|
|
||||||
### Dependencies to Research
|
### Dependencies to Research
|
||||||
|
|
||||||
- [ ] JLCPCB API client library (exists?)
|
- [ ] JLCPCB API client library (exists?)
|
||||||
- [ ] Digikey API v3 (issus/DigiKeyApi looks good)
|
- [ ] Digikey API v3 (issus/DigiKeyApi looks good)
|
||||||
- [ ] kicad-python 0.5.0 compatibility
|
- [ ] kicad-python 0.5.0 compatibility
|
||||||
|
|
||||||
### Questions to Answer
|
### Questions to Answer
|
||||||
|
|
||||||
- [ ] How to handle KiCAD running vs not running (IPC requirement)?
|
- [ ] How to handle KiCAD running vs not running (IPC requirement)?
|
||||||
- [ ] Should we support both SWIG and IPC during migration?
|
- [ ] Should we support both SWIG and IPC during migration?
|
||||||
- [ ] BOM format standardization?
|
- [ ] BOM format standardization?
|
||||||
@@ -467,7 +500,7 @@ Node: 18.x, 20.x, 22.x
|
|||||||
## 🏆 Success Metrics Achieved Today
|
## 🏆 Success Metrics Achieved Today
|
||||||
|
|
||||||
| Metric | Target | Achieved | Status |
|
| Metric | Target | Achieved | Status |
|
||||||
|--------|--------|----------|--------|
|
| ---------------- | --------------- | -------------- | ------ |
|
||||||
| Platform support | Linux primary | ✅ Linux ready | ✅ |
|
| Platform support | Linux primary | ✅ Linux ready | ✅ |
|
||||||
| CI/CD pipeline | GitHub Actions | ✅ Complete | ✅ |
|
| CI/CD pipeline | GitHub Actions | ✅ Complete | ✅ |
|
||||||
| Test coverage | Setup pytest | ✅ 20+ tests | ✅ |
|
| Test coverage | Setup pytest | ✅ 20+ tests | ✅ |
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Week 1 - Session 2 Summary
|
# Week 1 - Session 2 Summary
|
||||||
|
|
||||||
**Date:** October 25, 2025 (Afternoon)
|
**Date:** October 25, 2025 (Afternoon)
|
||||||
**Status:** 🚀 **OUTSTANDING PROGRESS**
|
**Status:** 🚀 **OUTSTANDING PROGRESS**
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@
|
|||||||
## 🎯 Session Goals
|
## 🎯 Session Goals
|
||||||
|
|
||||||
Continue Week 1 implementation while user installs KiCAD:
|
Continue Week 1 implementation while user installs KiCAD:
|
||||||
|
|
||||||
1. Update README with comprehensive Linux guide
|
1. Update README with comprehensive Linux guide
|
||||||
2. Create installation scripts
|
2. Create installation scripts
|
||||||
3. Begin IPC API preparation
|
3. Begin IPC API preparation
|
||||||
@@ -21,6 +23,7 @@ Continue Week 1 implementation while user installs KiCAD:
|
|||||||
**File:** `README.md`
|
**File:** `README.md`
|
||||||
|
|
||||||
**Changes:**
|
**Changes:**
|
||||||
|
|
||||||
- ✅ Updated project status to reflect v2.0 rebuild
|
- ✅ Updated project status to reflect v2.0 rebuild
|
||||||
- ✅ Added collapsible platform-specific installation sections:
|
- ✅ Added collapsible platform-specific installation sections:
|
||||||
- 🐧 **Linux (Ubuntu/Debian)** - Primary, detailed
|
- 🐧 **Linux (Ubuntu/Debian)** - Primary, detailed
|
||||||
@@ -39,6 +42,7 @@ Continue Week 1 implementation while user installs KiCAD:
|
|||||||
**File:** `scripts/install-linux.sh`
|
**File:** `scripts/install-linux.sh`
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
|
|
||||||
- ✅ Fully automated Ubuntu/Debian installation
|
- ✅ Fully automated Ubuntu/Debian installation
|
||||||
- ✅ Color-coded output (info/success/warning/error)
|
- ✅ Color-coded output (info/success/warning/error)
|
||||||
- ✅ Safety checks (platform detection, command validation)
|
- ✅ Safety checks (platform detection, command validation)
|
||||||
@@ -51,6 +55,7 @@ Continue Week 1 implementation while user installs KiCAD:
|
|||||||
- ✅ Helpful next-steps guidance
|
- ✅ Helpful next-steps guidance
|
||||||
|
|
||||||
**Usage:**
|
**Usage:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd kicad-mcp-server
|
cd kicad-mcp-server
|
||||||
./scripts/install-linux.sh
|
./scripts/install-linux.sh
|
||||||
@@ -65,6 +70,7 @@ cd kicad-mcp-server
|
|||||||
**File:** `.pre-commit-config.yaml`
|
**File:** `.pre-commit-config.yaml`
|
||||||
|
|
||||||
**Hooks Added:**
|
**Hooks Added:**
|
||||||
|
|
||||||
- ✅ **Python:**
|
- ✅ **Python:**
|
||||||
- Black (code formatting)
|
- Black (code formatting)
|
||||||
- isort (import sorting)
|
- isort (import sorting)
|
||||||
@@ -84,6 +90,7 @@ cd kicad-mcp-server
|
|||||||
- Markdownlint (formatting)
|
- Markdownlint (formatting)
|
||||||
|
|
||||||
**Setup:**
|
**Setup:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install pre-commit
|
pip install pre-commit
|
||||||
pre-commit install
|
pre-commit install
|
||||||
@@ -98,6 +105,7 @@ pre-commit install
|
|||||||
**File:** `docs/IPC_API_MIGRATION_PLAN.md`
|
**File:** `docs/IPC_API_MIGRATION_PLAN.md`
|
||||||
|
|
||||||
**Comprehensive 30-page migration guide:**
|
**Comprehensive 30-page migration guide:**
|
||||||
|
|
||||||
- ✅ Why migrate (SWIG deprecation analysis)
|
- ✅ Why migrate (SWIG deprecation analysis)
|
||||||
- ✅ IPC API architecture overview
|
- ✅ IPC API architecture overview
|
||||||
- ✅ 4-phase migration strategy (10 days)
|
- ✅ 4-phase migration strategy (10 days)
|
||||||
@@ -108,6 +116,7 @@ pre-commit install
|
|||||||
- ✅ Timeline with day-by-day tasks
|
- ✅ Timeline with day-by-day tasks
|
||||||
|
|
||||||
**Key Insights:**
|
**Key Insights:**
|
||||||
|
|
||||||
- SWIG will be removed in KiCAD 10.0
|
- SWIG will be removed in KiCAD 10.0
|
||||||
- IPC is faster for some operations
|
- IPC is faster for some operations
|
||||||
- Protocol Buffers ensure API stability
|
- Protocol Buffers ensure API stability
|
||||||
@@ -156,6 +165,7 @@ pre-commit install
|
|||||||
**Total Lines of Code:** ~800 lines
|
**Total Lines of Code:** ~800 lines
|
||||||
|
|
||||||
**Architecture:**
|
**Architecture:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from kicad_api import create_backend
|
from kicad_api import create_backend
|
||||||
|
|
||||||
@@ -173,6 +183,7 @@ if backend.connect():
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Key Features:**
|
**Key Features:**
|
||||||
|
|
||||||
- ✅ Abstraction allows painless migration
|
- ✅ Abstraction allows painless migration
|
||||||
- ✅ Both backends can coexist during transition
|
- ✅ Both backends can coexist during transition
|
||||||
- ✅ Easy testing (compare SWIG vs IPC outputs)
|
- ✅ Easy testing (compare SWIG vs IPC outputs)
|
||||||
@@ -187,6 +198,7 @@ if backend.connect():
|
|||||||
**File:** `package.json`
|
**File:** `package.json`
|
||||||
|
|
||||||
**Improvements:**
|
**Improvements:**
|
||||||
|
|
||||||
- ✅ Version bumped to `2.0.0-alpha.1`
|
- ✅ Version bumped to `2.0.0-alpha.1`
|
||||||
- ✅ Better description
|
- ✅ Better description
|
||||||
- ✅ Enhanced npm scripts:
|
- ✅ Enhanced npm scripts:
|
||||||
@@ -211,6 +223,7 @@ if backend.connect():
|
|||||||
### Files Created/Modified (Session 2)
|
### Files Created/Modified (Session 2)
|
||||||
|
|
||||||
**New Files (10):**
|
**New Files (10):**
|
||||||
|
|
||||||
```
|
```
|
||||||
docs/IPC_API_MIGRATION_PLAN.md # 500+ lines
|
docs/IPC_API_MIGRATION_PLAN.md # 500+ lines
|
||||||
docs/WEEK1_SESSION2_SUMMARY.md # This file
|
docs/WEEK1_SESSION2_SUMMARY.md # This file
|
||||||
@@ -224,6 +237,7 @@ python/kicad_api/swig_backend.py # 220 lines
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Modified Files (2):**
|
**Modified Files (2):**
|
||||||
|
|
||||||
```
|
```
|
||||||
README.md # Major rewrite
|
README.md # Major rewrite
|
||||||
package.json # Enhanced scripts
|
package.json # Enhanced scripts
|
||||||
@@ -247,7 +261,7 @@ package.json # Enhanced scripts
|
|||||||
### Progress: **95% Complete** ████████████░
|
### Progress: **95% Complete** ████████████░
|
||||||
|
|
||||||
| Task | Status |
|
| Task | Status |
|
||||||
|------|--------|
|
| --------------------- | -------------------------------- |
|
||||||
| Linux compatibility | ✅ Complete |
|
| Linux compatibility | ✅ Complete |
|
||||||
| CI/CD pipeline | ✅ Complete |
|
| CI/CD pipeline | ✅ Complete |
|
||||||
| Cross-platform paths | ✅ Complete |
|
| Cross-platform paths | ✅ Complete |
|
||||||
@@ -270,6 +284,7 @@ package.json # Enhanced scripts
|
|||||||
### IPC API Migration Prep ✅
|
### IPC API Migration Prep ✅
|
||||||
|
|
||||||
Everything is in place to begin migration:
|
Everything is in place to begin migration:
|
||||||
|
|
||||||
- ✅ Abstraction layer architecture defined
|
- ✅ Abstraction layer architecture defined
|
||||||
- ✅ Base classes and interfaces ready
|
- ✅ Base classes and interfaces ready
|
||||||
- ✅ Factory pattern for backend selection
|
- ✅ Factory pattern for backend selection
|
||||||
@@ -278,6 +293,7 @@ Everything is in place to begin migration:
|
|||||||
- ✅ Comprehensive migration plan documented
|
- ✅ Comprehensive migration plan documented
|
||||||
|
|
||||||
**Week 2 kickoff tasks:**
|
**Week 2 kickoff tasks:**
|
||||||
|
|
||||||
1. Install `kicad-python` package
|
1. Install `kicad-python` package
|
||||||
2. Test IPC connection to running KiCAD
|
2. Test IPC connection to running KiCAD
|
||||||
3. Begin porting `project.py` module
|
3. Begin porting `project.py` module
|
||||||
@@ -288,15 +304,19 @@ Everything is in place to begin migration:
|
|||||||
## 💡 Key Insights from Session 2
|
## 💡 Key Insights from Session 2
|
||||||
|
|
||||||
### 1. **Installation Automation**
|
### 1. **Installation Automation**
|
||||||
|
|
||||||
The bash script reduces setup time from 30+ minutes to < 10 minutes with zero manual intervention.
|
The bash script reduces setup time from 30+ minutes to < 10 minutes with zero manual intervention.
|
||||||
|
|
||||||
### 2. **Pre-Commit Hooks**
|
### 2. **Pre-Commit Hooks**
|
||||||
|
|
||||||
Automatic code quality checks prevent bugs before they're committed. This will save hours in code review.
|
Automatic code quality checks prevent bugs before they're committed. This will save hours in code review.
|
||||||
|
|
||||||
### 3. **Abstraction Pattern**
|
### 3. **Abstraction Pattern**
|
||||||
|
|
||||||
The backend abstraction is elegant - allows gradual migration without breaking existing functionality. Users won't notice the transition.
|
The backend abstraction is elegant - allows gradual migration without breaking existing functionality. Users won't notice the transition.
|
||||||
|
|
||||||
### 4. **Documentation Quality**
|
### 4. **Documentation Quality**
|
||||||
|
|
||||||
The IPC migration plan is thorough enough that another developer could execute it independently.
|
The IPC migration plan is thorough enough that another developer could execute it independently.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -308,26 +328,31 @@ The IPC migration plan is thorough enough that another developer could execute i
|
|||||||
You can immediately test:
|
You can immediately test:
|
||||||
|
|
||||||
**1. Platform Helper:**
|
**1. Platform Helper:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 python/utils/platform_helper.py
|
python3 python/utils/platform_helper.py
|
||||||
```
|
```
|
||||||
|
|
||||||
**2. Backend Detection:**
|
**2. Backend Detection:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 python/kicad_api/factory.py
|
python3 python/kicad_api/factory.py
|
||||||
```
|
```
|
||||||
|
|
||||||
**3. Installation Script:**
|
**3. Installation Script:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/install-linux.sh
|
./scripts/install-linux.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
**4. Pytest Suite:**
|
**4. Pytest Suite:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pytest tests/ -v
|
pytest tests/ -v
|
||||||
```
|
```
|
||||||
|
|
||||||
**5. Pre-commit Hooks:**
|
**5. Pre-commit Hooks:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pre-commit run --all-files
|
pre-commit run --all-files
|
||||||
```
|
```
|
||||||
@@ -337,18 +362,22 @@ pre-commit run --all-files
|
|||||||
## 📈 Impact Assessment
|
## 📈 Impact Assessment
|
||||||
|
|
||||||
### Developer Onboarding
|
### Developer Onboarding
|
||||||
|
|
||||||
- **Before:** 2-3 hours setup, Windows-only, manual steps
|
- **Before:** 2-3 hours setup, Windows-only, manual steps
|
||||||
- **After:** 10 minutes automated, cross-platform, one script
|
- **After:** 10 minutes automated, cross-platform, one script
|
||||||
|
|
||||||
### Code Quality
|
### Code Quality
|
||||||
|
|
||||||
- **Before:** No automated checks, inconsistent style
|
- **Before:** No automated checks, inconsistent style
|
||||||
- **After:** Pre-commit hooks, 100% type hints, Black formatting
|
- **After:** Pre-commit hooks, 100% type hints, Black formatting
|
||||||
|
|
||||||
### Future-Proofing
|
### Future-Proofing
|
||||||
|
|
||||||
- **Before:** Deprecated SWIG API, no migration path
|
- **Before:** Deprecated SWIG API, no migration path
|
||||||
- **After:** IPC API ready, abstraction layer in place
|
- **After:** IPC API ready, abstraction layer in place
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
- **Before:** README only, Windows-focused
|
- **Before:** README only, Windows-focused
|
||||||
- **After:** 8 comprehensive docs, Linux-primary, migration guides
|
- **After:** 8 comprehensive docs, Linux-primary, migration guides
|
||||||
|
|
||||||
@@ -357,12 +386,14 @@ pre-commit run --all-files
|
|||||||
## 🎯 Next Actions
|
## 🎯 Next Actions
|
||||||
|
|
||||||
### Immediate (Tonight/Tomorrow)
|
### Immediate (Tonight/Tomorrow)
|
||||||
|
|
||||||
1. Install KiCAD 9.0 on your system
|
1. Install KiCAD 9.0 on your system
|
||||||
2. Run `./scripts/install-linux.sh`
|
2. Run `./scripts/install-linux.sh`
|
||||||
3. Test backend detection
|
3. Test backend detection
|
||||||
4. Verify pytest suite passes
|
4. Verify pytest suite passes
|
||||||
|
|
||||||
### Week 2 Start (Monday)
|
### Week 2 Start (Monday)
|
||||||
|
|
||||||
1. Install `kicad-python` package
|
1. Install `kicad-python` package
|
||||||
2. Test IPC connection
|
2. Test IPC connection
|
||||||
3. Begin project.py migration
|
3. Begin project.py migration
|
||||||
@@ -373,17 +404,20 @@ pre-commit run --all-files
|
|||||||
## 🏆 Session 2 Achievements
|
## 🏆 Session 2 Achievements
|
||||||
|
|
||||||
### Infrastructure
|
### Infrastructure
|
||||||
|
|
||||||
- ✅ Automated Linux installation
|
- ✅ Automated Linux installation
|
||||||
- ✅ Pre-commit hooks for code quality
|
- ✅ Pre-commit hooks for code quality
|
||||||
- ✅ Enhanced npm scripts
|
- ✅ Enhanced npm scripts
|
||||||
- ✅ IPC API abstraction layer (800+ lines)
|
- ✅ IPC API abstraction layer (800+ lines)
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
- ✅ Updated README (Linux-primary)
|
- ✅ Updated README (Linux-primary)
|
||||||
- ✅ 30-page IPC migration plan
|
- ✅ 30-page IPC migration plan
|
||||||
- ✅ Session summaries
|
- ✅ Session summaries
|
||||||
|
|
||||||
### Architecture
|
### Architecture
|
||||||
|
|
||||||
- ✅ Backend abstraction pattern
|
- ✅ Backend abstraction pattern
|
||||||
- ✅ Factory with auto-detection
|
- ✅ Factory with auto-detection
|
||||||
- ✅ SWIG backward compatibility
|
- ✅ SWIG backward compatibility
|
||||||
@@ -394,6 +428,7 @@ pre-commit run --all-files
|
|||||||
## 🎉 Overall Day Summary
|
## 🎉 Overall Day Summary
|
||||||
|
|
||||||
**Sessions 1+2 Combined:**
|
**Sessions 1+2 Combined:**
|
||||||
|
|
||||||
- ⏱️ **Time:** ~4-5 hours total
|
- ⏱️ **Time:** ~4-5 hours total
|
||||||
- 📝 **Files:** 27 created
|
- 📝 **Files:** 27 created
|
||||||
- 💻 **Code:** ~3,000+ lines
|
- 💻 **Code:** ~3,000+ lines
|
||||||
|
|||||||
@@ -108,25 +108,25 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
properties: {
|
properties: {
|
||||||
output_dir: {
|
output_dir: {
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Output directory path"
|
description: "Output directory path",
|
||||||
},
|
},
|
||||||
layers: {
|
layers: {
|
||||||
type: "array",
|
type: "array",
|
||||||
items: { type: "string" },
|
items: { type: "string" },
|
||||||
description: "Layers to export (default: all copper + silkscreen + mask)"
|
description: "Layers to export (default: all copper + silkscreen + mask)",
|
||||||
},
|
},
|
||||||
format: {
|
format: {
|
||||||
type: "string",
|
type: "string",
|
||||||
enum: ["rs274x", "x2"],
|
enum: ["rs274x", "x2"],
|
||||||
description: "Gerber format version"
|
description: "Gerber format version",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
required: ["output_dir"]
|
},
|
||||||
|
required: ["output_dir"],
|
||||||
},
|
},
|
||||||
handler: async (params) => {
|
handler: async (params) => {
|
||||||
// Your implementation
|
// Your implementation
|
||||||
return { success: true, files: ["..."] };
|
return { success: true, files: ["..."] };
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "export_drill",
|
name: "export_drill",
|
||||||
@@ -135,24 +135,31 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
output_dir: { type: "string" },
|
output_dir: { type: "string" },
|
||||||
format: { type: "string", enum: ["excellon", "excellon2"] }
|
format: { type: "string", enum: ["excellon", "excellon2"] },
|
||||||
},
|
},
|
||||||
required: ["output_dir"]
|
required: ["output_dir"],
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "export_bom",
|
name: "export_bom",
|
||||||
description: "Export bill of materials as CSV or XML",
|
description: "Export bill of materials as CSV or XML",
|
||||||
inputSchema: { /* ... */ },
|
inputSchema: {
|
||||||
handler: async (params) => { /* ... */ }
|
/* ... */
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
|
},
|
||||||
},
|
},
|
||||||
// ... more export tools
|
// ... more export tools
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "drc",
|
name: "drc",
|
||||||
description: "Design rule checking: clearance validation, electrical rules, manufacturing constraints",
|
description:
|
||||||
|
"Design rule checking: clearance validation, electrical rules, manufacturing constraints",
|
||||||
tools: [
|
tools: [
|
||||||
{
|
{
|
||||||
name: "run_drc",
|
name: "run_drc",
|
||||||
@@ -162,17 +169,21 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
properties: {
|
properties: {
|
||||||
report_all: {
|
report_all: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
description: "Report all violations or stop at first"
|
description: "Report all violations or stop at first",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "get_drc_errors",
|
name: "get_drc_errors",
|
||||||
description: "Get current DRC violations without re-running check",
|
description: "Get current DRC violations without re-running check",
|
||||||
inputSchema: { type: "object", properties: {} },
|
inputSchema: { type: "object", properties: {} },
|
||||||
handler: async (params) => { /* ... */ }
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "set_design_rules",
|
name: "set_design_rules",
|
||||||
@@ -183,12 +194,14 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
min_clearance: { type: "number", description: "Minimum clearance in mm" },
|
min_clearance: { type: "number", description: "Minimum clearance in mm" },
|
||||||
min_track_width: { type: "number", description: "Minimum track width in mm" },
|
min_track_width: { type: "number", description: "Minimum track width in mm" },
|
||||||
min_via_diameter: { type: "number", description: "Minimum via diameter in mm" },
|
min_via_diameter: { type: "number", description: "Minimum via diameter in mm" },
|
||||||
min_via_drill: { type: "number", description: "Minimum via drill size in mm" }
|
min_via_drill: { type: "number", description: "Minimum via drill size in mm" },
|
||||||
}
|
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
},
|
||||||
}
|
handler: async (params) => {
|
||||||
]
|
/* ... */
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "zones",
|
name: "zones",
|
||||||
@@ -208,22 +221,26 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
x: { type: "number" },
|
x: { type: "number" },
|
||||||
y: { type: "number" }
|
y: { type: "number" },
|
||||||
}
|
|
||||||
},
|
},
|
||||||
description: "Polygon vertices in mm"
|
|
||||||
},
|
},
|
||||||
priority: { type: "number", description: "Fill priority (higher fills first)" }
|
description: "Polygon vertices in mm",
|
||||||
},
|
},
|
||||||
required: ["net_name", "layer", "points"]
|
priority: { type: "number", description: "Fill priority (higher fills first)" },
|
||||||
|
},
|
||||||
|
required: ["net_name", "layer", "points"],
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "fill_zones",
|
name: "fill_zones",
|
||||||
description: "Recalculate and fill all copper zones",
|
description: "Recalculate and fill all copper zones",
|
||||||
inputSchema: { type: "object", properties: {} },
|
inputSchema: { type: "object", properties: {} },
|
||||||
handler: async (params) => { /* ... */ }
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "remove_zone",
|
name: "remove_zone",
|
||||||
@@ -231,13 +248,15 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
zone_id: { type: "string", description: "Zone identifier" }
|
zone_id: { type: "string", description: "Zone identifier" },
|
||||||
},
|
},
|
||||||
required: ["zone_id"]
|
required: ["zone_id"],
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
handler: async (params) => {
|
||||||
}
|
/* ... */
|
||||||
]
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
// Add more categories...
|
// Add more categories...
|
||||||
];
|
];
|
||||||
@@ -293,7 +312,7 @@ export function searchTools(query: string): Array<{
|
|||||||
matches.push({
|
matches.push({
|
||||||
category: category.name,
|
category: category.name,
|
||||||
tool: tool.name,
|
tool: tool.name,
|
||||||
description: tool.description
|
description: tool.description,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,12 +332,7 @@ These are the tools that enable discovery and execution.
|
|||||||
```typescript
|
```typescript
|
||||||
// src/tools/router.ts
|
// src/tools/router.ts
|
||||||
|
|
||||||
import {
|
import { getAllCategories, getCategory, getTool, searchTools } from "./registry.js";
|
||||||
getAllCategories,
|
|
||||||
getCategory,
|
|
||||||
getTool,
|
|
||||||
searchTools
|
|
||||||
} from "./registry.js";
|
|
||||||
|
|
||||||
export const routerTools = {
|
export const routerTools = {
|
||||||
list_tool_categories: {
|
list_tool_categories: {
|
||||||
@@ -329,20 +343,20 @@ export const routerTools = {
|
|||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object" as const,
|
type: "object" as const,
|
||||||
properties: {},
|
properties: {},
|
||||||
required: []
|
required: [],
|
||||||
},
|
},
|
||||||
handler: async () => {
|
handler: async () => {
|
||||||
const categories = getAllCategories();
|
const categories = getAllCategories();
|
||||||
return {
|
return {
|
||||||
total_categories: categories.length,
|
total_categories: categories.length,
|
||||||
total_tools: categories.reduce((sum, c) => sum + c.tools.length, 0),
|
total_tools: categories.reduce((sum, c) => sum + c.tools.length, 0),
|
||||||
categories: categories.map(c => ({
|
categories: categories.map((c) => ({
|
||||||
name: c.name,
|
name: c.name,
|
||||||
description: c.description,
|
description: c.description,
|
||||||
tool_count: c.tools.length
|
tool_count: c.tools.length,
|
||||||
}))
|
})),
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
get_category_tools: {
|
get_category_tools: {
|
||||||
@@ -356,29 +370,29 @@ export const routerTools = {
|
|||||||
properties: {
|
properties: {
|
||||||
category: {
|
category: {
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Category name from list_tool_categories"
|
description: "Category name from list_tool_categories",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
required: ["category"]
|
},
|
||||||
|
required: ["category"],
|
||||||
},
|
},
|
||||||
handler: async (params: { category: string }) => {
|
handler: async (params: { category: string }) => {
|
||||||
const category = getCategory(params.category);
|
const category = getCategory(params.category);
|
||||||
if (!category) {
|
if (!category) {
|
||||||
return {
|
return {
|
||||||
error: `Unknown category: ${params.category}`,
|
error: `Unknown category: ${params.category}`,
|
||||||
available_categories: getAllCategories().map(c => c.name)
|
available_categories: getAllCategories().map((c) => c.name),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
category: category.name,
|
category: category.name,
|
||||||
description: category.description,
|
description: category.description,
|
||||||
tools: category.tools.map(t => ({
|
tools: category.tools.map((t) => ({
|
||||||
name: t.name,
|
name: t.name,
|
||||||
description: t.description,
|
description: t.description,
|
||||||
parameters: t.inputSchema
|
parameters: t.inputSchema,
|
||||||
}))
|
})),
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
execute_tool: {
|
execute_tool: {
|
||||||
@@ -391,21 +405,21 @@ export const routerTools = {
|
|||||||
properties: {
|
properties: {
|
||||||
tool_name: {
|
tool_name: {
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Tool name (from get_category_tools)"
|
description: "Tool name (from get_category_tools)",
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
type: "object",
|
type: "object",
|
||||||
description: "Tool parameters (see get_category_tools for schema)"
|
description: "Tool parameters (see get_category_tools for schema)",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
required: ["tool_name"]
|
},
|
||||||
|
required: ["tool_name"],
|
||||||
},
|
},
|
||||||
handler: async (input: { tool_name: string; params?: Record<string, unknown> }) => {
|
handler: async (input: { tool_name: string; params?: Record<string, unknown> }) => {
|
||||||
const entry = getTool(input.tool_name);
|
const entry = getTool(input.tool_name);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return {
|
return {
|
||||||
error: `Unknown tool: ${input.tool_name}`,
|
error: `Unknown tool: ${input.tool_name}`,
|
||||||
hint: "Use list_tool_categories and get_category_tools to find available tools"
|
hint: "Use list_tool_categories and get_category_tools to find available tools",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,16 +428,16 @@ export const routerTools = {
|
|||||||
return {
|
return {
|
||||||
tool: input.tool_name,
|
tool: input.tool_name,
|
||||||
category: entry.category,
|
category: entry.category,
|
||||||
result
|
result,
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return {
|
return {
|
||||||
error: `Tool execution failed: ${(err as Error).message}`,
|
error: `Tool execution failed: ${(err as Error).message}`,
|
||||||
tool: input.tool_name,
|
tool: input.tool_name,
|
||||||
category: entry.category
|
category: entry.category,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
search_tools: {
|
search_tools: {
|
||||||
@@ -436,20 +450,20 @@ export const routerTools = {
|
|||||||
properties: {
|
properties: {
|
||||||
query: {
|
query: {
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Search term (e.g., 'gerber', 'zone', 'differential', 'export')"
|
description: "Search term (e.g., 'gerber', 'zone', 'differential', 'export')",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
required: ["query"]
|
},
|
||||||
|
required: ["query"],
|
||||||
},
|
},
|
||||||
handler: async (params: { query: string }) => {
|
handler: async (params: { query: string }) => {
|
||||||
const matches = searchTools(params.query);
|
const matches = searchTools(params.query);
|
||||||
return {
|
return {
|
||||||
query: params.query,
|
query: params.query,
|
||||||
count: matches.length,
|
count: matches.length,
|
||||||
matches: matches.slice(0, 20) // Limit results
|
matches: matches.slice(0, 20), // Limit results
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -478,15 +492,15 @@ export const directTools: ToolDefinition[] = [
|
|||||||
template: {
|
template: {
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Optional template to use",
|
description: "Optional template to use",
|
||||||
enum: ["blank", "arduino", "raspberry-pi"]
|
enum: ["blank", "arduino", "raspberry-pi"],
|
||||||
}
|
|
||||||
},
|
},
|
||||||
required: ["name", "path"]
|
},
|
||||||
|
required: ["name", "path"],
|
||||||
},
|
},
|
||||||
handler: async (params) => {
|
handler: async (params) => {
|
||||||
// Implementation
|
// Implementation
|
||||||
return { success: true, project_path: `${params.path}/${params.name}` };
|
return { success: true, project_path: `${params.path}/${params.name}` };
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "open_project",
|
name: "open_project",
|
||||||
@@ -494,29 +508,35 @@ export const directTools: ToolDefinition[] = [
|
|||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
path: { type: "string", description: "Path to project file or directory" }
|
path: { type: "string", description: "Path to project file or directory" },
|
||||||
},
|
},
|
||||||
required: ["path"]
|
required: ["path"],
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "save_project",
|
name: "save_project",
|
||||||
description: "Save all project files",
|
description: "Save all project files",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {}
|
properties: {},
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "get_project_info",
|
name: "get_project_info",
|
||||||
description: "Get current project information: path, files, status",
|
description: "Get current project information: path, files, status",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {}
|
properties: {},
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// === PRIMARY OPERATIONS (your core workflow) ===
|
// === PRIMARY OPERATIONS (your core workflow) ===
|
||||||
@@ -530,11 +550,13 @@ export const directTools: ToolDefinition[] = [
|
|||||||
reference: { type: "string", description: "Reference designator (e.g., R1, U1)" },
|
reference: { type: "string", description: "Reference designator (e.g., R1, U1)" },
|
||||||
x: { type: "number", description: "X position" },
|
x: { type: "number", description: "X position" },
|
||||||
y: { type: "number", description: "Y position" },
|
y: { type: "number", description: "Y position" },
|
||||||
rotation: { type: "number", description: "Rotation in degrees", default: 0 }
|
rotation: { type: "number", description: "Rotation in degrees", default: 0 },
|
||||||
},
|
},
|
||||||
required: ["type", "reference", "x", "y"]
|
required: ["type", "reference", "x", "y"],
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "move_component",
|
name: "move_component",
|
||||||
@@ -544,11 +566,13 @@ export const directTools: ToolDefinition[] = [
|
|||||||
properties: {
|
properties: {
|
||||||
reference: { type: "string", description: "Component reference (e.g., R1)" },
|
reference: { type: "string", description: "Component reference (e.g., R1)" },
|
||||||
x: { type: "number", description: "New X position" },
|
x: { type: "number", description: "New X position" },
|
||||||
y: { type: "number", description: "New Y position" }
|
y: { type: "number", description: "New Y position" },
|
||||||
},
|
},
|
||||||
required: ["reference", "x", "y"]
|
required: ["reference", "x", "y"],
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "list_components",
|
name: "list_components",
|
||||||
@@ -556,10 +580,12 @@ export const directTools: ToolDefinition[] = [
|
|||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
filter: { type: "string", description: "Optional filter (e.g., 'R*' for resistors)" }
|
filter: { type: "string", description: "Optional filter (e.g., 'R*' for resistors)" },
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// === SECONDARY OPERATIONS (still common) ===
|
// === SECONDARY OPERATIONS (still common) ===
|
||||||
@@ -571,36 +597,42 @@ export const directTools: ToolDefinition[] = [
|
|||||||
properties: {
|
properties: {
|
||||||
start: {
|
start: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: { x: { type: "number" }, y: { type: "number" } }
|
properties: { x: { type: "number" }, y: { type: "number" } },
|
||||||
},
|
},
|
||||||
end: {
|
end: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: { x: { type: "number" }, y: { type: "number" } }
|
properties: { x: { type: "number" }, y: { type: "number" } },
|
||||||
},
|
},
|
||||||
net: { type: "string", description: "Net name" }
|
net: { type: "string", description: "Net name" },
|
||||||
},
|
},
|
||||||
required: ["start", "end"]
|
required: ["start", "end"],
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "list_nets",
|
name: "list_nets",
|
||||||
description: "List all nets/connections",
|
description: "List all nets/connections",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {}
|
properties: {},
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "get_info",
|
name: "get_info",
|
||||||
description: "Get general information about current state",
|
description: "Get general information about current state",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {}
|
properties: {},
|
||||||
|
},
|
||||||
|
handler: async (params) => {
|
||||||
|
/* ... */
|
||||||
|
},
|
||||||
},
|
},
|
||||||
handler: async (params) => { /* ... */ }
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -613,10 +645,7 @@ Wire everything together in your main server file.
|
|||||||
|
|
||||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||||
import {
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
||||||
CallToolRequestSchema,
|
|
||||||
ListToolsRequestSchema,
|
|
||||||
} from "@modelcontextprotocol/sdk/types.js";
|
|
||||||
|
|
||||||
import { directTools } from "./tools/direct.js";
|
import { directTools } from "./tools/direct.js";
|
||||||
import { routerTools } from "./tools/router.js";
|
import { routerTools } from "./tools/router.js";
|
||||||
@@ -634,14 +663,11 @@ const server = new Server(
|
|||||||
capabilities: {
|
capabilities: {
|
||||||
tools: {},
|
tools: {},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Combine all visible tools
|
// Combine all visible tools
|
||||||
const allVisibleTools = [
|
const allVisibleTools = [...directTools, ...Object.values(routerTools)];
|
||||||
...directTools,
|
|
||||||
...Object.values(routerTools)
|
|
||||||
];
|
|
||||||
|
|
||||||
// Build a handler map for quick lookup
|
// Build a handler map for quick lookup
|
||||||
const toolHandlers = new Map<string, (params: any) => Promise<any>>();
|
const toolHandlers = new Map<string, (params: any) => Promise<any>>();
|
||||||
@@ -656,7 +682,7 @@ for (const tool of Object.values(routerTools)) {
|
|||||||
// List tools handler - returns only direct + router tools
|
// List tools handler - returns only direct + router tools
|
||||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||||
return {
|
return {
|
||||||
tools: allVisibleTools.map(tool => ({
|
tools: allVisibleTools.map((tool) => ({
|
||||||
name: tool.name,
|
name: tool.name,
|
||||||
description: tool.description,
|
description: tool.description,
|
||||||
inputSchema: tool.inputSchema,
|
inputSchema: tool.inputSchema,
|
||||||
@@ -676,9 +702,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Unknown tool: ${name}`,
|
error: `Unknown tool: ${name}`,
|
||||||
hint: "Use list_tool_categories and search_tools to find available tools"
|
hint: "Use list_tool_categories and search_tools to find available tools",
|
||||||
})
|
}),
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
isError: true,
|
isError: true,
|
||||||
};
|
};
|
||||||
@@ -690,8 +716,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -700,9 +726,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Tool execution failed: ${(error as Error).message}`
|
error: `Tool execution failed: ${(error as Error).message}`,
|
||||||
})
|
}),
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
isError: true,
|
isError: true,
|
||||||
};
|
};
|
||||||
@@ -735,7 +761,7 @@ Include tools that are:
|
|||||||
**Examples by domain:**
|
**Examples by domain:**
|
||||||
|
|
||||||
| Domain | Direct Tools |
|
| Domain | Direct Tools |
|
||||||
|--------|-------------|
|
| ------------ | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **KiCAD** | create_project, open_project, save_project, add_component, move_component, add_track, list_components, list_nets, get_board_info |
|
| **KiCAD** | create_project, open_project, save_project, add_component, move_component, add_track, list_components, list_nets, get_board_info |
|
||||||
| **IDA Pro** | open_database, save_database, get_function, list_functions, add_comment, rename, get_xrefs, decompile |
|
| **IDA Pro** | open_database, save_database, get_function, list_functions, add_comment, rename, get_xrefs, decompile |
|
||||||
| **Git** | status, add, commit, push, pull, checkout, branch, log |
|
| **Git** | status, add, commit, push, pull, checkout, branch, log |
|
||||||
@@ -754,7 +780,7 @@ Include tools that are:
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
| Category | Why Route It |
|
| Category | Why Route It |
|
||||||
|----------|-------------|
|
| ----------------- | ---------------------------- |
|
||||||
| `export` | Only used at end of workflow |
|
| `export` | Only used at end of workflow |
|
||||||
| `drc/validation` | Used during review phase |
|
| `drc/validation` | Used during review phase |
|
||||||
| `advanced_*` | Specialty operations |
|
| `advanced_*` | Specialty operations |
|
||||||
@@ -854,52 +880,52 @@ const categories = [
|
|||||||
{
|
{
|
||||||
name: "disassembly",
|
name: "disassembly",
|
||||||
description: "Disassembly operations: undefine, make code/data, change types",
|
description: "Disassembly operations: undefine, make code/data, change types",
|
||||||
tools: ["make_code", "make_data", "undefine", "set_type", "make_array", "make_struct"]
|
tools: ["make_code", "make_data", "undefine", "set_type", "make_array", "make_struct"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "functions",
|
name: "functions",
|
||||||
description: "Function management: create, delete, modify boundaries, set types",
|
description: "Function management: create, delete, modify boundaries, set types",
|
||||||
tools: ["create_function", "delete_function", "set_func_end", "set_func_type", "add_func_arg"]
|
tools: ["create_function", "delete_function", "set_func_end", "set_func_type", "add_func_arg"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "types",
|
name: "types",
|
||||||
description: "Type system: structs, enums, typedefs, parse headers",
|
description: "Type system: structs, enums, typedefs, parse headers",
|
||||||
tools: ["create_struct", "add_struct_member", "create_enum", "parse_header", "import_types"]
|
tools: ["create_struct", "add_struct_member", "create_enum", "parse_header", "import_types"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "patching",
|
name: "patching",
|
||||||
description: "Binary patching: modify bytes, assemble, apply patches",
|
description: "Binary patching: modify bytes, assemble, apply patches",
|
||||||
tools: ["patch_bytes", "patch_word", "patch_dword", "assemble", "apply_patches"]
|
tools: ["patch_bytes", "patch_word", "patch_dword", "assemble", "apply_patches"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "scripting",
|
name: "scripting",
|
||||||
description: "IDAPython scripting: run scripts, evaluate expressions",
|
description: "IDAPython scripting: run scripts, evaluate expressions",
|
||||||
tools: ["run_script", "eval_python", "get_global", "set_global"]
|
tools: ["run_script", "eval_python", "get_global", "set_global"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "signatures",
|
name: "signatures",
|
||||||
description: "Signatures and patterns: FLIRT, Lumina, create signatures",
|
description: "Signatures and patterns: FLIRT, Lumina, create signatures",
|
||||||
tools: ["apply_flirt", "query_lumina", "create_sig", "find_pattern"]
|
tools: ["apply_flirt", "query_lumina", "create_sig", "find_pattern"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "debugging",
|
name: "debugging",
|
||||||
description: "Debugger control: breakpoints, stepping, memory",
|
description: "Debugger control: breakpoints, stepping, memory",
|
||||||
tools: ["set_breakpoint", "step_into", "step_over", "read_memory", "write_memory", "get_regs"]
|
tools: ["set_breakpoint", "step_into", "step_over", "read_memory", "write_memory", "get_regs"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "export",
|
name: "export",
|
||||||
description: "Export: ASM listing, pseudocode, database info, reports",
|
description: "Export: ASM listing, pseudocode, database info, reports",
|
||||||
tools: ["export_asm", "export_c", "export_json", "generate_report"]
|
tools: ["export_asm", "export_c", "export_json", "generate_report"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "import",
|
name: "import",
|
||||||
description: "Import: symbols, types, comments from external sources",
|
description: "Import: symbols, types, comments from external sources",
|
||||||
tools: ["import_symbols", "import_pdb", "import_map", "import_comments"]
|
tools: ["import_symbols", "import_pdb", "import_map", "import_comments"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "analysis",
|
name: "analysis",
|
||||||
description: "Analysis control: reanalyze, find patterns, auto-analysis settings",
|
description: "Analysis control: reanalyze, find patterns, auto-analysis settings",
|
||||||
tools: ["reanalyze", "find_crypto", "find_strings", "analyze_calls", "set_analysis_options"]
|
tools: ["reanalyze", "find_crypto", "find_strings", "analyze_calls", "set_analysis_options"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
@@ -962,19 +988,14 @@ Claude: "I've added length tuning meanders to match the trace lengths"
|
|||||||
// tests/router.test.ts
|
// tests/router.test.ts
|
||||||
|
|
||||||
import { describe, it, expect } from "vitest";
|
import { describe, it, expect } from "vitest";
|
||||||
import {
|
import { searchTools, getCategory, getTool, getAllCategories } from "../src/tools/registry.js";
|
||||||
searchTools,
|
|
||||||
getCategory,
|
|
||||||
getTool,
|
|
||||||
getAllCategories
|
|
||||||
} from "../src/tools/registry.js";
|
|
||||||
import { routerTools } from "../src/tools/router.js";
|
import { routerTools } from "../src/tools/router.js";
|
||||||
|
|
||||||
describe("Tool Registry", () => {
|
describe("Tool Registry", () => {
|
||||||
it("should find tools by keyword", () => {
|
it("should find tools by keyword", () => {
|
||||||
const results = searchTools("export");
|
const results = searchTools("export");
|
||||||
expect(results.length).toBeGreaterThan(0);
|
expect(results.length).toBeGreaterThan(0);
|
||||||
expect(results.some(r => r.tool.includes("export"))).toBe(true);
|
expect(results.some((r) => r.tool.includes("export"))).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return category info", () => {
|
it("should return category info", () => {
|
||||||
@@ -998,7 +1019,7 @@ describe("Router Tools", () => {
|
|||||||
|
|
||||||
it("get_category_tools returns tools for valid category", async () => {
|
it("get_category_tools returns tools for valid category", async () => {
|
||||||
const result = await routerTools.get_category_tools.handler({
|
const result = await routerTools.get_category_tools.handler({
|
||||||
category: "export"
|
category: "export",
|
||||||
});
|
});
|
||||||
expect(result.tools).toBeDefined();
|
expect(result.tools).toBeDefined();
|
||||||
expect(result.tools.length).toBeGreaterThan(0);
|
expect(result.tools.length).toBeGreaterThan(0);
|
||||||
@@ -1006,7 +1027,7 @@ describe("Router Tools", () => {
|
|||||||
|
|
||||||
it("get_category_tools returns error for invalid category", async () => {
|
it("get_category_tools returns error for invalid category", async () => {
|
||||||
const result = await routerTools.get_category_tools.handler({
|
const result = await routerTools.get_category_tools.handler({
|
||||||
category: "nonexistent"
|
category: "nonexistent",
|
||||||
});
|
});
|
||||||
expect(result.error).toBeDefined();
|
expect(result.error).toBeDefined();
|
||||||
});
|
});
|
||||||
@@ -1014,7 +1035,7 @@ describe("Router Tools", () => {
|
|||||||
it("execute_tool runs valid tool", async () => {
|
it("execute_tool runs valid tool", async () => {
|
||||||
const result = await routerTools.execute_tool.handler({
|
const result = await routerTools.execute_tool.handler({
|
||||||
tool_name: "export_gerber",
|
tool_name: "export_gerber",
|
||||||
params: { output_dir: "/tmp/test" }
|
params: { output_dir: "/tmp/test" },
|
||||||
});
|
});
|
||||||
expect(result.error).toBeUndefined();
|
expect(result.error).toBeUndefined();
|
||||||
});
|
});
|
||||||
@@ -1022,7 +1043,7 @@ describe("Router Tools", () => {
|
|||||||
it("execute_tool returns error for invalid tool", async () => {
|
it("execute_tool returns error for invalid tool", async () => {
|
||||||
const result = await routerTools.execute_tool.handler({
|
const result = await routerTools.execute_tool.handler({
|
||||||
tool_name: "nonexistent_tool",
|
tool_name: "nonexistent_tool",
|
||||||
params: {}
|
params: {},
|
||||||
});
|
});
|
||||||
expect(result.error).toBeDefined();
|
expect(result.error).toBeDefined();
|
||||||
});
|
});
|
||||||
@@ -1142,7 +1163,7 @@ Before shipping your router-based MCP server:
|
|||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
| Before | After |
|
| Before | After |
|
||||||
|--------|-------|
|
| ------------------------ | --------------------- |
|
||||||
| 100 tools visible | 15-18 tools visible |
|
| 100 tools visible | 15-18 tools visible |
|
||||||
| ~60K+ tokens consumed | ~10K tokens consumed |
|
| ~60K+ tokens consumed | ~10K tokens consumed |
|
||||||
| Tool selection confusion | Clear categories |
|
| Tool selection confusion | Clear categories |
|
||||||
|
|||||||
17
package-lock.json
generated
17
package-lock.json
generated
@@ -20,6 +20,7 @@
|
|||||||
"@types/glob": "^8.1.0",
|
"@types/glob": "^8.1.0",
|
||||||
"@types/node": "^20.19.0",
|
"@types/node": "^20.19.0",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
|
"prettier": "^3.8.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1150,6 +1151,22 @@
|
|||||||
"node": ">=16.20.0"
|
"node": ">=16.20.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
|
||||||
|
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/proxy-addr": {
|
"node_modules/proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
"@types/glob": "^8.1.0",
|
"@types/glob": "^8.1.0",
|
||||||
"@types/node": "^20.19.0",
|
"@types/node": "^20.19.0",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
|
"prettier": "^3.8.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,31 +2,31 @@
|
|||||||
* Configuration handling for KiCAD MCP server
|
* Configuration handling for KiCAD MCP server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { readFile } from 'fs/promises';
|
import { readFile } from "fs/promises";
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from "fs";
|
||||||
import { join, dirname } from 'path';
|
import { join, dirname } from "path";
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from "url";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from './logger.js';
|
import { logger } from "./logger.js";
|
||||||
|
|
||||||
// Get the current directory
|
// Get the current directory
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
// Default config location
|
// Default config location
|
||||||
const DEFAULT_CONFIG_PATH = join(dirname(__dirname), 'config', 'default-config.json');
|
const DEFAULT_CONFIG_PATH = join(dirname(__dirname), "config", "default-config.json");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server configuration schema
|
* Server configuration schema
|
||||||
*/
|
*/
|
||||||
const ConfigSchema = z.object({
|
const ConfigSchema = z.object({
|
||||||
name: z.string().default('kicad-mcp-server'),
|
name: z.string().default("kicad-mcp-server"),
|
||||||
version: z.string().default('1.0.0'),
|
version: z.string().default("1.0.0"),
|
||||||
description: z.string().default('MCP server for KiCAD PCB design operations'),
|
description: z.string().default("MCP server for KiCAD PCB design operations"),
|
||||||
pythonPath: z.string().optional(),
|
pythonPath: z.string().optional(),
|
||||||
kicadPath: z.string().optional(),
|
kicadPath: z.string().optional(),
|
||||||
logLevel: z.enum(['error', 'warn', 'info', 'debug']).default('info'),
|
logLevel: z.enum(["error", "warn", "info", "debug"]).default("info"),
|
||||||
logDir: z.string().optional()
|
logDir: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +52,7 @@ export async function loadConfig(configPath?: string): Promise<Config> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read and parse configuration
|
// Read and parse configuration
|
||||||
const configData = await readFile(filePath, 'utf-8');
|
const configData = await readFile(filePath, "utf-8");
|
||||||
const config = JSON.parse(configData);
|
const config = JSON.parse(configData);
|
||||||
|
|
||||||
// Validate configuration
|
// Validate configuration
|
||||||
|
|||||||
38
src/index.ts
38
src/index.ts
@@ -3,11 +3,11 @@
|
|||||||
* Main entry point
|
* Main entry point
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { join, dirname } from 'path';
|
import { join, dirname } from "path";
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from "url";
|
||||||
import { KiCADMcpServer } from './server.js';
|
import { KiCADMcpServer } from "./server.js";
|
||||||
import { loadConfig } from './config.js';
|
import { loadConfig } from "./config.js";
|
||||||
import { logger } from './logger.js';
|
import { logger } from "./logger.js";
|
||||||
|
|
||||||
// Get the current directory
|
// Get the current directory
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
@@ -26,13 +26,10 @@ async function main() {
|
|||||||
const config = await loadConfig(options.configPath);
|
const config = await loadConfig(options.configPath);
|
||||||
|
|
||||||
// Path to the Python script that interfaces with KiCAD
|
// Path to the Python script that interfaces with KiCAD
|
||||||
const kicadScriptPath = join(dirname(__dirname), 'python', 'kicad_interface.py');
|
const kicadScriptPath = join(dirname(__dirname), "python", "kicad_interface.py");
|
||||||
|
|
||||||
// Create the server
|
// Create the server
|
||||||
const server = new KiCADMcpServer(
|
const server = new KiCADMcpServer(kicadScriptPath, config.logLevel);
|
||||||
kicadScriptPath,
|
|
||||||
config.logLevel
|
|
||||||
);
|
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
await server.start();
|
await server.start();
|
||||||
@@ -40,8 +37,7 @@ async function main() {
|
|||||||
// Setup graceful shutdown
|
// Setup graceful shutdown
|
||||||
setupGracefulShutdown(server);
|
setupGracefulShutdown(server);
|
||||||
|
|
||||||
logger.info('KiCAD MCP server started with STDIO transport');
|
logger.info("KiCAD MCP server started with STDIO transport");
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to start KiCAD MCP server: ${error}`);
|
logger.error(`Failed to start KiCAD MCP server: ${error}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@@ -55,7 +51,7 @@ function parseCommandLineArgs(args: string[]) {
|
|||||||
let configPath = undefined;
|
let configPath = undefined;
|
||||||
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
for (let i = 0; i < args.length; i++) {
|
||||||
if (args[i] === '--config' && i + 1 < args.length) {
|
if (args[i] === "--config" && i + 1 < args.length) {
|
||||||
configPath = args[i + 1];
|
configPath = args[i + 1];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@@ -69,24 +65,24 @@ function parseCommandLineArgs(args: string[]) {
|
|||||||
*/
|
*/
|
||||||
function setupGracefulShutdown(server: KiCADMcpServer) {
|
function setupGracefulShutdown(server: KiCADMcpServer) {
|
||||||
// Handle termination signals
|
// Handle termination signals
|
||||||
process.on('SIGINT', async () => {
|
process.on("SIGINT", async () => {
|
||||||
logger.info('Received SIGINT signal. Shutting down...');
|
logger.info("Received SIGINT signal. Shutting down...");
|
||||||
await shutdownServer(server);
|
await shutdownServer(server);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('SIGTERM', async () => {
|
process.on("SIGTERM", async () => {
|
||||||
logger.info('Received SIGTERM signal. Shutting down...');
|
logger.info("Received SIGTERM signal. Shutting down...");
|
||||||
await shutdownServer(server);
|
await shutdownServer(server);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle uncaught exceptions
|
// Handle uncaught exceptions
|
||||||
process.on('uncaughtException', async (error) => {
|
process.on("uncaughtException", async (error) => {
|
||||||
logger.error(`Uncaught exception: ${error}`);
|
logger.error(`Uncaught exception: ${error}`);
|
||||||
await shutdownServer(server);
|
await shutdownServer(server);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle unhandled promise rejections
|
// Handle unhandled promise rejections
|
||||||
process.on('unhandledRejection', async (reason) => {
|
process.on("unhandledRejection", async (reason) => {
|
||||||
logger.error(`Unhandled promise rejection: ${reason}`);
|
logger.error(`Unhandled promise rejection: ${reason}`);
|
||||||
await shutdownServer(server);
|
await shutdownServer(server);
|
||||||
});
|
});
|
||||||
@@ -97,9 +93,9 @@ function setupGracefulShutdown(server: KiCADMcpServer) {
|
|||||||
*/
|
*/
|
||||||
async function shutdownServer(server: KiCADMcpServer) {
|
async function shutdownServer(server: KiCADMcpServer) {
|
||||||
try {
|
try {
|
||||||
logger.info('Shutting down KiCAD MCP server...');
|
logger.info("Shutting down KiCAD MCP server...");
|
||||||
await server.stop();
|
await server.stop();
|
||||||
logger.info('Server shutdown complete. Exiting...');
|
logger.info("Server shutdown complete. Exiting...");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Error during shutdown: ${error}`);
|
logger.error(`Error during shutdown: ${error}`);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||||
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
||||||
import { spawn, ChildProcess } from 'child_process';
|
import { spawn, ChildProcess } from "child_process";
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from "fs";
|
||||||
import path from 'path';
|
import path from "path";
|
||||||
|
|
||||||
// Import all tool definitions for reference
|
// Import all tool definitions for reference
|
||||||
// import { registerBoardTools } from './tools/board.js';
|
// import { registerBoardTools } from './tools/board.js';
|
||||||
@@ -19,13 +19,13 @@ class KiCADServer {
|
|||||||
private server: Server;
|
private server: Server;
|
||||||
private pythonProcess: ChildProcess | null = null;
|
private pythonProcess: ChildProcess | null = null;
|
||||||
private kicadScriptPath: string;
|
private kicadScriptPath: string;
|
||||||
private requestQueue: Array<{ request: any, resolve: Function, reject: Function }> = [];
|
private requestQueue: Array<{ request: any; resolve: Function; reject: Function }> = [];
|
||||||
private processingRequest = false;
|
private processingRequest = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Set absolute path to the Python KiCAD interface script
|
// Set absolute path to the Python KiCAD interface script
|
||||||
// Using a hardcoded path to avoid cwd() issues when running from Cline
|
// Using a hardcoded path to avoid cwd() issues when running from Cline
|
||||||
this.kicadScriptPath = 'c:/repo/KiCAD-MCP/python/kicad_interface.py';
|
this.kicadScriptPath = "c:/repo/KiCAD-MCP/python/kicad_interface.py";
|
||||||
|
|
||||||
// Check if script exists
|
// Check if script exists
|
||||||
if (!existsSync(this.kicadScriptPath)) {
|
if (!existsSync(this.kicadScriptPath)) {
|
||||||
@@ -35,16 +35,16 @@ class KiCADServer {
|
|||||||
// Initialize the server
|
// Initialize the server
|
||||||
this.server = new Server(
|
this.server = new Server(
|
||||||
{
|
{
|
||||||
name: 'kicad-mcp-server',
|
name: "kicad-mcp-server",
|
||||||
version: '1.0.0'
|
version: "1.0.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
capabilities: {
|
capabilities: {
|
||||||
tools: {
|
tools: {
|
||||||
// Empty object here, tools will be registered dynamically
|
// Empty object here, tools will be registered dynamically
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize handler with direct pass-through to Python KiCAD interface
|
// Initialize handler with direct pass-through to Python KiCAD interface
|
||||||
@@ -55,231 +55,234 @@ class KiCADServer {
|
|||||||
tools: [
|
tools: [
|
||||||
// Project tools
|
// Project tools
|
||||||
{
|
{
|
||||||
name: 'create_project',
|
name: "create_project",
|
||||||
description: 'Create a new KiCAD project',
|
description: "Create a new KiCAD project",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
projectName: { type: 'string', description: 'Name of the new project' },
|
projectName: { type: "string", description: "Name of the new project" },
|
||||||
path: { type: 'string', description: 'Path where to create the project' },
|
path: { type: "string", description: "Path where to create the project" },
|
||||||
template: { type: 'string', description: 'Optional template to use' }
|
template: { type: "string", description: "Optional template to use" },
|
||||||
|
},
|
||||||
|
required: ["projectName"],
|
||||||
},
|
},
|
||||||
required: ['projectName']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'open_project',
|
name: "open_project",
|
||||||
description: 'Open an existing KiCAD project',
|
description: "Open an existing KiCAD project",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
filename: { type: 'string', description: 'Path to the project file' }
|
filename: { type: "string", description: "Path to the project file" },
|
||||||
|
},
|
||||||
|
required: ["filename"],
|
||||||
},
|
},
|
||||||
required: ['filename']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'save_project',
|
name: "save_project",
|
||||||
description: 'Save the current KiCAD project',
|
description: "Save the current KiCAD project",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
filename: { type: 'string', description: 'Optional path to save to' }
|
filename: { type: "string", description: "Optional path to save to" },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'get_project_info',
|
name: "get_project_info",
|
||||||
description: 'Get information about the current project',
|
description: "Get information about the current project",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {}
|
properties: {},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Board tools
|
// Board tools
|
||||||
{
|
{
|
||||||
name: 'set_board_size',
|
name: "set_board_size",
|
||||||
description: 'Set the size of the PCB board',
|
description: "Set the size of the PCB board",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
width: { type: 'number', description: 'Board width' },
|
width: { type: "number", description: "Board width" },
|
||||||
height: { type: 'number', description: 'Board height' },
|
height: { type: "number", description: "Board height" },
|
||||||
unit: { type: 'string', description: 'Unit of measurement (mm or inch)' }
|
unit: { type: "string", description: "Unit of measurement (mm or inch)" },
|
||||||
|
},
|
||||||
|
required: ["width", "height"],
|
||||||
},
|
},
|
||||||
required: ['width', 'height']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'add_board_outline',
|
name: "add_board_outline",
|
||||||
description: 'Add a board outline to the PCB',
|
description: "Add a board outline to the PCB",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
shape: { type: 'string', description: 'Shape of outline (rectangle, circle, polygon, rounded_rectangle)' },
|
shape: {
|
||||||
width: { type: 'number', description: 'Width for rectangle shapes' },
|
type: "string",
|
||||||
height: { type: 'number', description: 'Height for rectangle shapes' },
|
description: "Shape of outline (rectangle, circle, polygon, rounded_rectangle)",
|
||||||
radius: { type: 'number', description: 'Radius for circle shapes' },
|
},
|
||||||
cornerRadius: { type: 'number', description: 'Corner radius for rounded rectangles' },
|
width: { type: "number", description: "Width for rectangle shapes" },
|
||||||
points: { type: 'array', description: 'Array of points for polygon shapes' },
|
height: { type: "number", description: "Height for rectangle shapes" },
|
||||||
centerX: { type: 'number', description: 'X coordinate of center' },
|
radius: { type: "number", description: "Radius for circle shapes" },
|
||||||
centerY: { type: 'number', description: 'Y coordinate of center' },
|
cornerRadius: { type: "number", description: "Corner radius for rounded rectangles" },
|
||||||
unit: { type: 'string', description: 'Unit of measurement (mm or inch)' }
|
points: { type: "array", description: "Array of points for polygon shapes" },
|
||||||
}
|
centerX: { type: "number", description: "X coordinate of center" },
|
||||||
}
|
centerY: { type: "number", description: "Y coordinate of center" },
|
||||||
|
unit: { type: "string", description: "Unit of measurement (mm or inch)" },
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Component tools
|
// Component tools
|
||||||
{
|
{
|
||||||
name: 'place_component',
|
name: "place_component",
|
||||||
description: 'Place a component on the PCB',
|
description: "Place a component on the PCB",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
componentId: { type: 'string', description: 'Component ID/footprint to place' },
|
componentId: { type: "string", description: "Component ID/footprint to place" },
|
||||||
position: { type: 'object', description: 'Position coordinates' },
|
position: { type: "object", description: "Position coordinates" },
|
||||||
reference: { type: 'string', description: 'Component reference designator' },
|
reference: { type: "string", description: "Component reference designator" },
|
||||||
value: { type: 'string', description: 'Component value' },
|
value: { type: "string", description: "Component value" },
|
||||||
rotation: { type: 'number', description: 'Rotation angle in degrees' },
|
rotation: { type: "number", description: "Rotation angle in degrees" },
|
||||||
layer: { type: 'string', description: 'Layer to place component on' }
|
layer: { type: "string", description: "Layer to place component on" },
|
||||||
|
},
|
||||||
|
required: ["componentId", "position"],
|
||||||
},
|
},
|
||||||
required: ['componentId', 'position']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Routing tools
|
// Routing tools
|
||||||
{
|
{
|
||||||
name: 'add_net',
|
name: "add_net",
|
||||||
description: 'Add a new net to the PCB',
|
description: "Add a new net to the PCB",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
name: { type: 'string', description: 'Net name' },
|
name: { type: "string", description: "Net name" },
|
||||||
class: { type: 'string', description: 'Net class' }
|
class: { type: "string", description: "Net class" },
|
||||||
|
},
|
||||||
|
required: ["name"],
|
||||||
},
|
},
|
||||||
required: ['name']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'route_trace',
|
name: "route_trace",
|
||||||
description: 'Route a trace between two points or pads',
|
description: "Route a trace between two points or pads",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
start: { type: 'object', description: 'Start point or pad' },
|
start: { type: "object", description: "Start point or pad" },
|
||||||
end: { type: 'object', description: 'End point or pad' },
|
end: { type: "object", description: "End point or pad" },
|
||||||
layer: { type: 'string', description: 'Layer to route on' },
|
layer: { type: "string", description: "Layer to route on" },
|
||||||
width: { type: 'number', description: 'Track width' },
|
width: { type: "number", description: "Track width" },
|
||||||
net: { type: 'string', description: 'Net name' }
|
net: { type: "string", description: "Net name" },
|
||||||
|
},
|
||||||
|
required: ["start", "end"],
|
||||||
},
|
},
|
||||||
required: ['start', 'end']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Schematic tools
|
// Schematic tools
|
||||||
{
|
{
|
||||||
name: 'create_schematic',
|
name: "create_schematic",
|
||||||
description: 'Create a new KiCAD schematic',
|
description: "Create a new KiCAD schematic",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
projectName: { type: 'string', description: 'Name of the schematic project' },
|
projectName: { type: "string", description: "Name of the schematic project" },
|
||||||
path: { type: 'string', description: 'Path where to create the schematic file' },
|
path: { type: "string", description: "Path where to create the schematic file" },
|
||||||
metadata: { type: 'object', description: 'Optional metadata for the schematic' }
|
metadata: { type: "object", description: "Optional metadata for the schematic" },
|
||||||
|
},
|
||||||
|
required: ["projectName"],
|
||||||
},
|
},
|
||||||
required: ['projectName']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'load_schematic',
|
name: "load_schematic",
|
||||||
description: 'Load an existing KiCAD schematic',
|
description: "Load an existing KiCAD schematic",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
filename: { type: 'string', description: 'Path to the schematic file to load' }
|
filename: { type: "string", description: "Path to the schematic file to load" },
|
||||||
|
},
|
||||||
|
required: ["filename"],
|
||||||
},
|
},
|
||||||
required: ['filename']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'add_schematic_component',
|
name: "add_schematic_component",
|
||||||
description: 'Add a component to a KiCAD schematic',
|
description: "Add a component to a KiCAD schematic",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
schematicPath: { type: 'string', description: 'Path to the schematic file' },
|
schematicPath: { type: "string", description: "Path to the schematic file" },
|
||||||
component: {
|
component: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
description: 'Component definition',
|
description: "Component definition",
|
||||||
properties: {
|
properties: {
|
||||||
type: { type: 'string', description: 'Component type (e.g., R, C, LED)' },
|
type: { type: "string", description: "Component type (e.g., R, C, LED)" },
|
||||||
reference: { type: 'string', description: 'Reference designator (e.g., R1, C2)' },
|
reference: { type: "string", description: "Reference designator (e.g., R1, C2)" },
|
||||||
value: { type: 'string', description: 'Component value (e.g., 10k, 0.1uF)' },
|
value: { type: "string", description: "Component value (e.g., 10k, 0.1uF)" },
|
||||||
library: { type: 'string', description: 'Symbol library name' },
|
library: { type: "string", description: "Symbol library name" },
|
||||||
x: { type: 'number', description: 'X position in schematic' },
|
x: { type: "number", description: "X position in schematic" },
|
||||||
y: { type: 'number', description: 'Y position in schematic' },
|
y: { type: "number", description: "Y position in schematic" },
|
||||||
rotation: { type: 'number', description: 'Rotation angle in degrees' },
|
rotation: { type: "number", description: "Rotation angle in degrees" },
|
||||||
properties: { type: 'object', description: 'Additional properties' }
|
properties: { type: "object", description: "Additional properties" },
|
||||||
},
|
},
|
||||||
required: ['type', 'reference']
|
required: ["type", "reference"],
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
required: ["schematicPath", "component"],
|
||||||
},
|
},
|
||||||
required: ['schematicPath', 'component']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'add_schematic_wire',
|
name: "add_schematic_wire",
|
||||||
description: 'Add a wire connection to a KiCAD schematic',
|
description: "Add a wire connection to a KiCAD schematic",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
schematicPath: { type: 'string', description: 'Path to the schematic file' },
|
schematicPath: { type: "string", description: "Path to the schematic file" },
|
||||||
startPoint: {
|
startPoint: {
|
||||||
type: 'array',
|
type: "array",
|
||||||
description: 'Starting point coordinates [x, y]',
|
description: "Starting point coordinates [x, y]",
|
||||||
items: { type: 'number' },
|
items: { type: "number" },
|
||||||
minItems: 2,
|
minItems: 2,
|
||||||
maxItems: 2
|
maxItems: 2,
|
||||||
},
|
},
|
||||||
endPoint: {
|
endPoint: {
|
||||||
type: 'array',
|
type: "array",
|
||||||
description: 'Ending point coordinates [x, y]',
|
description: "Ending point coordinates [x, y]",
|
||||||
items: { type: 'number' },
|
items: { type: "number" },
|
||||||
minItems: 2,
|
minItems: 2,
|
||||||
maxItems: 2
|
maxItems: 2,
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
required: ["schematicPath", "startPoint", "endPoint"],
|
||||||
},
|
},
|
||||||
required: ['schematicPath', 'startPoint', 'endPoint']
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'list_schematic_libraries',
|
name: "list_schematic_libraries",
|
||||||
description: 'List available KiCAD symbol libraries',
|
description: "List available KiCAD symbol libraries",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
searchPaths: {
|
searchPaths: {
|
||||||
type: 'array',
|
type: "array",
|
||||||
description: 'Optional search paths for libraries',
|
description: "Optional search paths for libraries",
|
||||||
items: { type: 'string' }
|
items: { type: "string" },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'export_schematic_pdf',
|
name: "export_schematic_pdf",
|
||||||
description: 'Export a KiCAD schematic to PDF',
|
description: "Export a KiCAD schematic to PDF",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
schematicPath: { type: 'string', description: 'Path to the schematic file' },
|
schematicPath: { type: "string", description: "Path to the schematic file" },
|
||||||
outputPath: { type: 'string', description: 'Path for the output PDF file' }
|
outputPath: { type: "string", description: "Path for the output PDF file" },
|
||||||
},
|
},
|
||||||
required: ['schematicPath', 'outputPath']
|
required: ["schematicPath", "outputPath"],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Register tool call handler
|
// Register tool call handler
|
||||||
@@ -299,35 +302,35 @@ class KiCADServer {
|
|||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
try {
|
try {
|
||||||
console.error('Starting KiCAD MCP server...');
|
console.error("Starting KiCAD MCP server...");
|
||||||
|
|
||||||
// Start the Python process for KiCAD scripting
|
// Start the Python process for KiCAD scripting
|
||||||
console.error(`Starting Python process with script: ${this.kicadScriptPath}`);
|
console.error(`Starting Python process with script: ${this.kicadScriptPath}`);
|
||||||
const pythonExe = 'C:\\Program Files\\KiCad\\9.0\\bin\\python.exe';
|
const pythonExe = "C:\\Program Files\\KiCad\\9.0\\bin\\python.exe";
|
||||||
|
|
||||||
console.error(`Using Python executable: ${pythonExe}`);
|
console.error(`Using Python executable: ${pythonExe}`);
|
||||||
this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], {
|
this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], {
|
||||||
stdio: ['pipe', 'pipe', 'pipe'],
|
stdio: ["pipe", "pipe", "pipe"],
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
PYTHONPATH: 'C:/Program Files/KiCad/9.0/lib/python3/dist-packages'
|
PYTHONPATH: "C:/Program Files/KiCad/9.0/lib/python3/dist-packages",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for process exit
|
// Listen for process exit
|
||||||
this.pythonProcess.on('exit', (code, signal) => {
|
this.pythonProcess.on("exit", (code, signal) => {
|
||||||
console.error(`Python process exited with code ${code} and signal ${signal}`);
|
console.error(`Python process exited with code ${code} and signal ${signal}`);
|
||||||
this.pythonProcess = null;
|
this.pythonProcess = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for process errors
|
// Listen for process errors
|
||||||
this.pythonProcess.on('error', (err) => {
|
this.pythonProcess.on("error", (err) => {
|
||||||
console.error(`Python process error: ${err.message}`);
|
console.error(`Python process error: ${err.message}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up error logging for stderr
|
// Set up error logging for stderr
|
||||||
if (this.pythonProcess.stderr) {
|
if (this.pythonProcess.stderr) {
|
||||||
this.pythonProcess.stderr.on('data', (data: Buffer) => {
|
this.pythonProcess.stderr.on("data", (data: Buffer) => {
|
||||||
console.error(`Python stderr: ${data.toString()}`);
|
console.error(`Python stderr: ${data.toString()}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -335,22 +338,21 @@ class KiCADServer {
|
|||||||
// Connect to transport
|
// Connect to transport
|
||||||
const transport = new StdioServerTransport();
|
const transport = new StdioServerTransport();
|
||||||
await this.server.connect(transport);
|
await this.server.connect(transport);
|
||||||
console.error('KiCAD MCP server running');
|
console.error("KiCAD MCP server running");
|
||||||
|
|
||||||
// Keep the process running
|
// Keep the process running
|
||||||
process.on('SIGINT', () => {
|
process.on("SIGINT", () => {
|
||||||
if (this.pythonProcess) {
|
if (this.pythonProcess) {
|
||||||
this.pythonProcess.kill();
|
this.pythonProcess.kill();
|
||||||
}
|
}
|
||||||
this.server.close().catch(console.error);
|
this.server.close().catch(console.error);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
console.error('Failed to start MCP server:', error.message);
|
console.error("Failed to start MCP server:", error.message);
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to start MCP server: Unknown error');
|
console.error("Failed to start MCP server: Unknown error");
|
||||||
}
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@@ -360,7 +362,7 @@ class KiCADServer {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// Check if Python process is running
|
// Check if Python process is running
|
||||||
if (!this.pythonProcess) {
|
if (!this.pythonProcess) {
|
||||||
console.error('Python process is not running');
|
console.error("Python process is not running");
|
||||||
reject(new Error("Python process for KiCAD scripting is not running"));
|
reject(new Error("Python process for KiCAD scripting is not running"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -369,7 +371,7 @@ class KiCADServer {
|
|||||||
this.requestQueue.push({
|
this.requestQueue.push({
|
||||||
request: { command, params },
|
request: { command, params },
|
||||||
resolve,
|
resolve,
|
||||||
reject
|
reject,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Process the queue if not already processing
|
// Process the queue if not already processing
|
||||||
@@ -398,16 +400,16 @@ class KiCADServer {
|
|||||||
const requestStr = JSON.stringify(request);
|
const requestStr = JSON.stringify(request);
|
||||||
|
|
||||||
// Set up response handling
|
// Set up response handling
|
||||||
let responseData = '';
|
let responseData = "";
|
||||||
|
|
||||||
// Clear any previous listeners
|
// Clear any previous listeners
|
||||||
if (this.pythonProcess?.stdout) {
|
if (this.pythonProcess?.stdout) {
|
||||||
this.pythonProcess.stdout.removeAllListeners('data');
|
this.pythonProcess.stdout.removeAllListeners("data");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up new listeners
|
// Set up new listeners
|
||||||
if (this.pythonProcess?.stdout) {
|
if (this.pythonProcess?.stdout) {
|
||||||
this.pythonProcess.stdout.on('data', (data: Buffer) => {
|
this.pythonProcess.stdout.on("data", (data: Buffer) => {
|
||||||
const chunk = data.toString();
|
const chunk = data.toString();
|
||||||
console.error(`Received data chunk: ${chunk.length} bytes`);
|
console.error(`Received data chunk: ${chunk.length} bytes`);
|
||||||
responseData += chunk;
|
responseData += chunk;
|
||||||
@@ -418,7 +420,9 @@ class KiCADServer {
|
|||||||
const result = JSON.parse(responseData);
|
const result = JSON.parse(responseData);
|
||||||
|
|
||||||
// If we get here, we have a valid JSON response
|
// If we get here, we have a valid JSON response
|
||||||
console.error(`Completed KiCAD command: ${request.command} with result: ${JSON.stringify(result)}`);
|
console.error(
|
||||||
|
`Completed KiCAD command: ${request.command} with result: ${JSON.stringify(result)}`,
|
||||||
|
);
|
||||||
|
|
||||||
// Reset processing flag
|
// Reset processing flag
|
||||||
this.processingRequest = false;
|
this.processingRequest = false;
|
||||||
@@ -428,7 +432,7 @@ class KiCADServer {
|
|||||||
|
|
||||||
// Clear listeners
|
// Clear listeners
|
||||||
if (this.pythonProcess?.stdout) {
|
if (this.pythonProcess?.stdout) {
|
||||||
this.pythonProcess.stdout.removeAllListeners('data');
|
this.pythonProcess.stdout.removeAllListeners("data");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve with the expected MCP tool response format
|
// Resolve with the expected MCP tool response format
|
||||||
@@ -436,20 +440,20 @@ class KiCADServer {
|
|||||||
resolve({
|
resolve({
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
resolve({
|
resolve({
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
text: result.errorDetails || result.message || 'Unknown error'
|
text: result.errorDetails || result.message || "Unknown error",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
isError: true
|
isError: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -464,7 +468,7 @@ class KiCADServer {
|
|||||||
|
|
||||||
// Clear listeners
|
// Clear listeners
|
||||||
if (this.pythonProcess?.stdout) {
|
if (this.pythonProcess?.stdout) {
|
||||||
this.pythonProcess.stdout.removeAllListeners('data');
|
this.pythonProcess.stdout.removeAllListeners("data");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset processing flag
|
// Reset processing flag
|
||||||
@@ -479,7 +483,7 @@ class KiCADServer {
|
|||||||
|
|
||||||
// Write the request to the Python process
|
// Write the request to the Python process
|
||||||
console.error(`Sending request: ${requestStr}`);
|
console.error(`Sending request: ${requestStr}`);
|
||||||
this.pythonProcess?.stdin?.write(requestStr + '\n');
|
this.pythonProcess?.stdin?.write(requestStr + "\n");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error processing request: ${error}`);
|
console.error(`Error processing request: ${error}`);
|
||||||
|
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
* Logger for KiCAD MCP server
|
* Logger for KiCAD MCP server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { existsSync, mkdirSync, appendFileSync } from 'fs';
|
import { existsSync, mkdirSync, appendFileSync } from "fs";
|
||||||
import { join } from 'path';
|
import { join } from "path";
|
||||||
import * as os from 'os';
|
import * as os from "os";
|
||||||
|
|
||||||
// Log levels
|
// Log levels
|
||||||
type LogLevel = 'error' | 'warn' | 'info' | 'debug';
|
type LogLevel = "error" | "warn" | "info" | "debug";
|
||||||
|
|
||||||
// Default log directory
|
// Default log directory
|
||||||
const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');
|
const DEFAULT_LOG_DIR = join(os.homedir(), ".kicad-mcp", "logs");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger class for KiCAD MCP server
|
* Logger class for KiCAD MCP server
|
||||||
*/
|
*/
|
||||||
class Logger {
|
class Logger {
|
||||||
private logLevel: LogLevel = 'info';
|
private logLevel: LogLevel = "info";
|
||||||
private logDir: string = DEFAULT_LOG_DIR;
|
private logDir: string = DEFAULT_LOG_DIR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +45,7 @@ class Logger {
|
|||||||
* @param message Message to log
|
* @param message Message to log
|
||||||
*/
|
*/
|
||||||
error(message: string): void {
|
error(message: string): void {
|
||||||
this.log('error', message);
|
this.log("error", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,8 +53,8 @@ class Logger {
|
|||||||
* @param message Message to log
|
* @param message Message to log
|
||||||
*/
|
*/
|
||||||
warn(message: string): void {
|
warn(message: string): void {
|
||||||
if (['error', 'warn', 'info', 'debug'].includes(this.logLevel)) {
|
if (["error", "warn", "info", "debug"].includes(this.logLevel)) {
|
||||||
this.log('warn', message);
|
this.log("warn", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,8 +63,8 @@ class Logger {
|
|||||||
* @param message Message to log
|
* @param message Message to log
|
||||||
*/
|
*/
|
||||||
info(message: string): void {
|
info(message: string): void {
|
||||||
if (['info', 'debug'].includes(this.logLevel)) {
|
if (["info", "debug"].includes(this.logLevel)) {
|
||||||
this.log('info', message);
|
this.log("info", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +73,8 @@ class Logger {
|
|||||||
* @param message Message to log
|
* @param message Message to log
|
||||||
*/
|
*/
|
||||||
debug(message: string): void {
|
debug(message: string): void {
|
||||||
if (this.logLevel === 'debug') {
|
if (this.logLevel === "debug") {
|
||||||
this.log('debug', message);
|
this.log("debug", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,8 +85,9 @@ class Logger {
|
|||||||
*/
|
*/
|
||||||
private log(level: LogLevel, message: string): void {
|
private log(level: LogLevel, message: string): void {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const pad = (n: number, w = 2) => String(n).padStart(w, '0');
|
const pad = (n: number, w = 2) => String(n).padStart(w, "0");
|
||||||
const timestamp = `${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())} ` +
|
const timestamp =
|
||||||
|
`${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ` +
|
||||||
`${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())},${pad(now.getMilliseconds(), 3)}`;
|
`${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())},${pad(now.getMilliseconds(), 3)}`;
|
||||||
const formattedMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
|
const formattedMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
|
||||||
|
|
||||||
@@ -101,8 +102,8 @@ class Logger {
|
|||||||
mkdirSync(this.logDir, { recursive: true });
|
mkdirSync(this.logDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const logFile = join(this.logDir, `kicad-mcp-${new Date().toISOString().split('T')[0]}.log`);
|
const logFile = join(this.logDir, `kicad-mcp-${new Date().toISOString().split("T")[0]}.log`);
|
||||||
appendFileSync(logFile, formattedMessage + '\n');
|
appendFileSync(logFile, formattedMessage + "\n");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to write to log file: ${error}`);
|
console.error(`Failed to write to log file: ${error}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
* in KiCAD PCB design.
|
* in KiCAD PCB design.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register component prompts with the MCP server
|
* Register component prompts with the MCP server
|
||||||
@@ -15,7 +15,7 @@ import { logger } from '../logger.js';
|
|||||||
* @param server MCP server instance
|
* @param server MCP server instance
|
||||||
*/
|
*/
|
||||||
export function registerComponentPrompts(server: McpServer): void {
|
export function registerComponentPrompts(server: McpServer): void {
|
||||||
logger.info('Registering component prompts');
|
logger.info("Registering component prompts");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Component Selection Prompt
|
// Component Selection Prompt
|
||||||
@@ -23,7 +23,7 @@ export function registerComponentPrompts(server: McpServer): void {
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"component_selection",
|
"component_selection",
|
||||||
{
|
{
|
||||||
requirements: z.string().describe("Description of the circuit requirements and constraints")
|
requirements: z.string().describe("Description of the circuit requirements and constraints"),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -44,11 +44,11 @@ Suggest appropriate components with their values, ratings, and footprints. Consi
|
|||||||
- Thermal characteristics
|
- Thermal characteristics
|
||||||
- Performance specifications
|
- Performance specifications
|
||||||
|
|
||||||
For each component type, recommend specific values and provide a brief explanation of your recommendation. If appropriate, suggest alternatives with different trade-offs.`
|
For each component type, recommend specific values and provide a brief explanation of your recommendation. If appropriate, suggest alternatives with different trade-offs.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -57,7 +57,7 @@ For each component type, recommend specific values and provide a brief explanati
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"component_placement_strategy",
|
"component_placement_strategy",
|
||||||
{
|
{
|
||||||
components: z.string().describe("List of components to be placed on the PCB")
|
components: z.string().describe("List of components to be placed on the PCB"),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -91,11 +91,11 @@ Provide a strategy for optimal placement considering:
|
|||||||
- Adequate spacing for rework
|
- Adequate spacing for rework
|
||||||
- Consider component height distribution
|
- Consider component height distribution
|
||||||
|
|
||||||
Group components functionally and suggest a logical arrangement. If possible, provide a rough sketch or description of component zones.`
|
Group components functionally and suggest a logical arrangement. If possible, provide a rough sketch or description of component zones.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -104,7 +104,9 @@ Group components functionally and suggest a logical arrangement. If possible, pr
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"component_replacement_analysis",
|
"component_replacement_analysis",
|
||||||
{
|
{
|
||||||
component_info: z.string().describe("Information about the component that needs to be replaced")
|
component_info: z
|
||||||
|
.string()
|
||||||
|
.describe("Information about the component that needs to be replaced"),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -137,11 +139,11 @@ Consider these factors when suggesting replacements:
|
|||||||
- Cost comparison with original part
|
- Cost comparison with original part
|
||||||
- Lead time considerations
|
- Lead time considerations
|
||||||
|
|
||||||
Suggest suitable replacement options and explain the advantages and disadvantages of each. Include any circuit modifications that might be necessary.`
|
Suggest suitable replacement options and explain the advantages and disadvantages of each. Include any circuit modifications that might be necessary.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -150,7 +152,9 @@ Suggest suitable replacement options and explain the advantages and disadvantage
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"component_troubleshooting",
|
"component_troubleshooting",
|
||||||
{
|
{
|
||||||
issue_description: z.string().describe("Description of the component or circuit issue being troubleshooted")
|
issue_description: z
|
||||||
|
.string()
|
||||||
|
.describe("Description of the component or circuit issue being troubleshooted"),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -184,11 +188,11 @@ Use the following systematic approach to diagnose the problem:
|
|||||||
- Check for potential EMI/RFI issues
|
- Check for potential EMI/RFI issues
|
||||||
- Review mechanical stress or vibration effects
|
- Review mechanical stress or vibration effects
|
||||||
|
|
||||||
Based on the available information, suggest likely causes of the issue and recommend specific steps to diagnose and resolve the problem.`
|
Based on the available information, suggest likely causes of the issue and recommend specific steps to diagnose and resolve the problem.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -197,7 +201,9 @@ Based on the available information, suggest likely causes of the issue and recom
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"component_value_calculation",
|
"component_value_calculation",
|
||||||
{
|
{
|
||||||
circuit_requirements: z.string().describe("Description of the circuit function and performance requirements")
|
circuit_requirements: z
|
||||||
|
.string()
|
||||||
|
.describe("Description of the circuit function and performance requirements"),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -220,12 +226,12 @@ Follow these steps to determine the optimal component values:
|
|||||||
- Parasitic effects
|
- Parasitic effects
|
||||||
- Available standard values
|
- Available standard values
|
||||||
|
|
||||||
Present your calculations step-by-step, showing your work and explaining your reasoning. Recommend specific component values, explaining why they're appropriate for this application. If there are multiple valid approaches, discuss the trade-offs between them.`
|
Present your calculations step-by-step, showing your work and explaining your reasoning. Recommend specific component values, explaining why they're appropriate for this application. If there are multiple valid approaches, discuss the trade-offs between them.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Component prompts registered');
|
logger.info("Component prompts registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
* in KiCAD.
|
* in KiCAD.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register design prompts with the MCP server
|
* Register design prompts with the MCP server
|
||||||
@@ -15,7 +15,7 @@ import { logger } from '../logger.js';
|
|||||||
* @param server MCP server instance
|
* @param server MCP server instance
|
||||||
*/
|
*/
|
||||||
export function registerDesignPrompts(server: McpServer): void {
|
export function registerDesignPrompts(server: McpServer): void {
|
||||||
logger.info('Registering design prompts');
|
logger.info("Registering design prompts");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// PCB Layout Review Prompt
|
// PCB Layout Review Prompt
|
||||||
@@ -23,7 +23,11 @@ export function registerDesignPrompts(server: McpServer): void {
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"pcb_layout_review",
|
"pcb_layout_review",
|
||||||
{
|
{
|
||||||
pcb_design_info: z.string().describe("Information about the current PCB design, including board dimensions, layer stack-up, component placement, and routing details")
|
pcb_design_info: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the current PCB design, including board dimensions, layer stack-up, component placement, and routing details",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -71,11 +75,11 @@ When reviewing the PCB layout, consider these key areas:
|
|||||||
- Silkscreen clarity and usefulness
|
- Silkscreen clarity and usefulness
|
||||||
- Solder mask considerations
|
- Solder mask considerations
|
||||||
|
|
||||||
Based on the provided information, identify potential issues and suggest specific improvements to enhance the PCB design.`
|
Based on the provided information, identify potential issues and suggest specific improvements to enhance the PCB design.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -84,7 +88,11 @@ Based on the provided information, identify potential issues and suggest specifi
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"layer_stackup_planning",
|
"layer_stackup_planning",
|
||||||
{
|
{
|
||||||
design_requirements: z.string().describe("Information about the PCB design requirements, including signal types, speed/frequency, power requirements, and any special considerations")
|
design_requirements: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the PCB design requirements, including signal types, speed/frequency, power requirements, and any special considerations",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -128,11 +136,11 @@ When planning a PCB layer stack-up, consider these important factors:
|
|||||||
- Thermal properties
|
- Thermal properties
|
||||||
- Mechanical stability
|
- Mechanical stability
|
||||||
|
|
||||||
Based on the provided requirements, recommend an appropriate layer stack-up, including the number of layers, their arrangement, material specifications, and thickness parameters. Explain the rationale behind your recommendations.`
|
Based on the provided requirements, recommend an appropriate layer stack-up, including the number of layers, their arrangement, material specifications, and thickness parameters. Explain the rationale behind your recommendations.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -141,7 +149,11 @@ Based on the provided requirements, recommend an appropriate layer stack-up, inc
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"design_rule_development",
|
"design_rule_development",
|
||||||
{
|
{
|
||||||
project_requirements: z.string().describe("Information about the PCB project requirements, including technology, speed/frequency, manufacturing capabilities, and any special considerations")
|
project_requirements: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the PCB project requirements, including technology, speed/frequency, manufacturing capabilities, and any special considerations",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -185,11 +197,11 @@ When developing PCB design rules, consider these key areas:
|
|||||||
- Thermal relief parameters
|
- Thermal relief parameters
|
||||||
- Teardrop specifications
|
- Teardrop specifications
|
||||||
|
|
||||||
Based on the provided project requirements, recommend a comprehensive set of design rules that will ensure signal integrity, manufacturability, and reliability of the PCB. Provide specific values where appropriate and explain the rationale behind critical rules.`
|
Based on the provided project requirements, recommend a comprehensive set of design rules that will ensure signal integrity, manufacturability, and reliability of the PCB. Provide specific values where appropriate and explain the rationale behind critical rules.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -198,7 +210,11 @@ Based on the provided project requirements, recommend a comprehensive set of des
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"component_selection_guidance",
|
"component_selection_guidance",
|
||||||
{
|
{
|
||||||
circuit_requirements: z.string().describe("Information about the circuit requirements, including functionality, performance needs, operating environment, and any special considerations")
|
circuit_requirements: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the circuit requirements, including functionality, performance needs, operating environment, and any special considerations",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -246,11 +262,11 @@ When selecting components for a PCB design, consider these important factors:
|
|||||||
- RoHS/REACH compliance
|
- RoHS/REACH compliance
|
||||||
- Special handling requirements
|
- Special handling requirements
|
||||||
|
|
||||||
Based on the provided circuit requirements, recommend appropriate component types, packages, and specific considerations for this design. Provide guidance on critical component selections and explain the rationale behind your recommendations.`
|
Based on the provided circuit requirements, recommend appropriate component types, packages, and specific considerations for this design. Provide guidance on critical component selections and explain the rationale behind your recommendations.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -259,8 +275,16 @@ Based on the provided circuit requirements, recommend appropriate component type
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"pcb_design_optimization",
|
"pcb_design_optimization",
|
||||||
{
|
{
|
||||||
design_info: z.string().describe("Information about the current PCB design, including board dimensions, layer stack-up, component placement, and routing details"),
|
design_info: z
|
||||||
optimization_goals: z.string().describe("Specific goals for optimization, such as performance improvement, cost reduction, size reduction, or manufacturability enhancement")
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the current PCB design, including board dimensions, layer stack-up, component placement, and routing details",
|
||||||
|
),
|
||||||
|
optimization_goals: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Specific goals for optimization, such as performance improvement, cost reduction, size reduction, or manufacturability enhancement",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -310,12 +334,12 @@ When optimizing a PCB design, consider these key areas based on the stated goals
|
|||||||
- Alternative packaging approaches
|
- Alternative packaging approaches
|
||||||
- Connector and interface optimization
|
- Connector and interface optimization
|
||||||
|
|
||||||
Based on the provided information and optimization goals, suggest specific, actionable improvements to the PCB design. Prioritize your recommendations based on their potential impact and implementation feasibility.`
|
Based on the provided information and optimization goals, suggest specific, actionable improvements to the PCB design. Prioritize your recommendations based on their potential impact and implementation feasibility.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Design prompts registered');
|
logger.info("Design prompts registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ export function registerFootprintPrompts(server: McpServer): void {
|
|||||||
.describe(
|
.describe(
|
||||||
"Component description, e.g. 'SOT-23 NPN transistor' or '2-pin JST XH 2.5mm connector'",
|
"Component description, e.g. 'SOT-23 NPN transistor' or '2-pin JST XH 2.5mm connector'",
|
||||||
),
|
),
|
||||||
libraryPath: z
|
libraryPath: z.string().optional().describe("Target .pretty library path (optional)"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Target .pretty library path (optional)"),
|
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -107,9 +104,7 @@ Now create the footprint for: {{component}}`,
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"footprint_ipc_checklist",
|
"footprint_ipc_checklist",
|
||||||
{
|
{
|
||||||
footprintPath: z
|
footprintPath: z.string().describe("Path to the .kicad_mod file to review"),
|
||||||
.string()
|
|
||||||
.describe("Path to the .kicad_mod file to review"),
|
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
* in KiCAD PCB design.
|
* in KiCAD PCB design.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register routing prompts with the MCP server
|
* Register routing prompts with the MCP server
|
||||||
@@ -15,7 +15,7 @@ import { logger } from '../logger.js';
|
|||||||
* @param server MCP server instance
|
* @param server MCP server instance
|
||||||
*/
|
*/
|
||||||
export function registerRoutingPrompts(server: McpServer): void {
|
export function registerRoutingPrompts(server: McpServer): void {
|
||||||
logger.info('Registering routing prompts');
|
logger.info("Registering routing prompts");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Routing Strategy Prompt
|
// Routing Strategy Prompt
|
||||||
@@ -23,7 +23,11 @@ export function registerRoutingPrompts(server: McpServer): void {
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"routing_strategy",
|
"routing_strategy",
|
||||||
{
|
{
|
||||||
board_info: z.string().describe("Information about the PCB board, including dimensions, layer stack-up, and components")
|
board_info: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the PCB board, including dimensions, layer stack-up, and components",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -63,11 +67,11 @@ Consider the following aspects when developing your routing strategy:
|
|||||||
- Plan for layer transitions (vias)
|
- Plan for layer transitions (vias)
|
||||||
- Consider impedance control requirements
|
- Consider impedance control requirements
|
||||||
|
|
||||||
Provide a comprehensive routing strategy that addresses these aspects, with specific recommendations for this particular board design.`
|
Provide a comprehensive routing strategy that addresses these aspects, with specific recommendations for this particular board design.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -76,7 +80,11 @@ Provide a comprehensive routing strategy that addresses these aspects, with spec
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"differential_pair_routing",
|
"differential_pair_routing",
|
||||||
{
|
{
|
||||||
differential_pairs: z.string().describe("Information about the differential pairs to be routed, including signal names, source and destination components, and speed/frequency requirements")
|
differential_pairs: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the differential pairs to be routed, including signal names, source and destination components, and speed/frequency requirements",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -115,11 +123,11 @@ When routing differential pairs, follow these best practices:
|
|||||||
- Consider the need for series or parallel termination resistors
|
- Consider the need for series or parallel termination resistors
|
||||||
- Place termination components close to the endpoints
|
- Place termination components close to the endpoints
|
||||||
|
|
||||||
Based on the provided information, suggest specific routing approaches for these differential pairs, including recommended trace width, spacing, and any special considerations for this particular design.`
|
Based on the provided information, suggest specific routing approaches for these differential pairs, including recommended trace width, spacing, and any special considerations for this particular design.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -128,7 +136,11 @@ Based on the provided information, suggest specific routing approaches for these
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"high_speed_routing",
|
"high_speed_routing",
|
||||||
{
|
{
|
||||||
high_speed_signals: z.string().describe("Information about the high-speed signals to be routed, including signal names, source and destination components, and speed/frequency requirements")
|
high_speed_signals: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the high-speed signals to be routed, including signal names, source and destination components, and speed/frequency requirements",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -168,11 +180,11 @@ When routing high-speed signals, consider these critical factors:
|
|||||||
- Consider transmission line effects
|
- Consider transmission line effects
|
||||||
- Account for capacitive loading from components and vias
|
- Account for capacitive loading from components and vias
|
||||||
|
|
||||||
Based on the provided information, suggest specific routing approaches for these high-speed signals, including recommended trace width, layer assignment, and any special considerations for this particular design.`
|
Based on the provided information, suggest specific routing approaches for these high-speed signals, including recommended trace width, layer assignment, and any special considerations for this particular design.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -181,7 +193,11 @@ Based on the provided information, suggest specific routing approaches for these
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"power_distribution",
|
"power_distribution",
|
||||||
{
|
{
|
||||||
power_requirements: z.string().describe("Information about the power requirements, including voltage rails, current needs, and components requiring power")
|
power_requirements: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the power requirements, including voltage rails, current needs, and components requiring power",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -221,11 +237,11 @@ Consider these key aspects of power distribution network design:
|
|||||||
- Keep power and ground planes closely coupled
|
- Keep power and ground planes closely coupled
|
||||||
- Consider filtering for noise-sensitive circuits
|
- Consider filtering for noise-sensitive circuits
|
||||||
|
|
||||||
Based on the provided information, suggest a comprehensive power distribution strategy, including specific recommendations for plane usage, trace widths, decoupling, and any special considerations for this particular design.`
|
Based on the provided information, suggest a comprehensive power distribution strategy, including specific recommendations for plane usage, trace widths, decoupling, and any special considerations for this particular design.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -234,7 +250,11 @@ Based on the provided information, suggest a comprehensive power distribution st
|
|||||||
server.prompt(
|
server.prompt(
|
||||||
"via_usage",
|
"via_usage",
|
||||||
{
|
{
|
||||||
board_info: z.string().describe("Information about the PCB board, including layer count, thickness, and design requirements")
|
board_info: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"Information about the PCB board, including layer count, thickness, and design requirements",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => ({
|
() => ({
|
||||||
messages: [
|
messages: [
|
||||||
@@ -277,12 +297,12 @@ Consider these important aspects of via usage:
|
|||||||
- Via placement to minimize trace length
|
- Via placement to minimize trace length
|
||||||
- Tenting and plugging options
|
- Tenting and plugging options
|
||||||
|
|
||||||
Based on the provided information, recommend appropriate via strategies for this PCB design, including specific via types, sizes, and placement guidelines.`
|
Based on the provided information, recommend appropriate via strategies for this PCB design, including specific via types, sizes, and placement guidelines.`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Routing prompts registered');
|
logger.info("Routing prompts registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
* to the LLM, enabling better context-aware assistance.
|
* to the LLM, enabling better context-aware assistance.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
import { createJsonResponse, createBinaryResponse } from '../utils/resource-helpers.js';
|
import { createJsonResponse, createBinaryResponse } from "../utils/resource-helpers.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
@@ -20,77 +20,77 @@ type CommandFunction = (command: string, params: Record<string, unknown>) => Pro
|
|||||||
* @param callKicadScript Function to call KiCAD script commands
|
* @param callKicadScript Function to call KiCAD script commands
|
||||||
*/
|
*/
|
||||||
export function registerBoardResources(server: McpServer, callKicadScript: CommandFunction): void {
|
export function registerBoardResources(server: McpServer, callKicadScript: CommandFunction): void {
|
||||||
logger.info('Registering board resources');
|
logger.info("Registering board resources");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Board Information Resource
|
// Board Information Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("board_info", "kicad://board/info", async (uri) => {
|
||||||
"board_info",
|
logger.debug("Retrieving board information");
|
||||||
"kicad://board/info",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving board information');
|
|
||||||
const result = await callKicadScript("get_board_info", {});
|
const result = await callKicadScript("get_board_info", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve board information: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve board information: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve board information",
|
error: "Failed to retrieve board information",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Successfully retrieved board information');
|
logger.debug("Successfully retrieved board information");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Layer List Resource
|
// Layer List Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("layer_list", "kicad://board/layers", async (uri) => {
|
||||||
"layer_list",
|
logger.debug("Retrieving layer list");
|
||||||
"kicad://board/layers",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving layer list');
|
|
||||||
const result = await callKicadScript("get_layer_list", {});
|
const result = await callKicadScript("get_layer_list", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve layer list: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve layer list: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve layer list",
|
error: "Failed to retrieve layer list",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved ${result.layers?.length || 0} layers`);
|
logger.debug(`Successfully retrieved ${result.layers?.length || 0} layers`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Board Extents Resource
|
// Board Extents Resource
|
||||||
@@ -101,12 +101,12 @@ export function registerBoardResources(server: McpServer, callKicadScript: Comma
|
|||||||
list: async () => ({
|
list: async () => ({
|
||||||
resources: [
|
resources: [
|
||||||
{ uri: "kicad://board/extents/mm", name: "Millimeters" },
|
{ uri: "kicad://board/extents/mm", name: "Millimeters" },
|
||||||
{ uri: "kicad://board/extents/inch", name: "Inches" }
|
{ uri: "kicad://board/extents/inch", name: "Inches" },
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const unit = params.unit || 'mm';
|
const unit = params.unit || "mm";
|
||||||
|
|
||||||
logger.debug(`Retrieving board extents in ${unit}`);
|
logger.debug(`Retrieving board extents in ${unit}`);
|
||||||
const result = await callKicadScript("get_board_extents", { unit });
|
const result = await callKicadScript("get_board_extents", { unit });
|
||||||
@@ -114,26 +114,30 @@ export function registerBoardResources(server: McpServer, callKicadScript: Comma
|
|||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve board extents: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve board extents: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve board extents",
|
error: "Failed to retrieve board extents",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Successfully retrieved board extents');
|
logger.debug("Successfully retrieved board extents");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -146,59 +150,65 @@ export function registerBoardResources(server: McpServer, callKicadScript: Comma
|
|||||||
resources: [
|
resources: [
|
||||||
{ uri: "kicad://board/2d-view/png", name: "PNG Format" },
|
{ uri: "kicad://board/2d-view/png", name: "PNG Format" },
|
||||||
{ uri: "kicad://board/2d-view/jpg", name: "JPEG Format" },
|
{ uri: "kicad://board/2d-view/jpg", name: "JPEG Format" },
|
||||||
{ uri: "kicad://board/2d-view/svg", name: "SVG Format" }
|
{ uri: "kicad://board/2d-view/svg", name: "SVG Format" },
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const format = (params.format || 'png') as 'png' | 'jpg' | 'svg';
|
const format = (params.format || "png") as "png" | "jpg" | "svg";
|
||||||
const width = params.width ? parseInt(params.width as string) : undefined;
|
const width = params.width ? parseInt(params.width as string) : undefined;
|
||||||
const height = params.height ? parseInt(params.height as string) : undefined;
|
const height = params.height ? parseInt(params.height as string) : undefined;
|
||||||
// Handle layers parameter - could be string or array
|
// Handle layers parameter - could be string or array
|
||||||
const layers = typeof params.layers === 'string' ? params.layers.split(',') : params.layers;
|
const layers = typeof params.layers === "string" ? params.layers.split(",") : params.layers;
|
||||||
|
|
||||||
logger.debug('Retrieving 2D board view');
|
logger.debug("Retrieving 2D board view");
|
||||||
const result = await callKicadScript("get_board_2d_view", {
|
const result = await callKicadScript("get_board_2d_view", {
|
||||||
layers,
|
layers,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
format
|
format,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve 2D board view: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve 2D board view: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve 2D board view",
|
error: "Failed to retrieve 2D board view",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Successfully retrieved 2D board view');
|
logger.debug("Successfully retrieved 2D board view");
|
||||||
|
|
||||||
if (format === 'svg') {
|
if (format === "svg") {
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: result.imageData,
|
text: result.imageData,
|
||||||
mimeType: "image/svg+xml"
|
mimeType: "image/svg+xml",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
blob: result.imageData,
|
blob: result.imageData,
|
||||||
mimeType: format === "jpg" ? "image/jpeg" : "image/png"
|
mimeType: format === "jpg" ? "image/jpeg" : "image/png",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -211,12 +221,12 @@ export function registerBoardResources(server: McpServer, callKicadScript: Comma
|
|||||||
resources: [
|
resources: [
|
||||||
{ uri: "kicad://board/3d-view/isometric", name: "Isometric View" },
|
{ uri: "kicad://board/3d-view/isometric", name: "Isometric View" },
|
||||||
{ uri: "kicad://board/3d-view/top", name: "Top View" },
|
{ uri: "kicad://board/3d-view/top", name: "Top View" },
|
||||||
{ uri: "kicad://board/3d-view/bottom", name: "Bottom View" }
|
{ uri: "kicad://board/3d-view/bottom", name: "Bottom View" },
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const angle = params.angle || 'isometric';
|
const angle = params.angle || "isometric";
|
||||||
const width = params.width ? parseInt(params.width as string) : undefined;
|
const width = params.width ? parseInt(params.width as string) : undefined;
|
||||||
const height = params.height ? parseInt(params.height as string) : undefined;
|
const height = params.height ? parseInt(params.height as string) : undefined;
|
||||||
|
|
||||||
@@ -224,56 +234,59 @@ export function registerBoardResources(server: McpServer, callKicadScript: Comma
|
|||||||
const result = await callKicadScript("get_board_3d_view", {
|
const result = await callKicadScript("get_board_3d_view", {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
angle
|
angle,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve 3D board view: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve 3D board view: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve 3D board view",
|
error: "Failed to retrieve 3D board view",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Successfully retrieved 3D board view');
|
logger.debug("Successfully retrieved 3D board view");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
blob: result.imageData,
|
blob: result.imageData,
|
||||||
mimeType: "image/png"
|
mimeType: "image/png",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Board Statistics Resource
|
// Board Statistics Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("board_statistics", "kicad://board/statistics", async (uri) => {
|
||||||
"board_statistics",
|
logger.debug("Generating board statistics");
|
||||||
"kicad://board/statistics",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Generating board statistics');
|
|
||||||
|
|
||||||
// Get board info
|
// Get board info
|
||||||
const boardResult = await callKicadScript("get_board_info", {});
|
const boardResult = await callKicadScript("get_board_info", {});
|
||||||
if (!boardResult.success) {
|
if (!boardResult.success) {
|
||||||
logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`);
|
logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to generate board statistics",
|
error: "Failed to generate board statistics",
|
||||||
details: boardResult.errorDetails
|
details: boardResult.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,14 +295,16 @@ export function registerBoardResources(server: McpServer, callKicadScript: Comma
|
|||||||
if (!componentsResult.success) {
|
if (!componentsResult.success) {
|
||||||
logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`);
|
logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to generate board statistics",
|
error: "Failed to generate board statistics",
|
||||||
details: componentsResult.errorDetails
|
details: componentsResult.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,14 +313,16 @@ export function registerBoardResources(server: McpServer, callKicadScript: Comma
|
|||||||
if (!netsResult.success) {
|
if (!netsResult.success) {
|
||||||
logger.error(`Failed to retrieve nets list: ${netsResult.errorDetails}`);
|
logger.error(`Failed to retrieve nets list: ${netsResult.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to generate board statistics",
|
error: "Failed to generate board statistics",
|
||||||
details: netsResult.errorDetails
|
details: netsResult.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,29 +331,30 @@ export function registerBoardResources(server: McpServer, callKicadScript: Comma
|
|||||||
board: {
|
board: {
|
||||||
size: boardResult.size,
|
size: boardResult.size,
|
||||||
layers: boardResult.layers?.length || 0,
|
layers: boardResult.layers?.length || 0,
|
||||||
title: boardResult.title
|
title: boardResult.title,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
count: componentsResult.components?.length || 0,
|
count: componentsResult.components?.length || 0,
|
||||||
types: countComponentTypes(componentsResult.components || [])
|
types: countComponentTypes(componentsResult.components || []),
|
||||||
},
|
},
|
||||||
nets: {
|
nets: {
|
||||||
count: netsResult.nets?.length || 0
|
count: netsResult.nets?.length || 0,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.debug('Successfully generated board statistics');
|
logger.debug("Successfully generated board statistics");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(statistics),
|
text: JSON.stringify(statistics),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
logger.info('Board resources registered');
|
logger.info("Board resources registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -346,7 +364,7 @@ function countComponentTypes(components: any[]): Record<string, number> {
|
|||||||
const typeCounts: Record<string, number> = {};
|
const typeCounts: Record<string, number> = {};
|
||||||
|
|
||||||
for (const component of components) {
|
for (const component of components) {
|
||||||
const type = component.value?.split(' ')[0] || 'Unknown';
|
const type = component.value?.split(" ")[0] || "Unknown";
|
||||||
typeCounts[type] = (typeCounts[type] || 0) + 1;
|
typeCounts[type] = (typeCounts[type] || 0) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
* to the LLM, enabling better context-aware assistance.
|
* to the LLM, enabling better context-aware assistance.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
@@ -17,43 +17,46 @@ type CommandFunction = (command: string, params: Record<string, unknown>) => Pro
|
|||||||
* @param server MCP server instance
|
* @param server MCP server instance
|
||||||
* @param callKicadScript Function to call KiCAD script commands
|
* @param callKicadScript Function to call KiCAD script commands
|
||||||
*/
|
*/
|
||||||
export function registerComponentResources(server: McpServer, callKicadScript: CommandFunction): void {
|
export function registerComponentResources(
|
||||||
logger.info('Registering component resources');
|
server: McpServer,
|
||||||
|
callKicadScript: CommandFunction,
|
||||||
|
): void {
|
||||||
|
logger.info("Registering component resources");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Component List Resource
|
// Component List Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("component_list", "kicad://components", async (uri) => {
|
||||||
"component_list",
|
logger.debug("Retrieving component list");
|
||||||
"kicad://components",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving component list');
|
|
||||||
const result = await callKicadScript("get_component_list", {});
|
const result = await callKicadScript("get_component_list", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component list: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component list: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve component list",
|
error: "Failed to retrieve component list",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved ${result.components?.length || 0} components`);
|
logger.debug(`Successfully retrieved ${result.components?.length || 0} components`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Component Details Resource
|
// Component Details Resource
|
||||||
@@ -61,38 +64,42 @@ export function registerComponentResources(server: McpServer, callKicadScript: C
|
|||||||
server.resource(
|
server.resource(
|
||||||
"component_details",
|
"component_details",
|
||||||
new ResourceTemplate("kicad://component/{reference}/details", {
|
new ResourceTemplate("kicad://component/{reference}/details", {
|
||||||
list: undefined
|
list: undefined,
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const { reference } = params;
|
const { reference } = params;
|
||||||
logger.debug(`Retrieving details for component: ${reference}`);
|
logger.debug(`Retrieving details for component: ${reference}`);
|
||||||
const result = await callKicadScript("get_component_properties", {
|
const result = await callKicadScript("get_component_properties", {
|
||||||
reference
|
reference,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component details: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component details: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Failed to retrieve details for component ${reference}`,
|
error: `Failed to retrieve details for component ${reference}`,
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved details for component: ${reference}`);
|
logger.debug(`Successfully retrieved details for component: ${reference}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -101,109 +108,113 @@ export function registerComponentResources(server: McpServer, callKicadScript: C
|
|||||||
server.resource(
|
server.resource(
|
||||||
"component_connections",
|
"component_connections",
|
||||||
new ResourceTemplate("kicad://component/{reference}/connections", {
|
new ResourceTemplate("kicad://component/{reference}/connections", {
|
||||||
list: undefined
|
list: undefined,
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const { reference } = params;
|
const { reference } = params;
|
||||||
logger.debug(`Retrieving connections for component: ${reference}`);
|
logger.debug(`Retrieving connections for component: ${reference}`);
|
||||||
const result = await callKicadScript("get_component_connections", {
|
const result = await callKicadScript("get_component_connections", {
|
||||||
reference
|
reference,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component connections: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component connections: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Failed to retrieve connections for component ${reference}`,
|
error: `Failed to retrieve connections for component ${reference}`,
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved connections for component: ${reference}`);
|
logger.debug(`Successfully retrieved connections for component: ${reference}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Component Placement Resource
|
// Component Placement Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("component_placement", "kicad://components/placement", async (uri) => {
|
||||||
"component_placement",
|
logger.debug("Retrieving component placement information");
|
||||||
"kicad://components/placement",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving component placement information');
|
|
||||||
const result = await callKicadScript("get_component_placement", {});
|
const result = await callKicadScript("get_component_placement", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component placement: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component placement: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve component placement information",
|
error: "Failed to retrieve component placement information",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Successfully retrieved component placement information');
|
logger.debug("Successfully retrieved component placement information");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Component Groups Resource
|
// Component Groups Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("component_groups", "kicad://components/groups", async (uri) => {
|
||||||
"component_groups",
|
logger.debug("Retrieving component groups");
|
||||||
"kicad://components/groups",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving component groups');
|
|
||||||
const result = await callKicadScript("get_component_groups", {});
|
const result = await callKicadScript("get_component_groups", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component groups: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component groups: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve component groups",
|
error: "Failed to retrieve component groups",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved ${result.groups?.length || 0} component groups`);
|
logger.debug(`Successfully retrieved ${result.groups?.length || 0} component groups`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Component Visualization Resource
|
// Component Visualization Resource
|
||||||
@@ -211,39 +222,43 @@ export function registerComponentResources(server: McpServer, callKicadScript: C
|
|||||||
server.resource(
|
server.resource(
|
||||||
"component_visualization",
|
"component_visualization",
|
||||||
new ResourceTemplate("kicad://component/{reference}/visualization", {
|
new ResourceTemplate("kicad://component/{reference}/visualization", {
|
||||||
list: undefined
|
list: undefined,
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const { reference } = params;
|
const { reference } = params;
|
||||||
logger.debug(`Generating visualization for component: ${reference}`);
|
logger.debug(`Generating visualization for component: ${reference}`);
|
||||||
const result = await callKicadScript("get_component_visualization", {
|
const result = await callKicadScript("get_component_visualization", {
|
||||||
reference
|
reference,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to generate component visualization: ${result.errorDetails}`);
|
logger.error(`Failed to generate component visualization: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Failed to generate visualization for component ${reference}`,
|
error: `Failed to generate visualization for component ${reference}`,
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully generated visualization for component: ${reference}`);
|
logger.debug(`Successfully generated visualization for component: ${reference}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
blob: result.imageData, // Base64 encoded image data
|
blob: result.imageData, // Base64 encoded image data
|
||||||
mimeType: "image/png"
|
mimeType: "image/png",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Component resources registered');
|
logger.info("Component resources registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Exports all resource registration functions
|
* Exports all resource registration functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { registerProjectResources } from './project.js';
|
export { registerProjectResources } from "./project.js";
|
||||||
export { registerBoardResources } from './board.js';
|
export { registerBoardResources } from "./board.js";
|
||||||
export { registerComponentResources } from './component.js';
|
export { registerComponentResources } from "./component.js";
|
||||||
export { registerLibraryResources } from './library.js';
|
export { registerLibraryResources } from "./library.js";
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
* to the LLM, enabling better context-aware assistance.
|
* to the LLM, enabling better context-aware assistance.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
@@ -18,8 +18,11 @@ type CommandFunction = (command: string, params: Record<string, unknown>) => Pro
|
|||||||
* @param server MCP server instance
|
* @param server MCP server instance
|
||||||
* @param callKicadScript Function to call KiCAD script commands
|
* @param callKicadScript Function to call KiCAD script commands
|
||||||
*/
|
*/
|
||||||
export function registerLibraryResources(server: McpServer, callKicadScript: CommandFunction): void {
|
export function registerLibraryResources(
|
||||||
logger.info('Registering library resources');
|
server: McpServer,
|
||||||
|
callKicadScript: CommandFunction,
|
||||||
|
): void {
|
||||||
|
logger.info("Registering library resources");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Component Library Resource
|
// Component Library Resource
|
||||||
@@ -28,83 +31,89 @@ export function registerLibraryResources(server: McpServer, callKicadScript: Com
|
|||||||
"component_library",
|
"component_library",
|
||||||
new ResourceTemplate("kicad://components/{filter?}/{library?}", {
|
new ResourceTemplate("kicad://components/{filter?}/{library?}", {
|
||||||
list: async () => ({
|
list: async () => ({
|
||||||
resources: [
|
resources: [{ uri: "kicad://components", name: "All Components" }],
|
||||||
{ uri: "kicad://components", name: "All Components" }
|
}),
|
||||||
]
|
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const filter = params.filter || '';
|
const filter = params.filter || "";
|
||||||
const library = params.library || '';
|
const library = params.library || "";
|
||||||
const limit = Number(params.limit) || undefined;
|
const limit = Number(params.limit) || undefined;
|
||||||
|
|
||||||
logger.debug(`Retrieving component library${filter ? ` with filter: ${filter}` : ''}${library ? ` from library: ${library}` : ''}`);
|
logger.debug(
|
||||||
|
`Retrieving component library${filter ? ` with filter: ${filter}` : ""}${library ? ` from library: ${library}` : ""}`,
|
||||||
|
);
|
||||||
|
|
||||||
const result = await callKicadScript("get_component_library", {
|
const result = await callKicadScript("get_component_library", {
|
||||||
filter,
|
filter,
|
||||||
library,
|
library,
|
||||||
limit
|
limit,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component library: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component library: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve component library",
|
error: "Failed to retrieve component library",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved ${result.components?.length || 0} components from library`);
|
logger.debug(
|
||||||
|
`Successfully retrieved ${result.components?.length || 0} components from library`,
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Library List Resource
|
// Library List Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("library_list", "kicad://libraries", async (uri) => {
|
||||||
"library_list",
|
logger.debug("Retrieving library list");
|
||||||
"kicad://libraries",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving library list');
|
|
||||||
const result = await callKicadScript("get_library_list", {});
|
const result = await callKicadScript("get_library_list", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve library list: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve library list: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve library list",
|
error: "Failed to retrieve library list",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved ${result.libraries?.length || 0} libraries`);
|
logger.debug(`Successfully retrieved ${result.libraries?.length || 0} libraries`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Library Component Details Resource
|
// Library Component Details Resource
|
||||||
@@ -112,40 +121,46 @@ export function registerLibraryResources(server: McpServer, callKicadScript: Com
|
|||||||
server.resource(
|
server.resource(
|
||||||
"library_component_details",
|
"library_component_details",
|
||||||
new ResourceTemplate("kicad://library/component/{componentId}/{library?}", {
|
new ResourceTemplate("kicad://library/component/{componentId}/{library?}", {
|
||||||
list: undefined
|
list: undefined,
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const { componentId, library } = params;
|
const { componentId, library } = params;
|
||||||
logger.debug(`Retrieving details for component: ${componentId}${library ? ` from library: ${library}` : ''}`);
|
logger.debug(
|
||||||
|
`Retrieving details for component: ${componentId}${library ? ` from library: ${library}` : ""}`,
|
||||||
|
);
|
||||||
|
|
||||||
const result = await callKicadScript("get_component_details", {
|
const result = await callKicadScript("get_component_details", {
|
||||||
componentId,
|
componentId,
|
||||||
library
|
library,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component details: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component details: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Failed to retrieve details for component ${componentId}`,
|
error: `Failed to retrieve details for component ${componentId}`,
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved details for component: ${componentId}`);
|
logger.debug(`Successfully retrieved details for component: ${componentId}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -154,40 +169,46 @@ export function registerLibraryResources(server: McpServer, callKicadScript: Com
|
|||||||
server.resource(
|
server.resource(
|
||||||
"component_footprint",
|
"component_footprint",
|
||||||
new ResourceTemplate("kicad://footprint/{componentId}/{footprint?}", {
|
new ResourceTemplate("kicad://footprint/{componentId}/{footprint?}", {
|
||||||
list: undefined
|
list: undefined,
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const { componentId, footprint } = params;
|
const { componentId, footprint } = params;
|
||||||
logger.debug(`Retrieving footprint for component: ${componentId}${footprint ? ` (${footprint})` : ''}`);
|
logger.debug(
|
||||||
|
`Retrieving footprint for component: ${componentId}${footprint ? ` (${footprint})` : ""}`,
|
||||||
|
);
|
||||||
|
|
||||||
const result = await callKicadScript("get_component_footprint", {
|
const result = await callKicadScript("get_component_footprint", {
|
||||||
componentId,
|
componentId,
|
||||||
footprint
|
footprint,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component footprint: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component footprint: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Failed to retrieve footprint for component ${componentId}`,
|
error: `Failed to retrieve footprint for component ${componentId}`,
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved footprint for component: ${componentId}`);
|
logger.debug(`Successfully retrieved footprint for component: ${componentId}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -196,27 +217,29 @@ export function registerLibraryResources(server: McpServer, callKicadScript: Com
|
|||||||
server.resource(
|
server.resource(
|
||||||
"component_symbol",
|
"component_symbol",
|
||||||
new ResourceTemplate("kicad://symbol/{componentId}", {
|
new ResourceTemplate("kicad://symbol/{componentId}", {
|
||||||
list: undefined
|
list: undefined,
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const { componentId } = params;
|
const { componentId } = params;
|
||||||
logger.debug(`Retrieving symbol for component: ${componentId}`);
|
logger.debug(`Retrieving symbol for component: ${componentId}`);
|
||||||
|
|
||||||
const result = await callKicadScript("get_component_symbol", {
|
const result = await callKicadScript("get_component_symbol", {
|
||||||
componentId
|
componentId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component symbol: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component symbol: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Failed to retrieve symbol for component ${componentId}`,
|
error: `Failed to retrieve symbol for component ${componentId}`,
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,23 +248,27 @@ export function registerLibraryResources(server: McpServer, callKicadScript: Com
|
|||||||
// If the result includes SVG data, return it as SVG
|
// If the result includes SVG data, return it as SVG
|
||||||
if (result.svgData) {
|
if (result.svgData) {
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: result.svgData,
|
text: result.svgData,
|
||||||
mimeType: "image/svg+xml"
|
mimeType: "image/svg+xml",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise return the JSON result
|
// Otherwise return the JSON result
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -250,41 +277,47 @@ export function registerLibraryResources(server: McpServer, callKicadScript: Com
|
|||||||
server.resource(
|
server.resource(
|
||||||
"component_3d_model",
|
"component_3d_model",
|
||||||
new ResourceTemplate("kicad://3d-model/{componentId}/{footprint?}", {
|
new ResourceTemplate("kicad://3d-model/{componentId}/{footprint?}", {
|
||||||
list: undefined
|
list: undefined,
|
||||||
}),
|
}),
|
||||||
async (uri, params) => {
|
async (uri, params) => {
|
||||||
const { componentId, footprint } = params;
|
const { componentId, footprint } = params;
|
||||||
logger.debug(`Retrieving 3D model for component: ${componentId}${footprint ? ` (${footprint})` : ''}`);
|
logger.debug(
|
||||||
|
`Retrieving 3D model for component: ${componentId}${footprint ? ` (${footprint})` : ""}`,
|
||||||
|
);
|
||||||
|
|
||||||
const result = await callKicadScript("get_component_3d_model", {
|
const result = await callKicadScript("get_component_3d_model", {
|
||||||
componentId,
|
componentId,
|
||||||
footprint
|
footprint,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve component 3D model: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve component 3D model: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: `Failed to retrieve 3D model for component ${componentId}`,
|
error: `Failed to retrieve 3D model for component ${componentId}`,
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved 3D model for component: ${componentId}`);
|
logger.debug(`Successfully retrieved 3D model for component: ${componentId}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Library resources registered');
|
logger.info("Library resources registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
* to the LLM, enabling better context-aware assistance.
|
* to the LLM, enabling better context-aware assistance.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
@@ -17,171 +17,173 @@ type CommandFunction = (command: string, params: Record<string, unknown>) => Pro
|
|||||||
* @param server MCP server instance
|
* @param server MCP server instance
|
||||||
* @param callKicadScript Function to call KiCAD script commands
|
* @param callKicadScript Function to call KiCAD script commands
|
||||||
*/
|
*/
|
||||||
export function registerProjectResources(server: McpServer, callKicadScript: CommandFunction): void {
|
export function registerProjectResources(
|
||||||
logger.info('Registering project resources');
|
server: McpServer,
|
||||||
|
callKicadScript: CommandFunction,
|
||||||
|
): void {
|
||||||
|
logger.info("Registering project resources");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Project Information Resource
|
// Project Information Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("project_info", "kicad://project/info", async (uri) => {
|
||||||
"project_info",
|
logger.debug("Retrieving project information");
|
||||||
"kicad://project/info",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving project information');
|
|
||||||
const result = await callKicadScript("get_project_info", {});
|
const result = await callKicadScript("get_project_info", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve project information: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve project information: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve project information",
|
error: "Failed to retrieve project information",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Successfully retrieved project information');
|
logger.debug("Successfully retrieved project information");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Project Properties Resource
|
// Project Properties Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("project_properties", "kicad://project/properties", async (uri) => {
|
||||||
"project_properties",
|
logger.debug("Retrieving project properties");
|
||||||
"kicad://project/properties",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving project properties');
|
|
||||||
const result = await callKicadScript("get_project_properties", {});
|
const result = await callKicadScript("get_project_properties", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve project properties: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve project properties: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve project properties",
|
error: "Failed to retrieve project properties",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Successfully retrieved project properties');
|
logger.debug("Successfully retrieved project properties");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Project Files Resource
|
// Project Files Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("project_files", "kicad://project/files", async (uri) => {
|
||||||
"project_files",
|
logger.debug("Retrieving project files");
|
||||||
"kicad://project/files",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving project files');
|
|
||||||
const result = await callKicadScript("get_project_files", {});
|
const result = await callKicadScript("get_project_files", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve project files: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve project files: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve project files",
|
error: "Failed to retrieve project files",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Successfully retrieved ${result.files?.length || 0} project files`);
|
logger.debug(`Successfully retrieved ${result.files?.length || 0} project files`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Project Status Resource
|
// Project Status Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("project_status", "kicad://project/status", async (uri) => {
|
||||||
"project_status",
|
logger.debug("Retrieving project status");
|
||||||
"kicad://project/status",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Retrieving project status');
|
|
||||||
const result = await callKicadScript("get_project_status", {});
|
const result = await callKicadScript("get_project_status", {});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
logger.error(`Failed to retrieve project status: ${result.errorDetails}`);
|
logger.error(`Failed to retrieve project status: ${result.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to retrieve project status",
|
error: "Failed to retrieve project status",
|
||||||
details: result.errorDetails
|
details: result.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Successfully retrieved project status');
|
logger.debug("Successfully retrieved project status");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(result),
|
text: JSON.stringify(result),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Project Summary Resource
|
// Project Summary Resource
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.resource(
|
server.resource("project_summary", "kicad://project/summary", async (uri) => {
|
||||||
"project_summary",
|
logger.debug("Generating project summary");
|
||||||
"kicad://project/summary",
|
|
||||||
async (uri) => {
|
|
||||||
logger.debug('Generating project summary');
|
|
||||||
|
|
||||||
// Get project info
|
// Get project info
|
||||||
const infoResult = await callKicadScript("get_project_info", {});
|
const infoResult = await callKicadScript("get_project_info", {});
|
||||||
if (!infoResult.success) {
|
if (!infoResult.success) {
|
||||||
logger.error(`Failed to retrieve project information: ${infoResult.errorDetails}`);
|
logger.error(`Failed to retrieve project information: ${infoResult.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to generate project summary",
|
error: "Failed to generate project summary",
|
||||||
details: infoResult.errorDetails
|
details: infoResult.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,14 +192,16 @@ export function registerProjectResources(server: McpServer, callKicadScript: Com
|
|||||||
if (!boardResult.success) {
|
if (!boardResult.success) {
|
||||||
logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`);
|
logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to generate project summary",
|
error: "Failed to generate project summary",
|
||||||
details: boardResult.errorDetails
|
details: boardResult.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,14 +210,16 @@ export function registerProjectResources(server: McpServer, callKicadScript: Com
|
|||||||
if (!componentsResult.success) {
|
if (!componentsResult.success) {
|
||||||
logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`);
|
logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`);
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
error: "Failed to generate project summary",
|
error: "Failed to generate project summary",
|
||||||
details: componentsResult.errorDetails
|
details: componentsResult.errorDetails,
|
||||||
}),
|
}),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,26 +229,27 @@ export function registerProjectResources(server: McpServer, callKicadScript: Com
|
|||||||
board: {
|
board: {
|
||||||
size: boardResult.size,
|
size: boardResult.size,
|
||||||
layers: boardResult.layers?.length || 0,
|
layers: boardResult.layers?.length || 0,
|
||||||
title: boardResult.title
|
title: boardResult.title,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
count: componentsResult.components?.length || 0,
|
count: componentsResult.components?.length || 0,
|
||||||
types: countComponentTypes(componentsResult.components || [])
|
types: countComponentTypes(componentsResult.components || []),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.debug('Successfully generated project summary');
|
logger.debug("Successfully generated project summary");
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri.href,
|
uri: uri.href,
|
||||||
text: JSON.stringify(summary),
|
text: JSON.stringify(summary),
|
||||||
mimeType: "application/json"
|
mimeType: "application/json",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
logger.info('Project resources registered');
|
logger.info("Project resources registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,7 +259,7 @@ function countComponentTypes(components: any[]): Record<string, number> {
|
|||||||
const typeCounts: Record<string, number> = {};
|
const typeCounts: Record<string, number> = {};
|
||||||
|
|
||||||
for (const component of components) {
|
for (const component of components) {
|
||||||
const type = component.value?.split(' ')[0] || 'Unknown';
|
const type = component.value?.split(" ")[0] || "Unknown";
|
||||||
typeCounts[type] = (typeCounts[type] || 0) + 1;
|
typeCounts[type] = (typeCounts[type] || 0) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
112
src/server.ts
112
src/server.ts
@@ -54,18 +54,8 @@ function findPythonExecutable(scriptPath: string): string {
|
|||||||
|
|
||||||
// Check for virtual environment
|
// Check for virtual environment
|
||||||
const venvPaths = [
|
const venvPaths = [
|
||||||
join(
|
join(projectRoot, "venv", isWindows ? "Scripts" : "bin", isWindows ? "python.exe" : "python"),
|
||||||
projectRoot,
|
join(projectRoot, ".venv", isWindows ? "Scripts" : "bin", isWindows ? "python.exe" : "python"),
|
||||||
"venv",
|
|
||||||
isWindows ? "Scripts" : "bin",
|
|
||||||
isWindows ? "python.exe" : "python",
|
|
||||||
),
|
|
||||||
join(
|
|
||||||
projectRoot,
|
|
||||||
".venv",
|
|
||||||
isWindows ? "Scripts" : "bin",
|
|
||||||
isWindows ? "python.exe" : "python",
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const venvPath of venvPaths) {
|
for (const venvPath of venvPaths) {
|
||||||
@@ -77,9 +67,7 @@ function findPythonExecutable(scriptPath: string): string {
|
|||||||
|
|
||||||
// Allow override via KICAD_PYTHON environment variable (any platform)
|
// Allow override via KICAD_PYTHON environment variable (any platform)
|
||||||
if (process.env.KICAD_PYTHON) {
|
if (process.env.KICAD_PYTHON) {
|
||||||
logger.info(
|
logger.info(`Using KICAD_PYTHON environment variable: ${process.env.KICAD_PYTHON}`);
|
||||||
`Using KICAD_PYTHON environment variable: ${process.env.KICAD_PYTHON}`,
|
|
||||||
);
|
|
||||||
return process.env.KICAD_PYTHON;
|
return process.env.KICAD_PYTHON;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,9 +111,7 @@ function findPythonExecutable(scriptPath: string): string {
|
|||||||
|
|
||||||
for (const path of homebrewPaths) {
|
for (const path of homebrewPaths) {
|
||||||
if (existsSync(path)) {
|
if (existsSync(path)) {
|
||||||
logger.info(
|
logger.info(`Found Homebrew Python at: ${path} (ensure pcbnew is importable)`);
|
||||||
`Found Homebrew Python at: ${path} (ensure pcbnew is importable)`,
|
|
||||||
);
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,19 +182,14 @@ export class KiCADMcpServer {
|
|||||||
* @param kicadScriptPath Path to the Python KiCAD interface script
|
* @param kicadScriptPath Path to the Python KiCAD interface script
|
||||||
* @param logLevel Log level for the server
|
* @param logLevel Log level for the server
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(kicadScriptPath: string, logLevel: "error" | "warn" | "info" | "debug" = "info") {
|
||||||
kicadScriptPath: string,
|
|
||||||
logLevel: "error" | "warn" | "info" | "debug" = "info",
|
|
||||||
) {
|
|
||||||
// Set up the logger
|
// Set up the logger
|
||||||
logger.setLogLevel(logLevel);
|
logger.setLogLevel(logLevel);
|
||||||
|
|
||||||
// Check if KiCAD script exists
|
// Check if KiCAD script exists
|
||||||
this.kicadScriptPath = kicadScriptPath;
|
this.kicadScriptPath = kicadScriptPath;
|
||||||
if (!existsSync(this.kicadScriptPath)) {
|
if (!existsSync(this.kicadScriptPath)) {
|
||||||
throw new Error(
|
throw new Error(`KiCAD interface script not found: ${this.kicadScriptPath}`);
|
||||||
`KiCAD interface script not found: ${this.kicadScriptPath}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the MCP server
|
// Initialize the MCP server
|
||||||
@@ -267,9 +248,7 @@ export class KiCADMcpServer {
|
|||||||
registerFootprintPrompts(this.server);
|
registerFootprintPrompts(this.server);
|
||||||
|
|
||||||
logger.info("All KiCAD tools, resources, and prompts registered");
|
logger.info("All KiCAD tools, resources, and prompts registered");
|
||||||
logger.info(
|
logger.info("Router pattern enabled: 4 router tools + direct tools for discovery");
|
||||||
"Router pattern enabled: 4 router tools + direct tools for discovery",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -277,15 +256,12 @@ export class KiCADMcpServer {
|
|||||||
*/
|
*/
|
||||||
private async validatePrerequisites(pythonExe: string): Promise<boolean> {
|
private async validatePrerequisites(pythonExe: string): Promise<boolean> {
|
||||||
const isWindows = process.platform === "win32";
|
const isWindows = process.platform === "win32";
|
||||||
const isLinux =
|
const isLinux = process.platform !== "win32" && process.platform !== "darwin";
|
||||||
process.platform !== "win32" && process.platform !== "darwin";
|
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
|
|
||||||
// Check if Python executable exists (for absolute paths) or is executable (for commands)
|
// Check if Python executable exists (for absolute paths) or is executable (for commands)
|
||||||
const isAbsolutePath =
|
const isAbsolutePath =
|
||||||
pythonExe.startsWith("/") ||
|
pythonExe.startsWith("/") || pythonExe.startsWith("C:") || pythonExe.startsWith("\\");
|
||||||
pythonExe.startsWith("C:") ||
|
|
||||||
pythonExe.startsWith("\\");
|
|
||||||
|
|
||||||
if (isAbsolutePath) {
|
if (isAbsolutePath) {
|
||||||
// Absolute path: use existsSync
|
// Absolute path: use existsSync
|
||||||
@@ -293,16 +269,10 @@ export class KiCADMcpServer {
|
|||||||
errors.push(`Python executable not found: ${pythonExe}`);
|
errors.push(`Python executable not found: ${pythonExe}`);
|
||||||
|
|
||||||
if (isWindows) {
|
if (isWindows) {
|
||||||
errors.push(
|
errors.push("Windows: Install KiCAD 9.0+ from https://www.kicad.org/download/windows/");
|
||||||
"Windows: Install KiCAD 9.0+ from https://www.kicad.org/download/windows/",
|
errors.push("Or run: .\\setup-windows.ps1 for automatic configuration");
|
||||||
);
|
|
||||||
errors.push(
|
|
||||||
"Or run: .\\setup-windows.ps1 for automatic configuration",
|
|
||||||
);
|
|
||||||
} else if (isLinux) {
|
} else if (isLinux) {
|
||||||
errors.push(
|
errors.push("Linux: Install KiCAD 9.0+ or set KICAD_PYTHON environment variable");
|
||||||
"Linux: Install KiCAD 9.0+ or set KICAD_PYTHON environment variable",
|
|
||||||
);
|
|
||||||
errors.push("Set KICAD_PYTHON to specify a custom Python path");
|
errors.push("Set KICAD_PYTHON to specify a custom Python path");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,20 +304,14 @@ export class KiCADMcpServer {
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
errors.push(`Python executable not found in PATH: ${pythonExe}`);
|
errors.push(`Python executable not found in PATH: ${pythonExe}`);
|
||||||
errors.push(`Error: ${error.message}`);
|
errors.push(`Error: ${error.message}`);
|
||||||
errors.push(
|
errors.push("Set KICAD_PYTHON environment variable to specify full path");
|
||||||
"Set KICAD_PYTHON environment variable to specify full path",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isLinux) {
|
if (isLinux) {
|
||||||
errors.push("");
|
errors.push("");
|
||||||
errors.push("Linux troubleshooting:");
|
errors.push("Linux troubleshooting:");
|
||||||
errors.push("1. Check if python3 is installed: which python3");
|
errors.push("1. Check if python3 is installed: which python3");
|
||||||
errors.push(
|
errors.push("2. Install KiCAD: sudo apt install kicad (Ubuntu/Debian)");
|
||||||
"2. Install KiCAD: sudo apt install kicad (Ubuntu/Debian)",
|
errors.push("3. Set KICAD_PYTHON=/usr/bin/python3 in your MCP config");
|
||||||
);
|
|
||||||
errors.push(
|
|
||||||
"3. Set KICAD_PYTHON=/usr/bin/python3 in your MCP config",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -358,11 +322,7 @@ export class KiCADMcpServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if dist/index.js exists (if running from compiled code)
|
// Check if dist/index.js exists (if running from compiled code)
|
||||||
const distPath = join(
|
const distPath = join(dirname(dirname(this.kicadScriptPath)), "dist", "index.js");
|
||||||
dirname(dirname(this.kicadScriptPath)),
|
|
||||||
"dist",
|
|
||||||
"index.js",
|
|
||||||
);
|
|
||||||
if (!existsSync(distPath)) {
|
if (!existsSync(distPath)) {
|
||||||
errors.push("Project not built. Run: npm run build");
|
errors.push("Project not built. Run: npm run build");
|
||||||
}
|
}
|
||||||
@@ -458,9 +418,7 @@ export class KiCADMcpServer {
|
|||||||
logger.info("Starting KiCAD MCP server...");
|
logger.info("Starting KiCAD MCP server...");
|
||||||
|
|
||||||
// Start the Python process for KiCAD scripting
|
// Start the Python process for KiCAD scripting
|
||||||
logger.info(
|
logger.info(`Starting Python process with script: ${this.kicadScriptPath}`);
|
||||||
`Starting Python process with script: ${this.kicadScriptPath}`,
|
|
||||||
);
|
|
||||||
const pythonExe = findPythonExecutable(this.kicadScriptPath);
|
const pythonExe = findPythonExecutable(this.kicadScriptPath);
|
||||||
|
|
||||||
logger.info(`Using Python executable: ${pythonExe}`);
|
logger.info(`Using Python executable: ${pythonExe}`);
|
||||||
@@ -468,25 +426,20 @@ export class KiCADMcpServer {
|
|||||||
// Validate prerequisites
|
// Validate prerequisites
|
||||||
const isValid = await this.validatePrerequisites(pythonExe);
|
const isValid = await this.validatePrerequisites(pythonExe);
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
throw new Error(
|
throw new Error("Prerequisites validation failed. See logs above for details.");
|
||||||
"Prerequisites validation failed. See logs above for details.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], {
|
this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], {
|
||||||
stdio: ["pipe", "pipe", "pipe"],
|
stdio: ["pipe", "pipe", "pipe"],
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
PYTHONPATH:
|
PYTHONPATH:
|
||||||
process.env.PYTHONPATH ||
|
process.env.PYTHONPATH || "C:/Program Files/KiCad/9.0/lib/python3/dist-packages",
|
||||||
"C:/Program Files/KiCad/9.0/lib/python3/dist-packages",
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for process exit
|
// Listen for process exit
|
||||||
this.pythonProcess.on("exit", (code, signal) => {
|
this.pythonProcess.on("exit", (code, signal) => {
|
||||||
logger.warn(
|
logger.warn(`Python process exited with code ${code} and signal ${signal}`);
|
||||||
`Python process exited with code ${code} and signal ${signal}`,
|
|
||||||
);
|
|
||||||
this.pythonProcess = null;
|
this.pythonProcess = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -563,17 +516,10 @@ export class KiCADMcpServer {
|
|||||||
// Determine timeout based on command type
|
// Determine timeout based on command type
|
||||||
// DRC and export operations need longer timeouts for large boards
|
// DRC and export operations need longer timeouts for large boards
|
||||||
let commandTimeout = 30000; // Default 30 seconds
|
let commandTimeout = 30000; // Default 30 seconds
|
||||||
const longRunningCommands = [
|
const longRunningCommands = ["run_drc", "export_gerber", "export_pdf", "export_3d"];
|
||||||
"run_drc",
|
|
||||||
"export_gerber",
|
|
||||||
"export_pdf",
|
|
||||||
"export_3d",
|
|
||||||
];
|
|
||||||
if (longRunningCommands.includes(command)) {
|
if (longRunningCommands.includes(command)) {
|
||||||
commandTimeout = 600000; // 10 minutes for long operations
|
commandTimeout = 600000; // 10 minutes for long operations
|
||||||
logger.info(
|
logger.info(`Using extended timeout (${commandTimeout / 1000}s) for command: ${command}`);
|
||||||
`Using extended timeout (${commandTimeout / 1000}s) for command: ${command}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add request to queue with timeout info
|
// Add request to queue with timeout info
|
||||||
@@ -678,12 +624,8 @@ export class KiCADMcpServer {
|
|||||||
// Set a timeout (use command-specific timeout or default)
|
// Set a timeout (use command-specific timeout or default)
|
||||||
const timeoutDuration = request.timeout || 30000;
|
const timeoutDuration = request.timeout || 30000;
|
||||||
const timeoutHandle = setTimeout(() => {
|
const timeoutHandle = setTimeout(() => {
|
||||||
logger.error(
|
logger.error(`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`);
|
||||||
`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`,
|
logger.error(`Buffer contents: ${this.responseBuffer.substring(0, 200)}...`);
|
||||||
);
|
|
||||||
logger.error(
|
|
||||||
`Buffer contents: ${this.responseBuffer.substring(0, 200)}...`,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Clear state
|
// Clear state
|
||||||
this.responseBuffer = "";
|
this.responseBuffer = "";
|
||||||
@@ -691,11 +633,7 @@ export class KiCADMcpServer {
|
|||||||
this.processingRequest = false;
|
this.processingRequest = false;
|
||||||
|
|
||||||
// Reject the promise
|
// Reject the promise
|
||||||
reject(
|
reject(new Error(`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`));
|
||||||
new Error(
|
|
||||||
`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Process next request
|
// Process next request
|
||||||
setTimeout(() => this.processNextRequest(), 0);
|
setTimeout(() => this.processNextRequest(), 0);
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* These tools handle board setup, layer management, and board properties
|
* These tools handle board setup, layer management, and board properties
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
@@ -18,7 +18,7 @@ type CommandFunction = (command: string, params: Record<string, unknown>) => Pro
|
|||||||
* @param callKicadScript Function to call KiCAD script commands
|
* @param callKicadScript Function to call KiCAD script commands
|
||||||
*/
|
*/
|
||||||
export function registerBoardTools(server: McpServer, callKicadScript: CommandFunction): void {
|
export function registerBoardTools(server: McpServer, callKicadScript: CommandFunction): void {
|
||||||
logger.info('Registering board management tools');
|
logger.info("Registering board management tools");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Set Board Size Tool
|
// Set Board Size Tool
|
||||||
@@ -28,23 +28,25 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
{
|
{
|
||||||
width: z.number().describe("Board width"),
|
width: z.number().describe("Board width"),
|
||||||
height: z.number().describe("Board height"),
|
height: z.number().describe("Board height"),
|
||||||
unit: z.enum(["mm", "inch"]).describe("Unit of measurement")
|
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
||||||
},
|
},
|
||||||
async ({ width, height, unit }) => {
|
async ({ width, height, unit }) => {
|
||||||
logger.debug(`Setting board size to ${width}x${height} ${unit}`);
|
logger.debug(`Setting board size to ${width}x${height} ${unit}`);
|
||||||
const result = await callKicadScript("set_board_size", {
|
const result = await callKicadScript("set_board_size", {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
unit
|
unit,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -54,13 +56,9 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
"add_layer",
|
"add_layer",
|
||||||
{
|
{
|
||||||
name: z.string().describe("Layer name"),
|
name: z.string().describe("Layer name"),
|
||||||
type: z.enum([
|
type: z.enum(["copper", "technical", "user", "signal"]).describe("Layer type"),
|
||||||
"copper", "technical", "user", "signal"
|
position: z.enum(["top", "bottom", "inner"]).describe("Layer position"),
|
||||||
]).describe("Layer type"),
|
number: z.number().optional().describe("Layer number (for inner layers)"),
|
||||||
position: z.enum([
|
|
||||||
"top", "bottom", "inner"
|
|
||||||
]).describe("Layer position"),
|
|
||||||
number: z.number().optional().describe("Layer number (for inner layers)")
|
|
||||||
},
|
},
|
||||||
async ({ name, type, position, number }) => {
|
async ({ name, type, position, number }) => {
|
||||||
logger.debug(`Adding ${type} layer: ${name}`);
|
logger.debug(`Adding ${type} layer: ${name}`);
|
||||||
@@ -68,16 +66,18 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
position,
|
position,
|
||||||
number
|
number,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -86,58 +86,56 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
server.tool(
|
server.tool(
|
||||||
"set_active_layer",
|
"set_active_layer",
|
||||||
{
|
{
|
||||||
layer: z.string().describe("Layer name to set as active")
|
layer: z.string().describe("Layer name to set as active"),
|
||||||
},
|
},
|
||||||
async ({ layer }) => {
|
async ({ layer }) => {
|
||||||
logger.debug(`Setting active layer to: ${layer}`);
|
logger.debug(`Setting active layer to: ${layer}`);
|
||||||
const result = await callKicadScript("set_active_layer", { layer });
|
const result = await callKicadScript("set_active_layer", { layer });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Get Board Info Tool
|
// Get Board Info Tool
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.tool(
|
server.tool("get_board_info", {}, async () => {
|
||||||
"get_board_info",
|
logger.debug("Getting board information");
|
||||||
{},
|
|
||||||
async () => {
|
|
||||||
logger.debug('Getting board information');
|
|
||||||
const result = await callKicadScript("get_board_info", {});
|
const result = await callKicadScript("get_board_info", {});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Get Layer List Tool
|
// Get Layer List Tool
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.tool(
|
server.tool("get_layer_list", {}, async () => {
|
||||||
"get_layer_list",
|
logger.debug("Getting layer list");
|
||||||
{},
|
|
||||||
async () => {
|
|
||||||
logger.debug('Getting layer list');
|
|
||||||
const result = await callKicadScript("get_layer_list", {});
|
const result = await callKicadScript("get_layer_list", {});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Add Board Outline Tool
|
// Add Board Outline Tool
|
||||||
@@ -145,8 +143,11 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
server.tool(
|
server.tool(
|
||||||
"add_board_outline",
|
"add_board_outline",
|
||||||
{
|
{
|
||||||
shape: z.enum(["rectangle", "circle", "polygon", "rounded_rectangle"]).describe("Shape of the outline"),
|
shape: z
|
||||||
params: z.object({
|
.enum(["rectangle", "circle", "polygon", "rounded_rectangle"])
|
||||||
|
.describe("Shape of the outline"),
|
||||||
|
params: z
|
||||||
|
.object({
|
||||||
// For rectangle / rounded_rectangle
|
// For rectangle / rounded_rectangle
|
||||||
width: z.number().optional().describe("Width of rectangle"),
|
width: z.number().optional().describe("Width of rectangle"),
|
||||||
height: z.number().optional().describe("Height of rectangle"),
|
height: z.number().optional().describe("Height of rectangle"),
|
||||||
@@ -154,17 +155,21 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
// For circle
|
// For circle
|
||||||
radius: z.number().optional().describe("Radius of circle"),
|
radius: z.number().optional().describe("Radius of circle"),
|
||||||
// For polygon
|
// For polygon
|
||||||
points: z.array(
|
points: z
|
||||||
|
.array(
|
||||||
z.object({
|
z.object({
|
||||||
x: z.number().describe("X coordinate"),
|
x: z.number().describe("X coordinate"),
|
||||||
y: z.number().describe("Y coordinate")
|
y: z.number().describe("Y coordinate"),
|
||||||
})
|
}),
|
||||||
).optional().describe("Points of polygon"),
|
)
|
||||||
|
.optional()
|
||||||
|
.describe("Points of polygon"),
|
||||||
// Position: top-left corner for rectangles/rounded_rectangle, center for circle
|
// Position: top-left corner for rectangles/rounded_rectangle, center for circle
|
||||||
x: z.number().describe("X coordinate of top-left corner for rectangles (default: 0)"),
|
x: z.number().describe("X coordinate of top-left corner for rectangles (default: 0)"),
|
||||||
y: z.number().describe("Y coordinate of top-left corner for rectangles (default: 0)"),
|
y: z.number().describe("Y coordinate of top-left corner for rectangles (default: 0)"),
|
||||||
unit: z.enum(["mm", "inch"]).describe("Unit of measurement")
|
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
||||||
}).describe("Parameters for the outline shape")
|
})
|
||||||
|
.describe("Parameters for the outline shape"),
|
||||||
},
|
},
|
||||||
async ({ shape, params }) => {
|
async ({ shape, params }) => {
|
||||||
logger.debug(`Adding ${shape} board outline`);
|
logger.debug(`Adding ${shape} board outline`);
|
||||||
@@ -172,16 +177,18 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
// and computes the center internally (center = x + width/2, y + height/2).
|
// and computes the center internally (center = x + width/2, y + height/2).
|
||||||
const result = await callKicadScript("add_board_outline", {
|
const result = await callKicadScript("add_board_outline", {
|
||||||
shape,
|
shape,
|
||||||
...params
|
...params,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -190,29 +197,33 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
server.tool(
|
server.tool(
|
||||||
"add_mounting_hole",
|
"add_mounting_hole",
|
||||||
{
|
{
|
||||||
position: z.object({
|
position: z
|
||||||
|
.object({
|
||||||
x: z.number().describe("X coordinate"),
|
x: z.number().describe("X coordinate"),
|
||||||
y: z.number().describe("Y coordinate"),
|
y: z.number().describe("Y coordinate"),
|
||||||
unit: z.enum(["mm", "inch"]).describe("Unit of measurement")
|
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
||||||
}).describe("Position of the mounting hole"),
|
})
|
||||||
|
.describe("Position of the mounting hole"),
|
||||||
diameter: z.number().describe("Diameter of the hole"),
|
diameter: z.number().describe("Diameter of the hole"),
|
||||||
padDiameter: z.number().optional().describe("Optional diameter of the pad around the hole")
|
padDiameter: z.number().optional().describe("Optional diameter of the pad around the hole"),
|
||||||
},
|
},
|
||||||
async ({ position, diameter, padDiameter }) => {
|
async ({ position, diameter, padDiameter }) => {
|
||||||
logger.debug(`Adding mounting hole at (${position.x},${position.y}) ${position.unit}`);
|
logger.debug(`Adding mounting hole at (${position.x},${position.y}) ${position.unit}`);
|
||||||
const result = await callKicadScript("add_mounting_hole", {
|
const result = await callKicadScript("add_mounting_hole", {
|
||||||
position,
|
position,
|
||||||
diameter,
|
diameter,
|
||||||
padDiameter
|
padDiameter,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -222,16 +233,18 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
"add_board_text",
|
"add_board_text",
|
||||||
{
|
{
|
||||||
text: z.string().describe("Text content"),
|
text: z.string().describe("Text content"),
|
||||||
position: z.object({
|
position: z
|
||||||
|
.object({
|
||||||
x: z.number().describe("X coordinate"),
|
x: z.number().describe("X coordinate"),
|
||||||
y: z.number().describe("Y coordinate"),
|
y: z.number().describe("Y coordinate"),
|
||||||
unit: z.enum(["mm", "inch"]).describe("Unit of measurement")
|
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
||||||
}).describe("Position of the text"),
|
})
|
||||||
|
.describe("Position of the text"),
|
||||||
layer: z.string().describe("Layer to place the text on"),
|
layer: z.string().describe("Layer to place the text on"),
|
||||||
size: z.number().describe("Text size"),
|
size: z.number().describe("Text size"),
|
||||||
thickness: z.number().optional().describe("Line thickness"),
|
thickness: z.number().optional().describe("Line thickness"),
|
||||||
rotation: z.number().optional().describe("Rotation angle in degrees"),
|
rotation: z.number().optional().describe("Rotation angle in degrees"),
|
||||||
style: z.enum(["normal", "italic", "bold"]).optional().describe("Text style")
|
style: z.enum(["normal", "italic", "bold"]).optional().describe("Text style"),
|
||||||
},
|
},
|
||||||
async ({ text, position, layer, size, thickness, rotation, style }) => {
|
async ({ text, position, layer, size, thickness, rotation, style }) => {
|
||||||
logger.debug(`Adding text "${text}" at (${position.x},${position.y}) ${position.unit}`);
|
logger.debug(`Adding text "${text}" at (${position.x},${position.y}) ${position.unit}`);
|
||||||
@@ -242,16 +255,18 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
size,
|
size,
|
||||||
thickness,
|
thickness,
|
||||||
rotation,
|
rotation,
|
||||||
style
|
style,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -262,16 +277,21 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
{
|
{
|
||||||
layer: z.string().describe("Layer for the zone"),
|
layer: z.string().describe("Layer for the zone"),
|
||||||
net: z.string().describe("Net name for the zone"),
|
net: z.string().describe("Net name for the zone"),
|
||||||
points: z.array(
|
points: z
|
||||||
|
.array(
|
||||||
z.object({
|
z.object({
|
||||||
x: z.number().describe("X coordinate"),
|
x: z.number().describe("X coordinate"),
|
||||||
y: z.number().describe("Y coordinate")
|
y: z.number().describe("Y coordinate"),
|
||||||
})
|
}),
|
||||||
).describe("Points defining the zone outline"),
|
)
|
||||||
|
.describe("Points defining the zone outline"),
|
||||||
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
||||||
clearance: z.number().optional().describe("Clearance value"),
|
clearance: z.number().optional().describe("Clearance value"),
|
||||||
minWidth: z.number().optional().describe("Minimum width"),
|
minWidth: z.number().optional().describe("Minimum width"),
|
||||||
padConnection: z.enum(["thermal", "solid", "none"]).optional().describe("Pad connection type")
|
padConnection: z
|
||||||
|
.enum(["thermal", "solid", "none"])
|
||||||
|
.optional()
|
||||||
|
.describe("Pad connection type"),
|
||||||
},
|
},
|
||||||
async ({ layer, net, points, unit, clearance, minWidth, padConnection }) => {
|
async ({ layer, net, points, unit, clearance, minWidth, padConnection }) => {
|
||||||
logger.debug(`Adding zone on layer ${layer} for net ${net}`);
|
logger.debug(`Adding zone on layer ${layer} for net ${net}`);
|
||||||
@@ -282,16 +302,18 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
unit,
|
unit,
|
||||||
clearance,
|
clearance,
|
||||||
minWidth,
|
minWidth,
|
||||||
padConnection
|
padConnection,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -300,19 +322,21 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
server.tool(
|
server.tool(
|
||||||
"get_board_extents",
|
"get_board_extents",
|
||||||
{
|
{
|
||||||
unit: z.enum(["mm", "inch"]).optional().describe("Unit of measurement for the result")
|
unit: z.enum(["mm", "inch"]).optional().describe("Unit of measurement for the result"),
|
||||||
},
|
},
|
||||||
async ({ unit }) => {
|
async ({ unit }) => {
|
||||||
logger.debug('Getting board extents');
|
logger.debug("Getting board extents");
|
||||||
const result = await callKicadScript("get_board_extents", { unit });
|
const result = await callKicadScript("get_board_extents", { unit });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -324,27 +348,29 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
layers: z.array(z.string()).optional().describe("Optional array of layer names to include"),
|
layers: z.array(z.string()).optional().describe("Optional array of layer names to include"),
|
||||||
width: z.number().optional().describe("Optional width of the image in pixels"),
|
width: z.number().optional().describe("Optional width of the image in pixels"),
|
||||||
height: z.number().optional().describe("Optional height of the image in pixels"),
|
height: z.number().optional().describe("Optional height of the image in pixels"),
|
||||||
format: z.enum(["png", "jpg", "svg"]).optional().describe("Image format")
|
format: z.enum(["png", "jpg", "svg"]).optional().describe("Image format"),
|
||||||
},
|
},
|
||||||
async ({ layers, width, height, format }) => {
|
async ({ layers, width, height, format }) => {
|
||||||
logger.debug('Getting 2D board view');
|
logger.debug("Getting 2D board view");
|
||||||
const result = await callKicadScript("get_board_2d_view", {
|
const result = await callKicadScript("get_board_2d_view", {
|
||||||
layers,
|
layers,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
format
|
format,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Board management tools registered');
|
logger.info("Board management tools registered");
|
||||||
|
|
||||||
// Import SVG logo onto PCB layer (silkscreen)
|
// Import SVG logo onto PCB layer (silkscreen)
|
||||||
server.tool(
|
server.tool(
|
||||||
@@ -355,16 +381,34 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
svgPath: z.string().describe("Path to the SVG logo file"),
|
svgPath: z.string().describe("Path to the SVG logo file"),
|
||||||
x: z.number().describe("X position of the logo top-left corner in mm"),
|
x: z.number().describe("X position of the logo top-left corner in mm"),
|
||||||
y: z.number().describe("Y position of the logo top-left corner in mm"),
|
y: z.number().describe("Y position of the logo top-left corner in mm"),
|
||||||
width: z.number().describe("Target width of the logo in mm (height is scaled to preserve aspect ratio)"),
|
width: z
|
||||||
layer: z.string().optional().describe("PCB layer name, e.g. F.SilkS or B.SilkS (default: F.SilkS)"),
|
.number()
|
||||||
strokeWidth: z.number().optional().describe("Outline stroke width in mm (0 = no outline, default 0)"),
|
.describe("Target width of the logo in mm (height is scaled to preserve aspect ratio)"),
|
||||||
|
layer: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("PCB layer name, e.g. F.SilkS or B.SilkS (default: F.SilkS)"),
|
||||||
|
strokeWidth: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Outline stroke width in mm (0 = no outline, default 0)"),
|
||||||
filled: z.boolean().optional().describe("Fill polygons with solid colour (default true)"),
|
filled: z.boolean().optional().describe("Fill polygons with solid colour (default true)"),
|
||||||
},
|
},
|
||||||
async (args: { pcbPath: string; svgPath: string; x: number; y: number; width: number; layer?: string; strokeWidth?: number; filled?: boolean }) => {
|
async (args: {
|
||||||
|
pcbPath: string;
|
||||||
|
svgPath: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
layer?: string;
|
||||||
|
strokeWidth?: number;
|
||||||
|
filled?: boolean;
|
||||||
|
}) => {
|
||||||
const result = await callKicadScript("import_svg_logo", args);
|
const result = await callKicadScript("import_svg_logo", args);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: [
|
text: [
|
||||||
result.message,
|
result.message,
|
||||||
@@ -372,11 +416,14 @@ export function registerBoardTools(server: McpServer, callKicadScript: CommandFu
|
|||||||
`Size: ${result.logo_width_mm?.toFixed(2)} × ${result.logo_height_mm?.toFixed(2)} mm`,
|
`Size: ${result.logo_width_mm?.toFixed(2)} × ${result.logo_height_mm?.toFixed(2)} mm`,
|
||||||
`Layer: ${result.layer}`,
|
`Layer: ${result.layer}`,
|
||||||
].join("\n"),
|
].join("\n"),
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `SVG import failed: ${result.message || "Unknown error"}` }],
|
content: [
|
||||||
|
{ type: "text", text: `SVG import failed: ${result.message || "Unknown error"}` },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ import { z } from "zod";
|
|||||||
import { logger } from "../logger.js";
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
command: string,
|
|
||||||
params: Record<string, unknown>,
|
|
||||||
) => Promise<any>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register component management tools with the MCP server
|
* Register component management tools with the MCP server
|
||||||
@@ -18,10 +15,7 @@ type CommandFunction = (
|
|||||||
* @param server MCP server instance
|
* @param server MCP server instance
|
||||||
* @param callKicadScript Function to call KiCAD script commands
|
* @param callKicadScript Function to call KiCAD script commands
|
||||||
*/
|
*/
|
||||||
export function registerComponentTools(
|
export function registerComponentTools(server: McpServer, callKicadScript: CommandFunction): void {
|
||||||
server: McpServer,
|
|
||||||
callKicadScript: CommandFunction,
|
|
||||||
): void {
|
|
||||||
logger.info("Registering component management tools");
|
logger.info("Registering component management tools");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -40,38 +34,19 @@ export function registerComponentTools(
|
|||||||
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
||||||
})
|
})
|
||||||
.describe("Position coordinates and unit"),
|
.describe("Position coordinates and unit"),
|
||||||
reference: z
|
reference: z.string().optional().describe("Optional desired reference (e.g., 'R5')"),
|
||||||
.string()
|
value: z.string().optional().describe("Optional component value (e.g., '10k')"),
|
||||||
.optional()
|
footprint: z.string().optional().describe("Optional specific footprint name"),
|
||||||
.describe("Optional desired reference (e.g., 'R5')"),
|
|
||||||
value: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Optional component value (e.g., '10k')"),
|
|
||||||
footprint: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Optional specific footprint name"),
|
|
||||||
rotation: z.number().optional().describe("Optional rotation in degrees"),
|
rotation: z.number().optional().describe("Optional rotation in degrees"),
|
||||||
layer: z
|
layer: z.string().optional().describe("Optional layer (e.g., 'F.Cu', 'B.SilkS')"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Optional layer (e.g., 'F.Cu', 'B.SilkS')"),
|
|
||||||
boardPath: z
|
boardPath: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Path to the .kicad_pcb file – required when using project-local footprint libraries"),
|
.describe(
|
||||||
|
"Path to the .kicad_pcb file – required when using project-local footprint libraries",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
async ({
|
async ({ componentId, position, reference, value, footprint, rotation, layer, boardPath }) => {
|
||||||
componentId,
|
|
||||||
position,
|
|
||||||
reference,
|
|
||||||
value,
|
|
||||||
footprint,
|
|
||||||
rotation,
|
|
||||||
layer,
|
|
||||||
boardPath,
|
|
||||||
}) => {
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Placing component: ${componentId} at ${position.x},${position.y} ${position.unit}`,
|
`Placing component: ${componentId} at ${position.x},${position.y} ${position.unit}`,
|
||||||
);
|
);
|
||||||
@@ -103,9 +78,7 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"move_component",
|
"move_component",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
|
||||||
.string()
|
|
||||||
.describe("Reference designator of the component (e.g., 'R5')"),
|
|
||||||
position: z
|
position: z
|
||||||
.object({
|
.object({
|
||||||
x: z.number().describe("X coordinate"),
|
x: z.number().describe("X coordinate"),
|
||||||
@@ -113,10 +86,7 @@ export function registerComponentTools(
|
|||||||
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
unit: z.enum(["mm", "inch"]).describe("Unit of measurement"),
|
||||||
})
|
})
|
||||||
.describe("New position coordinates and unit"),
|
.describe("New position coordinates and unit"),
|
||||||
rotation: z
|
rotation: z.number().optional().describe("Optional new rotation in degrees"),
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Optional new rotation in degrees"),
|
|
||||||
layer: z
|
layer: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -150,12 +120,8 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"rotate_component",
|
"rotate_component",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
|
||||||
.string()
|
angle: z.number().describe("Rotation angle in degrees (absolute, not relative)"),
|
||||||
.describe("Reference designator of the component (e.g., 'R5')"),
|
|
||||||
angle: z
|
|
||||||
.number()
|
|
||||||
.describe("Rotation angle in degrees (absolute, not relative)"),
|
|
||||||
},
|
},
|
||||||
async ({ reference, angle }) => {
|
async ({ reference, angle }) => {
|
||||||
logger.debug(`Rotating component: ${reference} to ${angle} degrees`);
|
logger.debug(`Rotating component: ${reference} to ${angle} degrees`);
|
||||||
@@ -183,9 +149,7 @@ export function registerComponentTools(
|
|||||||
{
|
{
|
||||||
reference: z
|
reference: z
|
||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe("Reference designator of the component to delete (e.g., 'R5')"),
|
||||||
"Reference designator of the component to delete (e.g., 'R5')",
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
async ({ reference }) => {
|
async ({ reference }) => {
|
||||||
logger.debug(`Deleting component: ${reference}`);
|
logger.debug(`Deleting component: ${reference}`);
|
||||||
@@ -208,13 +172,8 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"edit_component",
|
"edit_component",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
|
||||||
.string()
|
newReference: z.string().optional().describe("Optional new reference designator"),
|
||||||
.describe("Reference designator of the component (e.g., 'R5')"),
|
|
||||||
newReference: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Optional new reference designator"),
|
|
||||||
value: z.string().optional().describe("Optional new component value"),
|
value: z.string().optional().describe("Optional new component value"),
|
||||||
footprint: z.string().optional().describe("Optional new footprint"),
|
footprint: z.string().optional().describe("Optional new footprint"),
|
||||||
},
|
},
|
||||||
@@ -244,10 +203,7 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"find_component",
|
"find_component",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().optional().describe("Reference designator to search for"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Reference designator to search for"),
|
|
||||||
value: z.string().optional().describe("Component value to search for"),
|
value: z.string().optional().describe("Component value to search for"),
|
||||||
},
|
},
|
||||||
async ({ reference, value }) => {
|
async ({ reference, value }) => {
|
||||||
@@ -276,9 +232,7 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"get_component_properties",
|
"get_component_properties",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
|
||||||
.string()
|
|
||||||
.describe("Reference designator of the component (e.g., 'R5')"),
|
|
||||||
},
|
},
|
||||||
async ({ reference }) => {
|
async ({ reference }) => {
|
||||||
logger.debug(`Getting properties for component: ${reference}`);
|
logger.debug(`Getting properties for component: ${reference}`);
|
||||||
@@ -303,9 +257,7 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"add_component_annotation",
|
"add_component_annotation",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
|
||||||
.string()
|
|
||||||
.describe("Reference designator of the component (e.g., 'R5')"),
|
|
||||||
annotation: z.string().describe("Annotation or comment text to add"),
|
annotation: z.string().describe("Annotation or comment text to add"),
|
||||||
visible: z
|
visible: z
|
||||||
.boolean()
|
.boolean()
|
||||||
@@ -337,15 +289,11 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"group_components",
|
"group_components",
|
||||||
{
|
{
|
||||||
references: z
|
references: z.array(z.string()).describe("Reference designators of components to group"),
|
||||||
.array(z.string())
|
|
||||||
.describe("Reference designators of components to group"),
|
|
||||||
groupName: z.string().describe("Name for the component group"),
|
groupName: z.string().describe("Name for the component group"),
|
||||||
},
|
},
|
||||||
async ({ references, groupName }) => {
|
async ({ references, groupName }) => {
|
||||||
logger.debug(
|
logger.debug(`Grouping components: ${references.join(", ")} as ${groupName}`);
|
||||||
`Grouping components: ${references.join(", ")} as ${groupName}`,
|
|
||||||
);
|
|
||||||
const result = await callKicadScript("group_components", {
|
const result = await callKicadScript("group_components", {
|
||||||
references,
|
references,
|
||||||
groupName,
|
groupName,
|
||||||
@@ -368,9 +316,7 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"replace_component",
|
"replace_component",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().describe("Reference designator of the component to replace"),
|
||||||
.string()
|
|
||||||
.describe("Reference designator of the component to replace"),
|
|
||||||
newComponentId: z.string().describe("ID of the new component to use"),
|
newComponentId: z.string().describe("ID of the new component to use"),
|
||||||
newFootprint: z.string().optional().describe("Optional new footprint"),
|
newFootprint: z.string().optional().describe("Optional new footprint"),
|
||||||
newValue: z.string().optional().describe("Optional new component value"),
|
newValue: z.string().optional().describe("Optional new component value"),
|
||||||
@@ -401,13 +347,8 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"get_component_pads",
|
"get_component_pads",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().describe("Reference designator of the component (e.g., 'U1')"),
|
||||||
.string()
|
unit: z.enum(["mm", "inch"]).optional().describe("Unit for coordinates (default: mm)"),
|
||||||
.describe("Reference designator of the component (e.g., 'U1')"),
|
|
||||||
unit: z
|
|
||||||
.enum(["mm", "inch"])
|
|
||||||
.optional()
|
|
||||||
.describe("Unit for coordinates (default: mm)"),
|
|
||||||
},
|
},
|
||||||
async ({ reference, unit }) => {
|
async ({ reference, unit }) => {
|
||||||
logger.debug(`Getting pads for component: ${reference}`);
|
logger.debug(`Getting pads for component: ${reference}`);
|
||||||
@@ -433,10 +374,7 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"get_component_list",
|
"get_component_list",
|
||||||
{
|
{
|
||||||
layer: z
|
layer: z.string().optional().describe("Filter by layer (e.g., 'F.Cu', 'B.Cu')"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Filter by layer (e.g., 'F.Cu', 'B.Cu')"),
|
|
||||||
boundingBox: z
|
boundingBox: z
|
||||||
.object({
|
.object({
|
||||||
x1: z.number(),
|
x1: z.number(),
|
||||||
@@ -447,10 +385,7 @@ export function registerComponentTools(
|
|||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Filter by bounding box region"),
|
.describe("Filter by bounding box region"),
|
||||||
unit: z
|
unit: z.enum(["mm", "inch"]).optional().describe("Unit for coordinates (default: mm)"),
|
||||||
.enum(["mm", "inch"])
|
|
||||||
.optional()
|
|
||||||
.describe("Unit for coordinates (default: mm)"),
|
|
||||||
},
|
},
|
||||||
async ({ layer, boundingBox, unit }) => {
|
async ({ layer, boundingBox, unit }) => {
|
||||||
logger.debug("Getting component list");
|
logger.debug("Getting component list");
|
||||||
@@ -477,14 +412,9 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"get_pad_position",
|
"get_pad_position",
|
||||||
{
|
{
|
||||||
reference: z
|
reference: z.string().describe("Component reference designator (e.g., 'U1')"),
|
||||||
.string()
|
|
||||||
.describe("Component reference designator (e.g., 'U1')"),
|
|
||||||
pad: z.string().describe("Pad number or name (e.g., '1', 'A1')"),
|
pad: z.string().describe("Pad number or name (e.g., '1', 'A1')"),
|
||||||
unit: z
|
unit: z.enum(["mm", "inch"]).optional().describe("Unit for coordinates (default: mm)"),
|
||||||
.enum(["mm", "inch"])
|
|
||||||
.optional()
|
|
||||||
.describe("Unit for coordinates (default: mm)"),
|
|
||||||
},
|
},
|
||||||
async ({ reference, pad, unit }) => {
|
async ({ reference, pad, unit }) => {
|
||||||
logger.debug(`Getting pad position for ${reference} pad ${pad}`);
|
logger.debug(`Getting pad position for ${reference} pad ${pad}`);
|
||||||
@@ -523,10 +453,7 @@ export function registerComponentTools(
|
|||||||
columns: z.number().describe("Number of columns"),
|
columns: z.number().describe("Number of columns"),
|
||||||
rowSpacing: z.number().describe("Spacing between rows"),
|
rowSpacing: z.number().describe("Spacing between rows"),
|
||||||
columnSpacing: z.number().describe("Spacing between columns"),
|
columnSpacing: z.number().describe("Spacing between columns"),
|
||||||
startReference: z
|
startReference: z.string().optional().describe("Starting reference (e.g., 'R1')"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Starting reference (e.g., 'R1')"),
|
|
||||||
footprint: z.string().optional().describe("Footprint name"),
|
footprint: z.string().optional().describe("Footprint name"),
|
||||||
value: z.string().optional().describe("Component value"),
|
value: z.string().optional().describe("Component value"),
|
||||||
rotation: z.number().optional().describe("Rotation in degrees"),
|
rotation: z.number().optional().describe("Rotation in degrees"),
|
||||||
@@ -543,9 +470,7 @@ export function registerComponentTools(
|
|||||||
value,
|
value,
|
||||||
rotation,
|
rotation,
|
||||||
}) => {
|
}) => {
|
||||||
logger.debug(
|
logger.debug(`Placing component array: ${rows}x${columns} of ${componentId}`);
|
||||||
`Placing component array: ${rows}x${columns} of ${componentId}`,
|
|
||||||
);
|
|
||||||
const result = await callKicadScript("place_component_array", {
|
const result = await callKicadScript("place_component_array", {
|
||||||
componentId,
|
componentId,
|
||||||
startPosition,
|
startPosition,
|
||||||
@@ -576,20 +501,10 @@ export function registerComponentTools(
|
|||||||
server.tool(
|
server.tool(
|
||||||
"align_components",
|
"align_components",
|
||||||
{
|
{
|
||||||
references: z
|
references: z.array(z.string()).describe("Array of component references to align"),
|
||||||
.array(z.string())
|
alignmentType: z.enum(["horizontal", "vertical", "grid"]).describe("Type of alignment"),
|
||||||
.describe("Array of component references to align"),
|
spacing: z.number().optional().describe("Spacing between components in mm"),
|
||||||
alignmentType: z
|
referenceComponent: z.string().optional().describe("Reference component for alignment"),
|
||||||
.enum(["horizontal", "vertical", "grid"])
|
|
||||||
.describe("Type of alignment"),
|
|
||||||
spacing: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Spacing between components in mm"),
|
|
||||||
referenceComponent: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Reference component for alignment"),
|
|
||||||
},
|
},
|
||||||
async ({ references, alignmentType, spacing, referenceComponent }) => {
|
async ({ references, alignmentType, spacing, referenceComponent }) => {
|
||||||
logger.debug(`Aligning components: ${references.join(", ")}`);
|
logger.debug(`Aligning components: ${references.join(", ")}`);
|
||||||
@@ -626,10 +541,7 @@ export function registerComponentTools(
|
|||||||
})
|
})
|
||||||
.describe("Offset from original position"),
|
.describe("Offset from original position"),
|
||||||
newReference: z.string().optional().describe("New reference designator"),
|
newReference: z.string().optional().describe("New reference designator"),
|
||||||
count: z
|
count: z.number().optional().describe("Number of duplicates (default: 1)"),
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Number of duplicates (default: 1)"),
|
|
||||||
},
|
},
|
||||||
async ({ reference, offset, newReference, count }) => {
|
async ({ reference, offset, newReference, count }) => {
|
||||||
logger.debug(`Duplicating component: ${reference}`);
|
logger.debug(`Duplicating component: ${reference}`);
|
||||||
|
|||||||
@@ -8,10 +8,7 @@
|
|||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export function registerDatasheetTools(
|
export function registerDatasheetTools(server: McpServer, callKicadScript: Function) {
|
||||||
server: McpServer,
|
|
||||||
callKicadScript: Function,
|
|
||||||
) {
|
|
||||||
// ── enrich_datasheets ──────────────────────────────────────────────────────
|
// ── enrich_datasheets ──────────────────────────────────────────────────────
|
||||||
server.tool(
|
server.tool(
|
||||||
"enrich_datasheets",
|
"enrich_datasheets",
|
||||||
@@ -30,16 +27,12 @@ No API key or internet lookup required – the URL is constructed directly.
|
|||||||
|
|
||||||
Use dry_run=true to preview changes without writing.`,
|
Use dry_run=true to preview changes without writing.`,
|
||||||
{
|
{
|
||||||
schematic_path: z
|
schematic_path: z.string().describe("Path to the .kicad_sch file to enrich"),
|
||||||
.string()
|
|
||||||
.describe("Path to the .kicad_sch file to enrich"),
|
|
||||||
dry_run: z
|
dry_run: z
|
||||||
.boolean()
|
.boolean()
|
||||||
.optional()
|
.optional()
|
||||||
.default(false)
|
.default(false)
|
||||||
.describe(
|
.describe("If true, show what would be changed without writing to disk (default: false)"),
|
||||||
"If true, show what would be changed without writing to disk (default: false)",
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
async (args: { schematic_path: string; dry_run?: boolean }) => {
|
async (args: { schematic_path: string; dry_run?: boolean }) => {
|
||||||
const result = await callKicadScript("enrich_datasheets", args);
|
const result = await callKicadScript("enrich_datasheets", args);
|
||||||
@@ -65,9 +58,7 @@ Use dry_run=true to preview changes without writing.`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.updated === 0 && !args.dry_run) {
|
if (result.updated === 0 && !args.dry_run) {
|
||||||
lines.push(
|
lines.push("\nNo changes needed – all LCSC components already have a Datasheet URL.");
|
||||||
"\nNo changes needed – all LCSC components already have a Datasheet URL.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { content: [{ type: "text", text: lines.join("\n") }] };
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
||||||
@@ -96,9 +87,7 @@ Example: get_datasheet_url("C179739")
|
|||||||
{
|
{
|
||||||
lcsc: z
|
lcsc: z
|
||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe('LCSC part number, with or without "C" prefix (e.g. "C179739" or "179739")'),
|
||||||
'LCSC part number, with or without "C" prefix (e.g. "C179739" or "179739")',
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
async (args: { lcsc: string }) => {
|
async (args: { lcsc: string }) => {
|
||||||
const result = await callKicadScript("get_datasheet_url", { lcsc: args.lcsc });
|
const result = await callKicadScript("get_datasheet_url", { lcsc: args.lcsc });
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* These tools handle design rule checking and configuration
|
* These tools handle design rule checking and configuration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
@@ -18,7 +18,7 @@ type CommandFunction = (command: string, params: Record<string, unknown>) => Pro
|
|||||||
* @param callKicadScript Function to call KiCAD script commands
|
* @param callKicadScript Function to call KiCAD script commands
|
||||||
*/
|
*/
|
||||||
export function registerDesignRuleTools(server: McpServer, callKicadScript: CommandFunction): void {
|
export function registerDesignRuleTools(server: McpServer, callKicadScript: CommandFunction): void {
|
||||||
logger.info('Registering design rule tools');
|
logger.info("Registering design rule tools");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Set Design Rules Tool
|
// Set Design Rules Tool
|
||||||
@@ -38,40 +38,46 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
minMicroViaDiameter: z.number().optional().describe("Minimum micro via diameter (mm)"),
|
minMicroViaDiameter: z.number().optional().describe("Minimum micro via diameter (mm)"),
|
||||||
minMicroViaDrill: z.number().optional().describe("Minimum micro via drill size (mm)"),
|
minMicroViaDrill: z.number().optional().describe("Minimum micro via drill size (mm)"),
|
||||||
minHoleDiameter: z.number().optional().describe("Minimum hole diameter (mm)"),
|
minHoleDiameter: z.number().optional().describe("Minimum hole diameter (mm)"),
|
||||||
requireCourtyard: z.boolean().optional().describe("Whether to require courtyards for all footprints"),
|
requireCourtyard: z
|
||||||
courtyardClearance: z.number().optional().describe("Minimum clearance between courtyards (mm)")
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Whether to require courtyards for all footprints"),
|
||||||
|
courtyardClearance: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Minimum clearance between courtyards (mm)"),
|
||||||
},
|
},
|
||||||
async (params) => {
|
async (params) => {
|
||||||
logger.debug('Setting design rules');
|
logger.debug("Setting design rules");
|
||||||
const result = await callKicadScript("set_design_rules", params);
|
const result = await callKicadScript("set_design_rules", params);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Get Design Rules Tool
|
// Get Design Rules Tool
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
server.tool(
|
server.tool("get_design_rules", {}, async () => {
|
||||||
"get_design_rules",
|
logger.debug("Getting design rules");
|
||||||
{},
|
|
||||||
async () => {
|
|
||||||
logger.debug('Getting design rules');
|
|
||||||
const result = await callKicadScript("get_design_rules", {});
|
const result = await callKicadScript("get_design_rules", {});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Run DRC Tool
|
// Run DRC Tool
|
||||||
@@ -79,19 +85,21 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
server.tool(
|
server.tool(
|
||||||
"run_drc",
|
"run_drc",
|
||||||
{
|
{
|
||||||
reportPath: z.string().optional().describe("Optional path to save the DRC report")
|
reportPath: z.string().optional().describe("Optional path to save the DRC report"),
|
||||||
},
|
},
|
||||||
async ({ reportPath }) => {
|
async ({ reportPath }) => {
|
||||||
logger.debug('Running DRC check');
|
logger.debug("Running DRC check");
|
||||||
const result = await callKicadScript("run_drc", { reportPath });
|
const result = await callKicadScript("run_drc", { reportPath });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -108,11 +116,29 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
viaDrill: z.number().describe("Via drill size for this net class (mm)"),
|
viaDrill: z.number().describe("Via drill size for this net class (mm)"),
|
||||||
uvia_diameter: z.number().optional().describe("Micro via diameter for this net class (mm)"),
|
uvia_diameter: z.number().optional().describe("Micro via diameter for this net class (mm)"),
|
||||||
uvia_drill: z.number().optional().describe("Micro via drill size for this net class (mm)"),
|
uvia_drill: z.number().optional().describe("Micro via drill size for this net class (mm)"),
|
||||||
diff_pair_width: z.number().optional().describe("Differential pair width for this net class (mm)"),
|
diff_pair_width: z
|
||||||
diff_pair_gap: z.number().optional().describe("Differential pair gap for this net class (mm)"),
|
.number()
|
||||||
nets: z.array(z.string()).optional().describe("Array of net names to assign to this class")
|
.optional()
|
||||||
|
.describe("Differential pair width for this net class (mm)"),
|
||||||
|
diff_pair_gap: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Differential pair gap for this net class (mm)"),
|
||||||
|
nets: z.array(z.string()).optional().describe("Array of net names to assign to this class"),
|
||||||
},
|
},
|
||||||
async ({ name, description, clearance, trackWidth, viaDiameter, viaDrill, uvia_diameter, uvia_drill, diff_pair_width, diff_pair_gap, nets }) => {
|
async ({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
clearance,
|
||||||
|
trackWidth,
|
||||||
|
viaDiameter,
|
||||||
|
viaDrill,
|
||||||
|
uvia_diameter,
|
||||||
|
uvia_drill,
|
||||||
|
diff_pair_width,
|
||||||
|
diff_pair_gap,
|
||||||
|
nets,
|
||||||
|
}) => {
|
||||||
logger.debug(`Adding net class: ${name}`);
|
logger.debug(`Adding net class: ${name}`);
|
||||||
const result = await callKicadScript("add_net_class", {
|
const result = await callKicadScript("add_net_class", {
|
||||||
name,
|
name,
|
||||||
@@ -125,16 +151,18 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
uvia_drill,
|
uvia_drill,
|
||||||
diff_pair_width,
|
diff_pair_width,
|
||||||
diff_pair_gap,
|
diff_pair_gap,
|
||||||
nets
|
nets,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -144,22 +172,24 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
"assign_net_to_class",
|
"assign_net_to_class",
|
||||||
{
|
{
|
||||||
net: z.string().describe("Name of the net"),
|
net: z.string().describe("Name of the net"),
|
||||||
netClass: z.string().describe("Name of the net class")
|
netClass: z.string().describe("Name of the net class"),
|
||||||
},
|
},
|
||||||
async ({ net, netClass }) => {
|
async ({ net, netClass }) => {
|
||||||
logger.debug(`Assigning net ${net} to class ${netClass}`);
|
logger.debug(`Assigning net ${net} to class ${netClass}`);
|
||||||
const result = await callKicadScript("assign_net_to_class", {
|
const result = await callKicadScript("assign_net_to_class", {
|
||||||
net,
|
net,
|
||||||
netClass
|
netClass,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -172,7 +202,7 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
minTrackWidth: z.number().optional().describe("Minimum track width for this layer (mm)"),
|
minTrackWidth: z.number().optional().describe("Minimum track width for this layer (mm)"),
|
||||||
minClearance: z.number().optional().describe("Minimum clearance for this layer (mm)"),
|
minClearance: z.number().optional().describe("Minimum clearance for this layer (mm)"),
|
||||||
minViaDiameter: z.number().optional().describe("Minimum via diameter for this layer (mm)"),
|
minViaDiameter: z.number().optional().describe("Minimum via diameter for this layer (mm)"),
|
||||||
minViaDrill: z.number().optional().describe("Minimum via drill size for this layer (mm)")
|
minViaDrill: z.number().optional().describe("Minimum via drill size for this layer (mm)"),
|
||||||
},
|
},
|
||||||
async ({ layer, minTrackWidth, minClearance, minViaDiameter, minViaDrill }) => {
|
async ({ layer, minTrackWidth, minClearance, minViaDiameter, minViaDrill }) => {
|
||||||
logger.debug(`Setting constraints for layer: ${layer}`);
|
logger.debug(`Setting constraints for layer: ${layer}`);
|
||||||
@@ -181,16 +211,18 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
minTrackWidth,
|
minTrackWidth,
|
||||||
minClearance,
|
minClearance,
|
||||||
minViaDiameter,
|
minViaDiameter,
|
||||||
minViaDrill
|
minViaDrill,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -199,41 +231,57 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
server.tool(
|
server.tool(
|
||||||
"check_clearance",
|
"check_clearance",
|
||||||
{
|
{
|
||||||
item1: z.object({
|
item1: z
|
||||||
type: z.enum(["track", "via", "pad", "zone", "component"]).describe("Type of the first item"),
|
.object({
|
||||||
|
type: z
|
||||||
|
.enum(["track", "via", "pad", "zone", "component"])
|
||||||
|
.describe("Type of the first item"),
|
||||||
id: z.string().optional().describe("ID of the first item (if applicable)"),
|
id: z.string().optional().describe("ID of the first item (if applicable)"),
|
||||||
reference: z.string().optional().describe("Reference designator (for component)"),
|
reference: z.string().optional().describe("Reference designator (for component)"),
|
||||||
position: z.object({
|
position: z
|
||||||
|
.object({
|
||||||
x: z.number().optional(),
|
x: z.number().optional(),
|
||||||
y: z.number().optional(),
|
y: z.number().optional(),
|
||||||
unit: z.enum(["mm", "inch"]).optional()
|
unit: z.enum(["mm", "inch"]).optional(),
|
||||||
}).optional().describe("Position to check (if ID not provided)")
|
})
|
||||||
}).describe("First item to check"),
|
.optional()
|
||||||
item2: z.object({
|
.describe("Position to check (if ID not provided)"),
|
||||||
type: z.enum(["track", "via", "pad", "zone", "component"]).describe("Type of the second item"),
|
})
|
||||||
|
.describe("First item to check"),
|
||||||
|
item2: z
|
||||||
|
.object({
|
||||||
|
type: z
|
||||||
|
.enum(["track", "via", "pad", "zone", "component"])
|
||||||
|
.describe("Type of the second item"),
|
||||||
id: z.string().optional().describe("ID of the second item (if applicable)"),
|
id: z.string().optional().describe("ID of the second item (if applicable)"),
|
||||||
reference: z.string().optional().describe("Reference designator (for component)"),
|
reference: z.string().optional().describe("Reference designator (for component)"),
|
||||||
position: z.object({
|
position: z
|
||||||
|
.object({
|
||||||
x: z.number().optional(),
|
x: z.number().optional(),
|
||||||
y: z.number().optional(),
|
y: z.number().optional(),
|
||||||
unit: z.enum(["mm", "inch"]).optional()
|
unit: z.enum(["mm", "inch"]).optional(),
|
||||||
}).optional().describe("Position to check (if ID not provided)")
|
})
|
||||||
}).describe("Second item to check")
|
.optional()
|
||||||
|
.describe("Position to check (if ID not provided)"),
|
||||||
|
})
|
||||||
|
.describe("Second item to check"),
|
||||||
},
|
},
|
||||||
async ({ item1, item2 }) => {
|
async ({ item1, item2 }) => {
|
||||||
logger.debug(`Checking clearance between ${item1.type} and ${item2.type}`);
|
logger.debug(`Checking clearance between ${item1.type} and ${item2.type}`);
|
||||||
const result = await callKicadScript("check_clearance", {
|
const result = await callKicadScript("check_clearance", {
|
||||||
item1,
|
item1,
|
||||||
item2
|
item2,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -242,20 +290,25 @@ export function registerDesignRuleTools(server: McpServer, callKicadScript: Comm
|
|||||||
server.tool(
|
server.tool(
|
||||||
"get_drc_violations",
|
"get_drc_violations",
|
||||||
{
|
{
|
||||||
severity: z.enum(["error", "warning", "all"]).optional().describe("Filter violations by severity")
|
severity: z
|
||||||
|
.enum(["error", "warning", "all"])
|
||||||
|
.optional()
|
||||||
|
.describe("Filter violations by severity"),
|
||||||
},
|
},
|
||||||
async ({ severity }) => {
|
async ({ severity }) => {
|
||||||
logger.debug('Getting DRC violations');
|
logger.debug("Getting DRC violations");
|
||||||
const result = await callKicadScript("get_drc_violations", { severity });
|
const result = await callKicadScript("get_drc_violations", { severity });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Design rule tools registered');
|
logger.info("Design rule tools registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* These tools handle exporting PCB data to various formats
|
* These tools handle exporting PCB data to various formats
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
@@ -18,7 +18,7 @@ type CommandFunction = (command: string, params: Record<string, unknown>) => Pro
|
|||||||
* @param callKicadScript Function to call KiCAD script commands
|
* @param callKicadScript Function to call KiCAD script commands
|
||||||
*/
|
*/
|
||||||
export function registerExportTools(server: McpServer, callKicadScript: CommandFunction): void {
|
export function registerExportTools(server: McpServer, callKicadScript: CommandFunction): void {
|
||||||
logger.info('Registering export tools');
|
logger.info("Registering export tools");
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Export Gerber Tool
|
// Export Gerber Tool
|
||||||
@@ -27,13 +27,26 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
"export_gerber",
|
"export_gerber",
|
||||||
{
|
{
|
||||||
outputDir: z.string().describe("Directory to save Gerber files"),
|
outputDir: z.string().describe("Directory to save Gerber files"),
|
||||||
layers: z.array(z.string()).optional().describe("Optional array of layer names to export (default: all)"),
|
layers: z
|
||||||
useProtelExtensions: z.boolean().optional().describe("Whether to use Protel filename extensions"),
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe("Optional array of layer names to export (default: all)"),
|
||||||
|
useProtelExtensions: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Whether to use Protel filename extensions"),
|
||||||
generateDrillFiles: z.boolean().optional().describe("Whether to generate drill files"),
|
generateDrillFiles: z.boolean().optional().describe("Whether to generate drill files"),
|
||||||
generateMapFile: z.boolean().optional().describe("Whether to generate a map file"),
|
generateMapFile: z.boolean().optional().describe("Whether to generate a map file"),
|
||||||
useAuxOrigin: z.boolean().optional().describe("Whether to use auxiliary axis as origin")
|
useAuxOrigin: z.boolean().optional().describe("Whether to use auxiliary axis as origin"),
|
||||||
},
|
},
|
||||||
async ({ outputDir, layers, useProtelExtensions, generateDrillFiles, generateMapFile, useAuxOrigin }) => {
|
async ({
|
||||||
|
outputDir,
|
||||||
|
layers,
|
||||||
|
useProtelExtensions,
|
||||||
|
generateDrillFiles,
|
||||||
|
generateMapFile,
|
||||||
|
useAuxOrigin,
|
||||||
|
}) => {
|
||||||
logger.debug(`Exporting Gerber files to: ${outputDir}`);
|
logger.debug(`Exporting Gerber files to: ${outputDir}`);
|
||||||
const result = await callKicadScript("export_gerber", {
|
const result = await callKicadScript("export_gerber", {
|
||||||
outputDir,
|
outputDir,
|
||||||
@@ -41,16 +54,18 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
useProtelExtensions,
|
useProtelExtensions,
|
||||||
generateDrillFiles,
|
generateDrillFiles,
|
||||||
generateMapFile,
|
generateMapFile,
|
||||||
useAuxOrigin
|
useAuxOrigin,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -60,10 +75,16 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
"export_pdf",
|
"export_pdf",
|
||||||
{
|
{
|
||||||
outputPath: z.string().describe("Path to save the PDF file"),
|
outputPath: z.string().describe("Path to save the PDF file"),
|
||||||
layers: z.array(z.string()).optional().describe("Optional array of layer names to include (default: all)"),
|
layers: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe("Optional array of layer names to include (default: all)"),
|
||||||
blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"),
|
blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"),
|
||||||
frameReference: z.boolean().optional().describe("Whether to include frame reference"),
|
frameReference: z.boolean().optional().describe("Whether to include frame reference"),
|
||||||
pageSize: z.enum(["A4", "A3", "A2", "A1", "A0", "Letter", "Legal", "Tabloid"]).optional().describe("Page size")
|
pageSize: z
|
||||||
|
.enum(["A4", "A3", "A2", "A1", "A0", "Letter", "Legal", "Tabloid"])
|
||||||
|
.optional()
|
||||||
|
.describe("Page size"),
|
||||||
},
|
},
|
||||||
async ({ outputPath, layers, blackAndWhite, frameReference, pageSize }) => {
|
async ({ outputPath, layers, blackAndWhite, frameReference, pageSize }) => {
|
||||||
logger.debug(`Exporting PDF to: ${outputPath}`);
|
logger.debug(`Exporting PDF to: ${outputPath}`);
|
||||||
@@ -72,16 +93,18 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
layers,
|
layers,
|
||||||
blackAndWhite,
|
blackAndWhite,
|
||||||
frameReference,
|
frameReference,
|
||||||
pageSize
|
pageSize,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -91,9 +114,12 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
"export_svg",
|
"export_svg",
|
||||||
{
|
{
|
||||||
outputPath: z.string().describe("Path to save the SVG file"),
|
outputPath: z.string().describe("Path to save the SVG file"),
|
||||||
layers: z.array(z.string()).optional().describe("Optional array of layer names to include (default: all)"),
|
layers: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe("Optional array of layer names to include (default: all)"),
|
||||||
blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"),
|
blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"),
|
||||||
includeComponents: z.boolean().optional().describe("Whether to include component outlines")
|
includeComponents: z.boolean().optional().describe("Whether to include component outlines"),
|
||||||
},
|
},
|
||||||
async ({ outputPath, layers, blackAndWhite, includeComponents }) => {
|
async ({ outputPath, layers, blackAndWhite, includeComponents }) => {
|
||||||
logger.debug(`Exporting SVG to: ${outputPath}`);
|
logger.debug(`Exporting SVG to: ${outputPath}`);
|
||||||
@@ -101,16 +127,18 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
outputPath,
|
outputPath,
|
||||||
layers,
|
layers,
|
||||||
blackAndWhite,
|
blackAndWhite,
|
||||||
includeComponents
|
includeComponents,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -124,9 +152,16 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
includeComponents: z.boolean().optional().describe("Whether to include 3D component models"),
|
includeComponents: z.boolean().optional().describe("Whether to include 3D component models"),
|
||||||
includeCopper: z.boolean().optional().describe("Whether to include copper layers"),
|
includeCopper: z.boolean().optional().describe("Whether to include copper layers"),
|
||||||
includeSolderMask: z.boolean().optional().describe("Whether to include solder mask"),
|
includeSolderMask: z.boolean().optional().describe("Whether to include solder mask"),
|
||||||
includeSilkscreen: z.boolean().optional().describe("Whether to include silkscreen")
|
includeSilkscreen: z.boolean().optional().describe("Whether to include silkscreen"),
|
||||||
},
|
},
|
||||||
async ({ outputPath, format, includeComponents, includeCopper, includeSolderMask, includeSilkscreen }) => {
|
async ({
|
||||||
|
outputPath,
|
||||||
|
format,
|
||||||
|
includeComponents,
|
||||||
|
includeCopper,
|
||||||
|
includeSolderMask,
|
||||||
|
includeSilkscreen,
|
||||||
|
}) => {
|
||||||
logger.debug(`Exporting 3D model to: ${outputPath}`);
|
logger.debug(`Exporting 3D model to: ${outputPath}`);
|
||||||
const result = await callKicadScript("export_3d", {
|
const result = await callKicadScript("export_3d", {
|
||||||
outputPath,
|
outputPath,
|
||||||
@@ -134,16 +169,18 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
includeComponents,
|
includeComponents,
|
||||||
includeCopper,
|
includeCopper,
|
||||||
includeSolderMask,
|
includeSolderMask,
|
||||||
includeSilkscreen
|
includeSilkscreen,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -155,7 +192,10 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
outputPath: z.string().describe("Path to save the BOM file"),
|
outputPath: z.string().describe("Path to save the BOM file"),
|
||||||
format: z.enum(["CSV", "XML", "HTML", "JSON"]).describe("BOM file format"),
|
format: z.enum(["CSV", "XML", "HTML", "JSON"]).describe("BOM file format"),
|
||||||
groupByValue: z.boolean().optional().describe("Whether to group components by value"),
|
groupByValue: z.boolean().optional().describe("Whether to group components by value"),
|
||||||
includeAttributes: z.array(z.string()).optional().describe("Optional array of additional attributes to include")
|
includeAttributes: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe("Optional array of additional attributes to include"),
|
||||||
},
|
},
|
||||||
async ({ outputPath, format, groupByValue, includeAttributes }) => {
|
async ({ outputPath, format, groupByValue, includeAttributes }) => {
|
||||||
logger.debug(`Exporting BOM to: ${outputPath}`);
|
logger.debug(`Exporting BOM to: ${outputPath}`);
|
||||||
@@ -163,16 +203,18 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
outputPath,
|
outputPath,
|
||||||
format,
|
format,
|
||||||
groupByValue,
|
groupByValue,
|
||||||
includeAttributes
|
includeAttributes,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -182,22 +224,27 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
"export_netlist",
|
"export_netlist",
|
||||||
{
|
{
|
||||||
outputPath: z.string().describe("Path to save the netlist file"),
|
outputPath: z.string().describe("Path to save the netlist file"),
|
||||||
format: z.enum(["KiCad", "Spice", "Cadstar", "OrcadPCB2"]).optional().describe("Netlist format (default: KiCad)")
|
format: z
|
||||||
|
.enum(["KiCad", "Spice", "Cadstar", "OrcadPCB2"])
|
||||||
|
.optional()
|
||||||
|
.describe("Netlist format (default: KiCad)"),
|
||||||
},
|
},
|
||||||
async ({ outputPath, format }) => {
|
async ({ outputPath, format }) => {
|
||||||
logger.debug(`Exporting netlist to: ${outputPath}`);
|
logger.debug(`Exporting netlist to: ${outputPath}`);
|
||||||
const result = await callKicadScript("export_netlist", {
|
const result = await callKicadScript("export_netlist", {
|
||||||
outputPath,
|
outputPath,
|
||||||
format
|
format,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -209,7 +256,10 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
outputPath: z.string().describe("Path to save the position file"),
|
outputPath: z.string().describe("Path to save the position file"),
|
||||||
format: z.enum(["CSV", "ASCII"]).optional().describe("File format (default: CSV)"),
|
format: z.enum(["CSV", "ASCII"]).optional().describe("File format (default: CSV)"),
|
||||||
units: z.enum(["mm", "inch"]).optional().describe("Units to use (default: mm)"),
|
units: z.enum(["mm", "inch"]).optional().describe("Units to use (default: mm)"),
|
||||||
side: z.enum(["top", "bottom", "both"]).optional().describe("Which board side to include (default: both)")
|
side: z
|
||||||
|
.enum(["top", "bottom", "both"])
|
||||||
|
.optional()
|
||||||
|
.describe("Which board side to include (default: both)"),
|
||||||
},
|
},
|
||||||
async ({ outputPath, format, units, side }) => {
|
async ({ outputPath, format, units, side }) => {
|
||||||
logger.debug(`Exporting position file to: ${outputPath}`);
|
logger.debug(`Exporting position file to: ${outputPath}`);
|
||||||
@@ -217,16 +267,18 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
outputPath,
|
outputPath,
|
||||||
format,
|
format,
|
||||||
units,
|
units,
|
||||||
side
|
side,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
@@ -237,24 +289,29 @@ export function registerExportTools(server: McpServer, callKicadScript: CommandF
|
|||||||
{
|
{
|
||||||
outputPath: z.string().describe("Path to save the VRML file"),
|
outputPath: z.string().describe("Path to save the VRML file"),
|
||||||
includeComponents: z.boolean().optional().describe("Whether to include 3D component models"),
|
includeComponents: z.boolean().optional().describe("Whether to include 3D component models"),
|
||||||
useRelativePaths: z.boolean().optional().describe("Whether to use relative paths for 3D models")
|
useRelativePaths: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Whether to use relative paths for 3D models"),
|
||||||
},
|
},
|
||||||
async ({ outputPath, includeComponents, useRelativePaths }) => {
|
async ({ outputPath, includeComponents, useRelativePaths }) => {
|
||||||
logger.debug(`Exporting VRML to: ${outputPath}`);
|
logger.debug(`Exporting VRML to: ${outputPath}`);
|
||||||
const result = await callKicadScript("export_vrml", {
|
const result = await callKicadScript("export_vrml", {
|
||||||
outputPath,
|
outputPath,
|
||||||
includeComponents,
|
includeComponents,
|
||||||
useRelativePaths
|
useRelativePaths,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result)
|
text: JSON.stringify(result),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Export tools registered');
|
logger.info("Export tools registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,10 +62,7 @@ const RectSchema = z.object({
|
|||||||
|
|
||||||
// ---- tool registration --------------------------------------------------- //
|
// ---- tool registration --------------------------------------------------- //
|
||||||
|
|
||||||
export function registerFootprintTools(
|
export function registerFootprintTools(server: McpServer, callKicadScript: Function) {
|
||||||
server: McpServer,
|
|
||||||
callKicadScript: Function,
|
|
||||||
) {
|
|
||||||
// ── create_footprint ──────────────────────────────────────────────────── //
|
// ── create_footprint ──────────────────────────────────────────────────── //
|
||||||
server.tool(
|
server.tool(
|
||||||
"create_footprint",
|
"create_footprint",
|
||||||
@@ -80,10 +77,7 @@ export function registerFootprintTools(
|
|||||||
),
|
),
|
||||||
name: z.string().describe("Footprint name, e.g. 'R_0603_Custom'"),
|
name: z.string().describe("Footprint name, e.g. 'R_0603_Custom'"),
|
||||||
description: z.string().optional().describe("Human-readable description"),
|
description: z.string().optional().describe("Human-readable description"),
|
||||||
tags: z
|
tags: z.string().optional().describe("Space-separated tag string, e.g. 'resistor SMD 0603'"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Space-separated tag string, e.g. 'resistor SMD 0603'"),
|
|
||||||
pads: z
|
pads: z
|
||||||
.array(PadSchema)
|
.array(PadSchema)
|
||||||
.optional()
|
.optional()
|
||||||
@@ -91,9 +85,7 @@ export function registerFootprintTools(
|
|||||||
courtyard: RectSchema.optional().describe(
|
courtyard: RectSchema.optional().describe(
|
||||||
"Courtyard rectangle on F.CrtYd (recommended: 0.25 mm clearance around pads)",
|
"Courtyard rectangle on F.CrtYd (recommended: 0.25 mm clearance around pads)",
|
||||||
),
|
),
|
||||||
silkscreen: RectSchema.optional().describe(
|
silkscreen: RectSchema.optional().describe("Silkscreen rectangle on F.SilkS"),
|
||||||
"Silkscreen rectangle on F.SilkS",
|
|
||||||
),
|
|
||||||
fabLayer: RectSchema.optional().describe(
|
fabLayer: RectSchema.optional().describe(
|
||||||
"Fab-layer rectangle on F.Fab (shows component body)",
|
"Fab-layer rectangle on F.Fab (shows component body)",
|
||||||
),
|
),
|
||||||
@@ -139,9 +131,7 @@ export function registerFootprintTools(
|
|||||||
footprintPath: z
|
footprintPath: z
|
||||||
.string()
|
.string()
|
||||||
.describe("Full path to the .kicad_mod file, e.g. C:/MyLib.pretty/R_Custom.kicad_mod"),
|
.describe("Full path to the .kicad_mod file, e.g. C:/MyLib.pretty/R_Custom.kicad_mod"),
|
||||||
padNumber: z
|
padNumber: z.union([z.string(), z.number()]).describe("Pad number to edit, e.g. '1' or 2"),
|
||||||
.union([z.string(), z.number()])
|
|
||||||
.describe("Pad number to edit, e.g. '1' or 2"),
|
|
||||||
size: PadSize.optional().describe("New pad size in mm"),
|
size: PadSize.optional().describe("New pad size in mm"),
|
||||||
at: PadPosition.optional().describe("New pad position in mm"),
|
at: PadPosition.optional().describe("New pad position in mm"),
|
||||||
drill: z
|
drill: z
|
||||||
@@ -151,10 +141,7 @@ export function registerFootprintTools(
|
|||||||
])
|
])
|
||||||
.optional()
|
.optional()
|
||||||
.describe("New drill size (for THT pads)"),
|
.describe("New drill size (for THT pads)"),
|
||||||
shape: z
|
shape: z.enum(["rect", "circle", "oval", "roundrect"]).optional().describe("New pad shape"),
|
||||||
.enum(["rect", "circle", "oval", "roundrect"])
|
|
||||||
.optional()
|
|
||||||
.describe("New pad shape"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
footprintPath: string;
|
footprintPath: string;
|
||||||
@@ -177,9 +164,7 @@ export function registerFootprintTools(
|
|||||||
"Register a .pretty footprint library in KiCAD's fp-lib-table so KiCAD can find the footprints. " +
|
"Register a .pretty footprint library in KiCAD's fp-lib-table so KiCAD can find the footprints. " +
|
||||||
"Run this after create_footprint when KiCAD shows 'library not found in footprint library table'.",
|
"Run this after create_footprint when KiCAD shows 'library not found in footprint library table'.",
|
||||||
{
|
{
|
||||||
libraryPath: z
|
libraryPath: z.string().describe("Full path to the .pretty directory to register"),
|
||||||
.string()
|
|
||||||
.describe("Full path to the .pretty directory to register"),
|
|
||||||
libraryName: z
|
libraryName: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
|
|||||||
@@ -7,33 +7,21 @@
|
|||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export function registerFreeroutingTools(
|
export function registerFreeroutingTools(server: McpServer, callKicadScript: Function) {
|
||||||
server: McpServer,
|
|
||||||
callKicadScript: Function,
|
|
||||||
) {
|
|
||||||
// Full autoroute: export DSN -> run Freerouting -> import SES
|
// Full autoroute: export DSN -> run Freerouting -> import SES
|
||||||
server.tool(
|
server.tool(
|
||||||
"autoroute",
|
"autoroute",
|
||||||
"Run Freerouting autorouter on the current PCB. Exports to Specctra DSN, runs Freerouting CLI, and imports the routed SES result. Requires Java 11+ and freerouting.jar (see check_freerouting).",
|
"Run Freerouting autorouter on the current PCB. Exports to Specctra DSN, runs Freerouting CLI, and imports the routed SES result. Requires Java 11+ and freerouting.jar (see check_freerouting).",
|
||||||
{
|
{
|
||||||
boardPath: z
|
boardPath: z.string().optional().describe("Path to .kicad_pcb file (default: current board)"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Path to .kicad_pcb file (default: current board)"),
|
|
||||||
freeroutingJar: z
|
freeroutingJar: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.describe(
|
.describe(
|
||||||
"Path to freerouting.jar (default: ~/.kicad-mcp/freerouting.jar or FREEROUTING_JAR env)",
|
"Path to freerouting.jar (default: ~/.kicad-mcp/freerouting.jar or FREEROUTING_JAR env)",
|
||||||
),
|
),
|
||||||
maxPasses: z
|
maxPasses: z.number().optional().describe("Maximum routing passes (default: 20)"),
|
||||||
.number()
|
timeout: z.number().optional().describe("Timeout in seconds (default: 300)"),
|
||||||
.optional()
|
|
||||||
.describe("Maximum routing passes (default: 20)"),
|
|
||||||
timeout: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Timeout in seconds (default: 300)"),
|
|
||||||
},
|
},
|
||||||
async (args: any) => {
|
async (args: any) => {
|
||||||
const result = await callKicadScript("autoroute", args);
|
const result = await callKicadScript("autoroute", args);
|
||||||
@@ -53,10 +41,7 @@ export function registerFreeroutingTools(
|
|||||||
"export_dsn",
|
"export_dsn",
|
||||||
"Export the current PCB to Specctra DSN format. Useful for manual Freerouting workflow or external autorouters.",
|
"Export the current PCB to Specctra DSN format. Useful for manual Freerouting workflow or external autorouters.",
|
||||||
{
|
{
|
||||||
boardPath: z
|
boardPath: z.string().optional().describe("Path to .kicad_pcb file (default: current board)"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Path to .kicad_pcb file (default: current board)"),
|
|
||||||
outputPath: z
|
outputPath: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -81,10 +66,7 @@ export function registerFreeroutingTools(
|
|||||||
"Import a Specctra SES (session) file into the current PCB. Use after running Freerouting externally.",
|
"Import a Specctra SES (session) file into the current PCB. Use after running Freerouting externally.",
|
||||||
{
|
{
|
||||||
sesPath: z.string().describe("Path to the .ses file to import"),
|
sesPath: z.string().describe("Path to the .ses file to import"),
|
||||||
boardPath: z
|
boardPath: z.string().optional().describe("Path to .kicad_pcb file (default: current board)"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Path to .kicad_pcb file (default: current board)"),
|
|
||||||
},
|
},
|
||||||
async (args: any) => {
|
async (args: any) => {
|
||||||
const result = await callKicadScript("import_ses", args);
|
const result = await callKicadScript("import_ses", args);
|
||||||
@@ -104,10 +86,7 @@ export function registerFreeroutingTools(
|
|||||||
"check_freerouting",
|
"check_freerouting",
|
||||||
"Check if Java and Freerouting JAR are available on the system. Run this before autoroute to verify prerequisites.",
|
"Check if Java and Freerouting JAR are available on the system. Run this before autoroute to verify prerequisites.",
|
||||||
{
|
{
|
||||||
freeroutingJar: z
|
freeroutingJar: z.string().optional().describe("Path to freerouting.jar to check"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Path to freerouting.jar to check"),
|
|
||||||
},
|
},
|
||||||
async (args: any) => {
|
async (args: any) => {
|
||||||
const result = await callKicadScript("check_freerouting", args);
|
const result = await callKicadScript("check_freerouting", args);
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* Provides access to JLCPCB's complete parts catalog via their API
|
* Provides access to JLCPCB's complete parts catalog via their API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
|
|
||||||
export function registerJLCPCBApiTools(server: McpServer, callKicadScript: Function) {
|
export function registerJLCPCBApiTools(server: McpServer, callKicadScript: Function) {
|
||||||
// Download JLCPCB parts database
|
// Download JLCPCB parts database
|
||||||
@@ -18,32 +18,41 @@ No API credentials required - uses public JLCSearch API.
|
|||||||
The download takes 5-10 minutes and creates a local SQLite database
|
The download takes 5-10 minutes and creates a local SQLite database
|
||||||
for fast offline searching.`,
|
for fast offline searching.`,
|
||||||
{
|
{
|
||||||
force: z.boolean().optional().default(false)
|
force: z
|
||||||
.describe("Force re-download even if database exists")
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.default(false)
|
||||||
|
.describe("Force re-download even if database exists"),
|
||||||
},
|
},
|
||||||
async (args: { force?: boolean }) => {
|
async (args: { force?: boolean }) => {
|
||||||
const result = await callKicadScript("download_jlcpcb_database", args);
|
const result = await callKicadScript("download_jlcpcb_database", args);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `✓ Successfully downloaded JLCPCB parts database\n\n` +
|
text:
|
||||||
|
`✓ Successfully downloaded JLCPCB parts database\n\n` +
|
||||||
`Total parts: ${result.total_parts}\n` +
|
`Total parts: ${result.total_parts}\n` +
|
||||||
`Basic parts: ${result.basic_parts}\n` +
|
`Basic parts: ${result.basic_parts}\n` +
|
||||||
`Extended parts: ${result.extended_parts}\n` +
|
`Extended parts: ${result.extended_parts}\n` +
|
||||||
`Database size: ${result.db_size_mb} MB\n` +
|
`Database size: ${result.db_size_mb} MB\n` +
|
||||||
`Database path: ${result.db_path}`
|
`Database path: ${result.db_path}`,
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `✗ Failed to download JLCPCB database: ${result.message || 'Unknown error'}\n\n` +
|
text:
|
||||||
`Make sure JLCPCB_API_KEY and JLCPCB_API_SECRET environment variables are set.`
|
`✗ Failed to download JLCPCB database: ${result.message || "Unknown error"}\n\n` +
|
||||||
}]
|
`Make sure JLCPCB_API_KEY and JLCPCB_API_SECRET environment variables are set.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Search JLCPCB parts
|
// Search JLCPCB parts
|
||||||
@@ -56,58 +65,80 @@ Provides real pricing, stock info, and library type (Basic parts = free assembly
|
|||||||
|
|
||||||
Use this to find components with exact specifications and cost optimization.`,
|
Use this to find components with exact specifications and cost optimization.`,
|
||||||
{
|
{
|
||||||
query: z.string().optional()
|
query: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
.describe("Free-text search (e.g., '10k resistor 0603', 'ESP32', 'STM32F103')"),
|
.describe("Free-text search (e.g., '10k resistor 0603', 'ESP32', 'STM32F103')"),
|
||||||
category: z.string().optional()
|
category: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
.describe("Filter by category (e.g., 'Resistors', 'Capacitors', 'Microcontrollers')"),
|
.describe("Filter by category (e.g., 'Resistors', 'Capacitors', 'Microcontrollers')"),
|
||||||
package: z.string().optional()
|
package: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
.describe("Filter by package type (e.g., '0603', 'SOT-23', 'QFN-32')"),
|
.describe("Filter by package type (e.g., '0603', 'SOT-23', 'QFN-32')"),
|
||||||
library_type: z.enum(["Basic", "Extended", "Preferred", "All"]).optional().default("All")
|
library_type: z
|
||||||
|
.enum(["Basic", "Extended", "Preferred", "All"])
|
||||||
|
.optional()
|
||||||
|
.default("All")
|
||||||
.describe("Filter by library type (Basic = free assembly at JLCPCB)"),
|
.describe("Filter by library type (Basic = free assembly at JLCPCB)"),
|
||||||
manufacturer: z.string().optional()
|
manufacturer: z.string().optional().describe("Filter by manufacturer name"),
|
||||||
.describe("Filter by manufacturer name"),
|
in_stock: z
|
||||||
in_stock: z.boolean().optional().default(true)
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.default(true)
|
||||||
.describe("Only show parts with available stock"),
|
.describe("Only show parts with available stock"),
|
||||||
limit: z.number().optional().default(20)
|
limit: z.number().optional().default(20).describe("Maximum number of results to return"),
|
||||||
.describe("Maximum number of results to return")
|
|
||||||
},
|
},
|
||||||
async (args: any) => {
|
async (args: any) => {
|
||||||
const result = await callKicadScript("search_jlcpcb_parts", args);
|
const result = await callKicadScript("search_jlcpcb_parts", args);
|
||||||
if (result.success && result.parts) {
|
if (result.success && result.parts) {
|
||||||
if (result.parts.length === 0) {
|
if (result.parts.length === 0) {
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `No JLCPCB parts found matching your criteria.\n\n` +
|
text:
|
||||||
`Try broadening your search or check if the database is populated.`
|
`No JLCPCB parts found matching your criteria.\n\n` +
|
||||||
}]
|
`Try broadening your search or check if the database is populated.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const partsList = result.parts.map((p: any) => {
|
const partsList = result.parts
|
||||||
const priceInfo = p.price_breaks && p.price_breaks.length > 0
|
.map((p: any) => {
|
||||||
|
const priceInfo =
|
||||||
|
p.price_breaks && p.price_breaks.length > 0
|
||||||
? ` - $${p.price_breaks[0].price}/ea`
|
? ` - $${p.price_breaks[0].price}/ea`
|
||||||
: '';
|
: "";
|
||||||
const stockInfo = p.stock > 0 ? ` (${p.stock} in stock)` : ' (out of stock)';
|
const stockInfo = p.stock > 0 ? ` (${p.stock} in stock)` : " (out of stock)";
|
||||||
return `${p.lcsc}: ${p.mfr_part} - ${p.description} [${p.library_type}]${priceInfo}${stockInfo}`;
|
return `${p.lcsc}: ${p.mfr_part} - ${p.description} [${p.library_type}]${priceInfo}${stockInfo}`;
|
||||||
}).join('\n');
|
})
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Found ${result.count} JLCPCB parts:\n\n${partsList}\n\n` +
|
text:
|
||||||
`💡 Basic parts have free assembly. Extended parts charge $3 setup fee per unique part.`
|
`Found ${result.count} JLCPCB parts:\n\n${partsList}\n\n` +
|
||||||
}]
|
`💡 Basic parts have free assembly. Extended parts charge $3 setup fee per unique part.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Failed to search JLCPCB parts: ${result.message || 'Unknown error'}\n\n` +
|
text:
|
||||||
`Make sure you've downloaded the database first using download_jlcpcb_database.`
|
`Failed to search JLCPCB parts: ${result.message || "Unknown error"}\n\n` +
|
||||||
}]
|
`Make sure you've downloaded the database first using download_jlcpcb_database.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get JLCPCB part details
|
// Get JLCPCB part details
|
||||||
@@ -115,50 +146,55 @@ Use this to find components with exact specifications and cost optimization.`,
|
|||||||
"get_jlcpcb_part",
|
"get_jlcpcb_part",
|
||||||
"Get detailed information about a specific JLCPCB part by LCSC number",
|
"Get detailed information about a specific JLCPCB part by LCSC number",
|
||||||
{
|
{
|
||||||
lcsc_number: z.string()
|
lcsc_number: z.string().describe("LCSC part number (e.g., 'C25804', 'C2286')"),
|
||||||
.describe("LCSC part number (e.g., 'C25804', 'C2286')")
|
|
||||||
},
|
},
|
||||||
async (args: { lcsc_number: string }) => {
|
async (args: { lcsc_number: string }) => {
|
||||||
const result = await callKicadScript("get_jlcpcb_part", args);
|
const result = await callKicadScript("get_jlcpcb_part", args);
|
||||||
if (result.success && result.part) {
|
if (result.success && result.part) {
|
||||||
const p = result.part;
|
const p = result.part;
|
||||||
const priceTable = p.price_breaks && p.price_breaks.length > 0
|
const priceTable =
|
||||||
? '\n\nPrice Breaks:\n' + p.price_breaks.map((pb: any) =>
|
p.price_breaks && p.price_breaks.length > 0
|
||||||
` ${pb.qty}+: $${pb.price}/ea`
|
? "\n\nPrice Breaks:\n" +
|
||||||
).join('\n')
|
p.price_breaks.map((pb: any) => ` ${pb.qty}+: $${pb.price}/ea`).join("\n")
|
||||||
: '';
|
: "";
|
||||||
|
|
||||||
const footprints = result.footprints && result.footprints.length > 0
|
const footprints =
|
||||||
? '\n\nSuggested KiCAD Footprints:\n' + result.footprints.map((f: string) =>
|
result.footprints && result.footprints.length > 0
|
||||||
` - ${f}`
|
? "\n\nSuggested KiCAD Footprints:\n" +
|
||||||
).join('\n')
|
result.footprints.map((f: string) => ` - ${f}`).join("\n")
|
||||||
: '';
|
: "";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `LCSC: ${p.lcsc}\n` +
|
text:
|
||||||
|
`LCSC: ${p.lcsc}\n` +
|
||||||
`MFR Part: ${p.mfr_part}\n` +
|
`MFR Part: ${p.mfr_part}\n` +
|
||||||
`Manufacturer: ${p.manufacturer}\n` +
|
`Manufacturer: ${p.manufacturer}\n` +
|
||||||
`Category: ${p.category} / ${p.subcategory}\n` +
|
`Category: ${p.category} / ${p.subcategory}\n` +
|
||||||
`Package: ${p.package}\n` +
|
`Package: ${p.package}\n` +
|
||||||
`Description: ${p.description}\n` +
|
`Description: ${p.description}\n` +
|
||||||
`Library Type: ${p.library_type} ${p.library_type === 'Basic' ? '(Free assembly!)' : ''}\n` +
|
`Library Type: ${p.library_type} ${p.library_type === "Basic" ? "(Free assembly!)" : ""}\n` +
|
||||||
`Stock: ${p.stock}\n` +
|
`Stock: ${p.stock}\n` +
|
||||||
(p.datasheet ? `Datasheet: ${p.datasheet}\n` : '') +
|
(p.datasheet ? `Datasheet: ${p.datasheet}\n` : "") +
|
||||||
priceTable +
|
priceTable +
|
||||||
footprints
|
footprints,
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Part not found: ${args.lcsc_number}\n\n` +
|
text:
|
||||||
`Make sure you've downloaded the JLCPCB database first.`
|
`Part not found: ${args.lcsc_number}\n\n` +
|
||||||
}]
|
`Make sure you've downloaded the JLCPCB database first.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get JLCPCB database statistics
|
// Get JLCPCB database statistics
|
||||||
@@ -171,25 +207,31 @@ Use this to find components with exact specifications and cost optimization.`,
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
const stats = result.stats;
|
const stats = result.stats;
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `JLCPCB Database Statistics:\n\n` +
|
text:
|
||||||
|
`JLCPCB Database Statistics:\n\n` +
|
||||||
`Total parts: ${stats.total_parts.toLocaleString()}\n` +
|
`Total parts: ${stats.total_parts.toLocaleString()}\n` +
|
||||||
`Basic parts: ${stats.basic_parts.toLocaleString()} (free assembly)\n` +
|
`Basic parts: ${stats.basic_parts.toLocaleString()} (free assembly)\n` +
|
||||||
`Extended parts: ${stats.extended_parts.toLocaleString()} ($3 setup fee each)\n` +
|
`Extended parts: ${stats.extended_parts.toLocaleString()} ($3 setup fee each)\n` +
|
||||||
`In stock: ${stats.in_stock.toLocaleString()}\n` +
|
`In stock: ${stats.in_stock.toLocaleString()}\n` +
|
||||||
`Database path: ${stats.db_path}`
|
`Database path: ${stats.db_path}`,
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `JLCPCB database not found or empty.\n\n` +
|
text:
|
||||||
`Run download_jlcpcb_database first to populate the database.`
|
`JLCPCB database not found or empty.\n\n` +
|
||||||
}]
|
`Run download_jlcpcb_database first to populate the database.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Suggest alternative parts
|
// Suggest alternative parts
|
||||||
@@ -200,46 +242,54 @@ Use this to find components with exact specifications and cost optimization.`,
|
|||||||
Finds similar parts that may be cheaper, have more stock, or are Basic library type.
|
Finds similar parts that may be cheaper, have more stock, or are Basic library type.
|
||||||
Useful for cost optimization and finding alternatives when parts are out of stock.`,
|
Useful for cost optimization and finding alternatives when parts are out of stock.`,
|
||||||
{
|
{
|
||||||
lcsc_number: z.string()
|
lcsc_number: z.string().describe("Reference LCSC part number to find alternatives for"),
|
||||||
.describe("Reference LCSC part number to find alternatives for"),
|
limit: z.number().optional().default(5).describe("Maximum number of alternatives to return"),
|
||||||
limit: z.number().optional().default(5)
|
|
||||||
.describe("Maximum number of alternatives to return")
|
|
||||||
},
|
},
|
||||||
async (args: { lcsc_number: string; limit?: number }) => {
|
async (args: { lcsc_number: string; limit?: number }) => {
|
||||||
const result = await callKicadScript("suggest_jlcpcb_alternatives", args);
|
const result = await callKicadScript("suggest_jlcpcb_alternatives", args);
|
||||||
if (result.success && result.alternatives) {
|
if (result.success && result.alternatives) {
|
||||||
if (result.alternatives.length === 0) {
|
if (result.alternatives.length === 0) {
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `No alternatives found for ${args.lcsc_number}`
|
text: `No alternatives found for ${args.lcsc_number}`,
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const altsList = result.alternatives.map((p: any, i: number) => {
|
const altsList = result.alternatives
|
||||||
const priceInfo = p.price_breaks && p.price_breaks.length > 0
|
.map((p: any, i: number) => {
|
||||||
|
const priceInfo =
|
||||||
|
p.price_breaks && p.price_breaks.length > 0
|
||||||
? ` - $${p.price_breaks[0].price}/ea`
|
? ` - $${p.price_breaks[0].price}/ea`
|
||||||
: '';
|
: "";
|
||||||
const savings = result.reference_price && p.price_breaks && p.price_breaks.length > 0
|
const savings =
|
||||||
|
result.reference_price && p.price_breaks && p.price_breaks.length > 0
|
||||||
? ` (${((1 - p.price_breaks[0].price / result.reference_price) * 100).toFixed(0)}% cheaper)`
|
? ` (${((1 - p.price_breaks[0].price / result.reference_price) * 100).toFixed(0)}% cheaper)`
|
||||||
: '';
|
: "";
|
||||||
return `${i + 1}. ${p.lcsc}: ${p.mfr_part} [${p.library_type}]${priceInfo}${savings}\n ${p.description}\n Stock: ${p.stock}`;
|
return `${i + 1}. ${p.lcsc}: ${p.mfr_part} [${p.library_type}]${priceInfo}${savings}\n ${p.description}\n Stock: ${p.stock}`;
|
||||||
}).join('\n\n');
|
})
|
||||||
|
.join("\n\n");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Alternative parts for ${args.lcsc_number}:\n\n${altsList}`
|
text: `Alternative parts for ${args.lcsc_number}:\n\n${altsList}`,
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Failed to find alternatives: ${result.message || 'Unknown error'}`
|
text: `Failed to find alternatives: ${result.message || "Unknown error"}`,
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* Provides search/browse access to local KiCad symbol libraries
|
* Provides search/browse access to local KiCad symbol libraries
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
|
|
||||||
export function registerSymbolLibraryTools(server: McpServer, callKicadScript: Function) {
|
export function registerSymbolLibraryTools(server: McpServer, callKicadScript: Function) {
|
||||||
// List available symbol libraries
|
// List available symbol libraries
|
||||||
@@ -19,20 +19,20 @@ export function registerSymbolLibraryTools(server: McpServer, callKicadScript: F
|
|||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Found ${result.count} symbol libraries:\n${result.libraries.join('\n')}`
|
text: `Found ${result.count} symbol libraries:\n${result.libraries.join("\n")}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Failed to list symbol libraries: ${result.message || 'Unknown error'}`
|
text: `Failed to list symbol libraries: ${result.message || "Unknown error"}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Search for symbols across all libraries
|
// Search for symbols across all libraries
|
||||||
@@ -45,12 +45,12 @@ Use this to find components already in your local libraries (e.g., JLCPCB-KiCad-
|
|||||||
|
|
||||||
Returns symbol references that can be used directly in schematics.`,
|
Returns symbol references that can be used directly in schematics.`,
|
||||||
{
|
{
|
||||||
query: z.string()
|
query: z.string().describe("Search query (e.g., 'ESP32', 'STM32F103', 'C8734' for LCSC ID)"),
|
||||||
.describe("Search query (e.g., 'ESP32', 'STM32F103', 'C8734' for LCSC ID)"),
|
library: z
|
||||||
library: z.string().optional()
|
.string()
|
||||||
|
.optional()
|
||||||
.describe("Optional: filter to specific library name pattern (e.g., 'JLCPCB')"),
|
.describe("Optional: filter to specific library name pattern (e.g., 'JLCPCB')"),
|
||||||
limit: z.number().optional().default(20)
|
limit: z.number().optional().default(20).describe("Maximum number of results to return"),
|
||||||
.describe("Maximum number of results to return")
|
|
||||||
},
|
},
|
||||||
async (args: { query: string; library?: string; limit?: number }) => {
|
async (args: { query: string; library?: string; limit?: number }) => {
|
||||||
const result = await callKicadScript("search_symbols", args);
|
const result = await callKicadScript("search_symbols", args);
|
||||||
@@ -60,38 +60,40 @@ Returns symbol references that can be used directly in schematics.`,
|
|||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `No symbols found matching "${args.query}"${args.library ? ` in libraries matching "${args.library}"` : ''}`
|
text: `No symbols found matching "${args.query}"${args.library ? ` in libraries matching "${args.library}"` : ""}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const symbolList = result.symbols.map((s: any) => {
|
const symbolList = result.symbols
|
||||||
|
.map((s: any) => {
|
||||||
const parts = [`${s.full_ref}`];
|
const parts = [`${s.full_ref}`];
|
||||||
if (s.lcsc_id) parts.push(`LCSC: ${s.lcsc_id}`);
|
if (s.lcsc_id) parts.push(`LCSC: ${s.lcsc_id}`);
|
||||||
if (s.description) parts.push(s.description);
|
if (s.description) parts.push(s.description);
|
||||||
else if (s.value) parts.push(s.value);
|
else if (s.value) parts.push(s.value);
|
||||||
return parts.join(' | ');
|
return parts.join(" | ");
|
||||||
}).join('\n');
|
})
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Found ${result.count} symbols matching "${args.query}":\n\n${symbolList}`
|
text: `Found ${result.count} symbols matching "${args.query}":\n\n${symbolList}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Failed to search symbols: ${result.message || 'Unknown error'}`
|
text: `Failed to search symbols: ${result.message || "Unknown error"}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// List symbols in a specific library
|
// List symbols in a specific library
|
||||||
@@ -99,36 +101,37 @@ Returns symbol references that can be used directly in schematics.`,
|
|||||||
"list_library_symbols",
|
"list_library_symbols",
|
||||||
"List all symbols in a specific KiCAD symbol library",
|
"List all symbols in a specific KiCAD symbol library",
|
||||||
{
|
{
|
||||||
library: z.string()
|
library: z.string().describe("Library name (e.g., 'Device', 'PCM_JLCPCB-MCUs')"),
|
||||||
.describe("Library name (e.g., 'Device', 'PCM_JLCPCB-MCUs')")
|
|
||||||
},
|
},
|
||||||
async (args: { library: string }) => {
|
async (args: { library: string }) => {
|
||||||
const result = await callKicadScript("list_library_symbols", args);
|
const result = await callKicadScript("list_library_symbols", args);
|
||||||
if (result.success && result.symbols) {
|
if (result.success && result.symbols) {
|
||||||
const symbolList = result.symbols.map((s: any) => {
|
const symbolList = result.symbols
|
||||||
|
.map((s: any) => {
|
||||||
const parts = [` - ${s.name}`];
|
const parts = [` - ${s.name}`];
|
||||||
if (s.lcsc_id) parts.push(`(LCSC: ${s.lcsc_id})`);
|
if (s.lcsc_id) parts.push(`(LCSC: ${s.lcsc_id})`);
|
||||||
return parts.join(' ');
|
return parts.join(" ");
|
||||||
}).join('\n');
|
})
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Library "${args.library}" contains ${result.count} symbols:\n${symbolList}`
|
text: `Library "${args.library}" contains ${result.count} symbols:\n${symbolList}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Failed to list symbols in library ${args.library}: ${result.message || 'Unknown error'}`
|
text: `Failed to list symbols in library ${args.library}: ${result.message || "Unknown error"}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get detailed information about a specific symbol
|
// Get detailed information about a specific symbol
|
||||||
@@ -136,8 +139,9 @@ Returns symbol references that can be used directly in schematics.`,
|
|||||||
"get_symbol_info",
|
"get_symbol_info",
|
||||||
"Get detailed information about a specific symbol",
|
"Get detailed information about a specific symbol",
|
||||||
{
|
{
|
||||||
symbol: z.string()
|
symbol: z
|
||||||
.describe("Symbol specification (e.g., 'Device:R' or 'PCM_JLCPCB-MCUs:STM32F103C8T6')")
|
.string()
|
||||||
|
.describe("Symbol specification (e.g., 'Device:R' or 'PCM_JLCPCB-MCUs:STM32F103C8T6')"),
|
||||||
},
|
},
|
||||||
async (args: { symbol: string }) => {
|
async (args: { symbol: string }) => {
|
||||||
const result = await callKicadScript("get_symbol_info", args);
|
const result = await callKicadScript("get_symbol_info", args);
|
||||||
@@ -145,34 +149,36 @@ Returns symbol references that can be used directly in schematics.`,
|
|||||||
const info = result.symbol_info;
|
const info = result.symbol_info;
|
||||||
const details = [
|
const details = [
|
||||||
`Symbol: ${info.full_ref}`,
|
`Symbol: ${info.full_ref}`,
|
||||||
info.value ? `Value: ${info.value}` : '',
|
info.value ? `Value: ${info.value}` : "",
|
||||||
info.description ? `Description: ${info.description}` : '',
|
info.description ? `Description: ${info.description}` : "",
|
||||||
info.lcsc_id ? `LCSC: ${info.lcsc_id}` : '',
|
info.lcsc_id ? `LCSC: ${info.lcsc_id}` : "",
|
||||||
info.manufacturer ? `Manufacturer: ${info.manufacturer}` : '',
|
info.manufacturer ? `Manufacturer: ${info.manufacturer}` : "",
|
||||||
info.mpn ? `MPN: ${info.mpn}` : '',
|
info.mpn ? `MPN: ${info.mpn}` : "",
|
||||||
info.footprint ? `Footprint: ${info.footprint}` : '',
|
info.footprint ? `Footprint: ${info.footprint}` : "",
|
||||||
info.category ? `Category: ${info.category}` : '',
|
info.category ? `Category: ${info.category}` : "",
|
||||||
info.lib_class ? `Class: ${info.lib_class}` : '',
|
info.lib_class ? `Class: ${info.lib_class}` : "",
|
||||||
info.datasheet ? `Datasheet: ${info.datasheet}` : '',
|
info.datasheet ? `Datasheet: ${info.datasheet}` : "",
|
||||||
].filter(line => line).join('\n');
|
]
|
||||||
|
.filter((line) => line)
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: details
|
text: details,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Failed to get symbol info: ${result.message || 'Unknown error'}`
|
text: `Failed to get symbol info: ${result.message || "Unknown error"}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,7 @@
|
|||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export function registerLibraryTools(
|
export function registerLibraryTools(server: McpServer, callKicadScript: Function) {
|
||||||
server: McpServer,
|
|
||||||
callKicadScript: Function,
|
|
||||||
) {
|
|
||||||
// List available footprint libraries
|
// List available footprint libraries
|
||||||
server.tool(
|
server.tool(
|
||||||
"list_libraries",
|
"list_libraries",
|
||||||
@@ -48,18 +45,9 @@ export function registerLibraryTools(
|
|||||||
"search_footprints",
|
"search_footprints",
|
||||||
"Search for footprints matching a pattern across all libraries",
|
"Search for footprints matching a pattern across all libraries",
|
||||||
{
|
{
|
||||||
search_term: z
|
search_term: z.string().describe("Search term or pattern to match footprint names"),
|
||||||
.string()
|
library: z.string().optional().describe("Optional specific library to search in"),
|
||||||
.describe("Search term or pattern to match footprint names"),
|
limit: z.number().optional().default(50).describe("Maximum number of results to return"),
|
||||||
library: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Optional specific library to search in"),
|
|
||||||
limit: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.default(50)
|
|
||||||
.describe("Maximum number of results to return"),
|
|
||||||
},
|
},
|
||||||
async (args: { search_term: string; library?: string; limit?: number }) => {
|
async (args: { search_term: string; library?: string; limit?: number }) => {
|
||||||
const result = await callKicadScript("search_footprints", {
|
const result = await callKicadScript("search_footprints", {
|
||||||
@@ -99,25 +87,14 @@ export function registerLibraryTools(
|
|||||||
"list_library_footprints",
|
"list_library_footprints",
|
||||||
"List all footprints in a specific KiCAD library",
|
"List all footprints in a specific KiCAD library",
|
||||||
{
|
{
|
||||||
library_name: z
|
library_name: z.string().describe("Name of the library to list footprints from"),
|
||||||
.string()
|
filter: z.string().optional().describe("Optional filter pattern for footprint names"),
|
||||||
.describe("Name of the library to list footprints from"),
|
limit: z.number().optional().default(100).describe("Maximum number of footprints to list"),
|
||||||
filter: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Optional filter pattern for footprint names"),
|
|
||||||
limit: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.default(100)
|
|
||||||
.describe("Maximum number of footprints to list"),
|
|
||||||
},
|
},
|
||||||
async (args: { library_name: string; filter?: string; limit?: number }) => {
|
async (args: { library_name: string; filter?: string; limit?: number }) => {
|
||||||
const result = await callKicadScript("list_library_footprints", args);
|
const result = await callKicadScript("list_library_footprints", args);
|
||||||
if (result.success && result.footprints) {
|
if (result.success && result.footprints) {
|
||||||
const footprintList = result.footprints
|
const footprintList = result.footprints.map((fp: string) => ` - ${fp}`).join("\n");
|
||||||
.map((fp: string) => ` - ${fp}`)
|
|
||||||
.join("\n");
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
@@ -143,12 +120,8 @@ export function registerLibraryTools(
|
|||||||
"get_footprint_info",
|
"get_footprint_info",
|
||||||
"Get detailed information about a specific footprint",
|
"Get detailed information about a specific footprint",
|
||||||
{
|
{
|
||||||
library_name: z
|
library_name: z.string().describe("Name of the library containing the footprint"),
|
||||||
.string()
|
footprint_name: z.string().describe("Name of the footprint to get information about"),
|
||||||
.describe("Name of the library containing the footprint"),
|
|
||||||
footprint_name: z
|
|
||||||
.string()
|
|
||||||
.describe("Name of the footprint to get information about"),
|
|
||||||
},
|
},
|
||||||
async (args: { library_name: string; footprint_name: string }) => {
|
async (args: { library_name: string; footprint_name: string }) => {
|
||||||
const result = await callKicadScript("get_footprint_info", args);
|
const result = await callKicadScript("get_footprint_info", args);
|
||||||
@@ -156,15 +129,16 @@ export function registerLibraryTools(
|
|||||||
const info = result.info;
|
const info = result.info;
|
||||||
|
|
||||||
// pads is a list of {number, type, shape} objects
|
// pads is a list of {number, type, shape} objects
|
||||||
const padsArray: Array<{ number: string; type: string; shape: string }> =
|
const padsArray: Array<{ number: string; type: string; shape: string }> = Array.isArray(
|
||||||
Array.isArray(info.pads) ? info.pads : [];
|
info.pads,
|
||||||
|
)
|
||||||
|
? info.pads
|
||||||
|
: [];
|
||||||
const padsSummary = padsArray.length
|
const padsSummary = padsArray.length
|
||||||
? `${padsArray.length} pads: ${padsArray.map((p) => p.number).join(", ")}`
|
? `${padsArray.length} pads: ${padsArray.map((p) => p.number).join(", ")}`
|
||||||
: "";
|
: "";
|
||||||
const padsDetail = padsArray.length
|
const padsDetail = padsArray.length
|
||||||
? padsArray
|
? padsArray.map((p) => ` pad ${p.number}: ${p.type} ${p.shape}`).join("\n")
|
||||||
.map((p) => ` pad ${p.number}: ${p.type} ${p.shape}`)
|
|
||||||
.join("\n")
|
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const details = [
|
const details = [
|
||||||
@@ -178,9 +152,7 @@ export function registerLibraryTools(
|
|||||||
info.courtyard
|
info.courtyard
|
||||||
? `Courtyard size: ${info.courtyard.width}mm x ${info.courtyard.height}mm`
|
? `Courtyard size: ${info.courtyard.width}mm x ${info.courtyard.height}mm`
|
||||||
: "",
|
: "",
|
||||||
info.attributes
|
info.attributes ? `Attributes: ${JSON.stringify(info.attributes)}` : "",
|
||||||
? `Attributes: ${JSON.stringify(info.attributes)}`
|
|
||||||
: "",
|
|
||||||
]
|
]
|
||||||
.filter((line) => line)
|
.filter((line) => line)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
* Project management tools for KiCAD MCP server
|
* Project management tools for KiCAD MCP server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
|
|
||||||
export function registerProjectTools(server: McpServer, callKicadScript: Function) {
|
export function registerProjectTools(server: McpServer, callKicadScript: Function) {
|
||||||
// Create project tool
|
// Create project tool
|
||||||
@@ -17,12 +17,14 @@ export function registerProjectTools(server: McpServer, callKicadScript: Functio
|
|||||||
async (args: { path: string; name: string }) => {
|
async (args: { path: string; name: string }) => {
|
||||||
const result = await callKicadScript("create_project", args);
|
const result = await callKicadScript("create_project", args);
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Open project tool
|
// Open project tool
|
||||||
@@ -35,12 +37,14 @@ export function registerProjectTools(server: McpServer, callKicadScript: Functio
|
|||||||
async (args: { filename: string }) => {
|
async (args: { filename: string }) => {
|
||||||
const result = await callKicadScript("open_project", args);
|
const result = await callKicadScript("open_project", args);
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Save project tool
|
// Save project tool
|
||||||
@@ -53,12 +57,14 @@ export function registerProjectTools(server: McpServer, callKicadScript: Functio
|
|||||||
async (args: { path?: string }) => {
|
async (args: { path?: string }) => {
|
||||||
const result = await callKicadScript("save_project", args);
|
const result = await callKicadScript("save_project", args);
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get project info tool
|
// Get project info tool
|
||||||
@@ -69,12 +75,14 @@ export function registerProjectTools(server: McpServer, callKicadScript: Functio
|
|||||||
async () => {
|
async () => {
|
||||||
const result = await callKicadScript("get_project_info", {});
|
const result = await callKicadScript("get_project_info", {});
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Snapshot project tool — saves a named checkpoint as PDF/image
|
// Snapshot project tool — saves a named checkpoint as PDF/image
|
||||||
@@ -83,17 +91,26 @@ export function registerProjectTools(server: McpServer, callKicadScript: Functio
|
|||||||
"Save a named checkpoint snapshot of the current project state (renders board to PDF and records step label). Call after completing each major step — e.g. after Step 1 (schematic_ok) and Step 2 (layout_ok). Required by the demo workflow before waiting for user confirmation.",
|
"Save a named checkpoint snapshot of the current project state (renders board to PDF and records step label). Call after completing each major step — e.g. after Step 1 (schematic_ok) and Step 2 (layout_ok). Required by the demo workflow before waiting for user confirmation.",
|
||||||
{
|
{
|
||||||
step: z.string().describe("Step number or identifier, e.g. '1' or '2'"),
|
step: z.string().describe("Step number or identifier, e.g. '1' or '2'"),
|
||||||
label: z.string().describe("Short label for this checkpoint, e.g. 'schematic_ok' or 'layout_ok'"),
|
label: z
|
||||||
prompt: z.string().optional().describe("Full prompt text to save as PROMPT_step{step}_{timestamp}.md alongside the snapshot"),
|
.string()
|
||||||
|
.describe("Short label for this checkpoint, e.g. 'schematic_ok' or 'layout_ok'"),
|
||||||
|
prompt: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"Full prompt text to save as PROMPT_step{step}_{timestamp}.md alongside the snapshot",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
async (args: { step: string; label: string; prompt?: string }) => {
|
async (args: { step: string; label: string; prompt?: string }) => {
|
||||||
const result = await callKicadScript("snapshot_project", args);
|
const result = await callKicadScript("snapshot_project", args);
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Centralizes all tool definitions and provides lookup/search functionality
|
* Centralizes all tool definitions and provides lookup/search functionality
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
|
|
||||||
export interface ToolDefinition {
|
export interface ToolDefinition {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -36,8 +36,8 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
"add_zone",
|
"add_zone",
|
||||||
"get_board_extents",
|
"get_board_extents",
|
||||||
"get_board_2d_view",
|
"get_board_2d_view",
|
||||||
"launch_kicad_ui"
|
"launch_kicad_ui",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "component",
|
name: "component",
|
||||||
@@ -50,8 +50,8 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
"get_component_properties",
|
"get_component_properties",
|
||||||
"add_component_annotation",
|
"add_component_annotation",
|
||||||
"group_components",
|
"group_components",
|
||||||
"replace_component"
|
"replace_component",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "export",
|
name: "export",
|
||||||
@@ -64,8 +64,8 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
"export_bom",
|
"export_bom",
|
||||||
"export_netlist",
|
"export_netlist",
|
||||||
"export_position_file",
|
"export_position_file",
|
||||||
"export_vrml"
|
"export_vrml",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "drc",
|
name: "drc",
|
||||||
@@ -78,12 +78,13 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
"assign_net_to_class",
|
"assign_net_to_class",
|
||||||
"set_layer_constraints",
|
"set_layer_constraints",
|
||||||
"check_clearance",
|
"check_clearance",
|
||||||
"get_drc_violations"
|
"get_drc_violations",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "schematic",
|
name: "schematic",
|
||||||
description: "Schematic operations: create, inspect, add/edit/delete components, wire connections, netlists, annotation",
|
description:
|
||||||
|
"Schematic operations: create, inspect, add/edit/delete components, wire connections, netlists, annotation",
|
||||||
tools: [
|
tools: [
|
||||||
"create_schematic",
|
"create_schematic",
|
||||||
"add_schematic_component",
|
"add_schematic_component",
|
||||||
@@ -107,37 +108,24 @@ export const toolCategories: ToolCategory[] = [
|
|||||||
"sync_schematic_to_board",
|
"sync_schematic_to_board",
|
||||||
"get_schematic_view",
|
"get_schematic_view",
|
||||||
"export_schematic_svg",
|
"export_schematic_svg",
|
||||||
"export_schematic_pdf"
|
"export_schematic_pdf",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "library",
|
name: "library",
|
||||||
description: "Footprint library access: search, browse, get footprint information",
|
description: "Footprint library access: search, browse, get footprint information",
|
||||||
tools: [
|
tools: ["list_libraries", "search_footprints", "list_library_footprints", "get_footprint_info"],
|
||||||
"list_libraries",
|
|
||||||
"search_footprints",
|
|
||||||
"list_library_footprints",
|
|
||||||
"get_footprint_info"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "routing",
|
name: "routing",
|
||||||
description: "Advanced routing operations: vias, copper pours",
|
description: "Advanced routing operations: vias, copper pours",
|
||||||
tools: [
|
tools: ["add_via", "add_copper_pour"],
|
||||||
"add_via",
|
|
||||||
"add_copper_pour"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "autoroute",
|
name: "autoroute",
|
||||||
description: "Freerouting autorouter: automatic PCB routing via Specctra DSN/SES",
|
description: "Freerouting autorouter: automatic PCB routing via Specctra DSN/SES",
|
||||||
tools: [
|
tools: ["autoroute", "export_dsn", "import_ses", "check_freerouting"],
|
||||||
"autoroute",
|
},
|
||||||
"export_dsn",
|
|
||||||
"import_ses",
|
|
||||||
"check_freerouting"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,7 +163,7 @@ export const directToolNames = [
|
|||||||
"sync_schematic_to_board",
|
"sync_schematic_to_board",
|
||||||
|
|
||||||
// UI management
|
// UI management
|
||||||
"check_kicad_ui"
|
"check_kicad_ui",
|
||||||
];
|
];
|
||||||
|
|
||||||
// Build lookup maps at module load time
|
// Build lookup maps at module load time
|
||||||
@@ -260,7 +248,7 @@ export function searchTools(query: string): SearchResult[] {
|
|||||||
matches.push({
|
matches.push({
|
||||||
category: "direct",
|
category: "direct",
|
||||||
tool: toolName,
|
tool: toolName,
|
||||||
description: `${toolName} (direct tool — call directly, no execute_tool needed)`
|
description: `${toolName} (direct tool — call directly, no execute_tool needed)`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,15 +256,14 @@ export function searchTools(query: string): SearchResult[] {
|
|||||||
// Search routed tools by name and category
|
// Search routed tools by name and category
|
||||||
for (const category of toolCategories) {
|
for (const category of toolCategories) {
|
||||||
const categoryMatch =
|
const categoryMatch =
|
||||||
category.name.toLowerCase().includes(q) ||
|
category.name.toLowerCase().includes(q) || category.description.toLowerCase().includes(q);
|
||||||
category.description.toLowerCase().includes(q);
|
|
||||||
|
|
||||||
for (const toolName of category.tools) {
|
for (const toolName of category.tools) {
|
||||||
if (toolName.toLowerCase().includes(q) || categoryMatch) {
|
if (toolName.toLowerCase().includes(q) || categoryMatch) {
|
||||||
matches.push({
|
matches.push({
|
||||||
category: category.name,
|
category: category.name,
|
||||||
tool: toolName,
|
tool: toolName,
|
||||||
description: `${toolName} (${category.name})`
|
description: `${toolName} (${category.name})`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,10 +284,10 @@ export function getRegistryStats() {
|
|||||||
total_routed_tools: routedToolCount,
|
total_routed_tools: routedToolCount,
|
||||||
total_direct_tools: directToolCount,
|
total_direct_tools: directToolCount,
|
||||||
total_tools: routedToolCount + directToolCount,
|
total_tools: routedToolCount + directToolCount,
|
||||||
categories: toolCategories.map(c => ({
|
categories: toolCategories.map((c) => ({
|
||||||
name: c.name,
|
name: c.name,
|
||||||
tool_count: c.tools.length
|
tool_count: c.tools.length,
|
||||||
}))
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,16 +4,16 @@
|
|||||||
* Provides discovery and execution of routed tools
|
* Provides discovery and execution of routed tools
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
import {
|
import {
|
||||||
getAllCategories,
|
getAllCategories,
|
||||||
getCategory,
|
getCategory,
|
||||||
getToolCategory,
|
getToolCategory,
|
||||||
searchTools as registrySearchTools,
|
searchTools as registrySearchTools,
|
||||||
getRegistryStats
|
getRegistryStats,
|
||||||
} from './registry.js';
|
} from "./registry.js";
|
||||||
|
|
||||||
// Command function type for KiCAD script calls
|
// Command function type for KiCAD script calls
|
||||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||||
@@ -28,7 +28,7 @@ const toolHandlers = new Map<string, (params: any) => Promise<any>>();
|
|||||||
*/
|
*/
|
||||||
export function registerToolHandler(
|
export function registerToolHandler(
|
||||||
toolName: string,
|
toolName: string,
|
||||||
handler: (params: any) => Promise<any>
|
handler: (params: any) => Promise<any>,
|
||||||
): void {
|
): void {
|
||||||
toolHandlers.set(toolName, handler);
|
toolHandlers.set(toolName, handler);
|
||||||
logger.debug(`Registered handler for routed tool: ${toolName}`);
|
logger.debug(`Registered handler for routed tool: ${toolName}`);
|
||||||
@@ -38,7 +38,7 @@ export function registerToolHandler(
|
|||||||
* Register all router tools with the MCP server
|
* Register all router tools with the MCP server
|
||||||
*/
|
*/
|
||||||
export function registerRouterTools(server: McpServer, callKicadScript: CommandFunction): void {
|
export function registerRouterTools(server: McpServer, callKicadScript: CommandFunction): void {
|
||||||
logger.info('Registering router tools');
|
logger.info("Registering router tools");
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// list_tool_categories
|
// list_tool_categories
|
||||||
@@ -49,7 +49,7 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
// No parameters
|
// No parameters
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
logger.debug('Listing tool categories');
|
logger.debug("Listing tool categories");
|
||||||
|
|
||||||
const stats = getRegistryStats();
|
const stats = getRegistryStats();
|
||||||
const categories = getAllCategories();
|
const categories = getAllCategories();
|
||||||
@@ -59,20 +59,22 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
total_routed_tools: stats.total_routed_tools,
|
total_routed_tools: stats.total_routed_tools,
|
||||||
total_direct_tools: stats.total_direct_tools,
|
total_direct_tools: stats.total_direct_tools,
|
||||||
note: "Use get_category_tools to see tools in each category. Direct tools are always available.",
|
note: "Use get_category_tools to see tools in each category. Direct tools are always available.",
|
||||||
categories: categories.map(c => ({
|
categories: categories.map((c) => ({
|
||||||
name: c.name,
|
name: c.name,
|
||||||
description: c.description,
|
description: c.description,
|
||||||
tool_count: c.tools.length
|
tool_count: c.tools.length,
|
||||||
}))
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -81,7 +83,7 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
server.tool(
|
server.tool(
|
||||||
"get_category_tools",
|
"get_category_tools",
|
||||||
{
|
{
|
||||||
category: z.string().describe("Category name from list_tool_categories")
|
category: z.string().describe("Category name from list_tool_categories"),
|
||||||
},
|
},
|
||||||
async ({ category }) => {
|
async ({ category }) => {
|
||||||
logger.debug(`Getting tools for category: ${category}`);
|
logger.debug(`Getting tools for category: ${category}`);
|
||||||
@@ -89,15 +91,21 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
const categoryData = getCategory(category);
|
const categoryData = getCategory(category);
|
||||||
|
|
||||||
if (!categoryData) {
|
if (!categoryData) {
|
||||||
const availableCategories = getAllCategories().map(c => c.name);
|
const availableCategories = getAllCategories().map((c) => c.name);
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify(
|
||||||
|
{
|
||||||
error: `Unknown category: ${category}`,
|
error: `Unknown category: ${category}`,
|
||||||
available_categories: availableCategories
|
available_categories: availableCategories,
|
||||||
}, null, 2)
|
},
|
||||||
}]
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,20 +115,22 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
category: categoryData.name,
|
category: categoryData.name,
|
||||||
description: categoryData.description,
|
description: categoryData.description,
|
||||||
tool_count: categoryData.tools.length,
|
tool_count: categoryData.tools.length,
|
||||||
tools: categoryData.tools.map(toolName => ({
|
tools: categoryData.tools.map((toolName) => ({
|
||||||
name: toolName,
|
name: toolName,
|
||||||
description: `Use execute_tool with tool_name="${toolName}" to run this tool`
|
description: `Use execute_tool with tool_name="${toolName}" to run this tool`,
|
||||||
})),
|
})),
|
||||||
note: "Use execute_tool to run any of these tools with appropriate parameters"
|
note: "Use execute_tool to run any of these tools with appropriate parameters",
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -130,7 +140,7 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
"execute_tool",
|
"execute_tool",
|
||||||
{
|
{
|
||||||
tool_name: z.string().describe("Tool name from get_category_tools"),
|
tool_name: z.string().describe("Tool name from get_category_tools"),
|
||||||
params: z.record(z.unknown()).optional().describe("Tool parameters (optional)")
|
params: z.record(z.unknown()).optional().describe("Tool parameters (optional)"),
|
||||||
},
|
},
|
||||||
async ({ tool_name, params }) => {
|
async ({ tool_name, params }) => {
|
||||||
logger.info(`Executing routed tool: ${tool_name}`);
|
logger.info(`Executing routed tool: ${tool_name}`);
|
||||||
@@ -140,13 +150,19 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
|
|
||||||
if (!category) {
|
if (!category) {
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify(
|
||||||
|
{
|
||||||
error: `Unknown tool: ${tool_name}`,
|
error: `Unknown tool: ${tool_name}`,
|
||||||
hint: "Use list_tool_categories and get_category_tools to find available tools"
|
hint: "Use list_tool_categories and get_category_tools to find available tools",
|
||||||
}, null, 2)
|
},
|
||||||
}]
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,30 +173,44 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
// Tool is in registry but handler not registered yet
|
// Tool is in registry but handler not registered yet
|
||||||
// This means the tool exists but hasn't been migrated to router pattern yet
|
// This means the tool exists but hasn't been migrated to router pattern yet
|
||||||
// Fall back to calling KiCAD script directly
|
// Fall back to calling KiCAD script directly
|
||||||
logger.warn(`Tool ${tool_name} in registry but no handler registered, falling back to direct call`);
|
logger.warn(
|
||||||
|
`Tool ${tool_name} in registry but no handler registered, falling back to direct call`,
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await callKicadScript(tool_name, params || {});
|
const result = await callKicadScript(tool_name, params || {});
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify(
|
||||||
|
{
|
||||||
tool: tool_name,
|
tool: tool_name,
|
||||||
category: category,
|
category: category,
|
||||||
result: result
|
result: result,
|
||||||
}, null, 2)
|
},
|
||||||
}]
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify(
|
||||||
|
{
|
||||||
error: `Tool execution failed: ${(error as Error).message}`,
|
error: `Tool execution failed: ${(error as Error).message}`,
|
||||||
tool: tool_name,
|
tool: tool_name,
|
||||||
category: category
|
category: category,
|
||||||
}, null, 2)
|
},
|
||||||
}]
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,28 +222,40 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
// The handler already returns MCP-formatted response
|
// The handler already returns MCP-formatted response
|
||||||
// Just add metadata
|
// Just add metadata
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify(
|
||||||
|
{
|
||||||
tool: tool_name,
|
tool: tool_name,
|
||||||
category: category,
|
category: category,
|
||||||
...result
|
...result,
|
||||||
}, null, 2)
|
},
|
||||||
}]
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify(
|
||||||
|
{
|
||||||
error: `Tool execution failed: ${(error as Error).message}`,
|
error: `Tool execution failed: ${(error as Error).message}`,
|
||||||
tool: tool_name,
|
tool: tool_name,
|
||||||
category: category
|
category: category,
|
||||||
}, null, 2)
|
},
|
||||||
}]
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -222,7 +264,7 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
server.tool(
|
server.tool(
|
||||||
"search_tools",
|
"search_tools",
|
||||||
{
|
{
|
||||||
query: z.string().describe("Search term (e.g., 'gerber', 'zone', 'export', 'drc')")
|
query: z.string().describe("Search term (e.g., 'gerber', 'zone', 'export', 'drc')"),
|
||||||
},
|
},
|
||||||
async ({ query }) => {
|
async ({ query }) => {
|
||||||
logger.debug(`Searching tools for: ${query}`);
|
logger.debug(`Searching tools for: ${query}`);
|
||||||
@@ -233,19 +275,22 @@ export function registerRouterTools(server: McpServer, callKicadScript: CommandF
|
|||||||
query: query,
|
query: query,
|
||||||
count: matches.length,
|
count: matches.length,
|
||||||
matches: matches,
|
matches: matches,
|
||||||
note: matches.length > 0
|
note:
|
||||||
|
matches.length > 0
|
||||||
? "Use execute_tool with the tool name to run it"
|
? "Use execute_tool with the tool name to run it"
|
||||||
: "No tools found matching your query. Try list_tool_categories to browse all categories."
|
: "No tools found matching your query. Try list_tool_categories to browse all categories.",
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Router tools registered successfully');
|
logger.info("Router tools registered successfully");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,7 @@
|
|||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export function registerRoutingTools(
|
export function registerRoutingTools(server: McpServer, callKicadScript: Function) {
|
||||||
server: McpServer,
|
|
||||||
callKicadScript: Function,
|
|
||||||
) {
|
|
||||||
// Add net tool
|
// Add net tool
|
||||||
server.tool(
|
server.tool(
|
||||||
"add_net",
|
"add_net",
|
||||||
@@ -79,10 +76,7 @@ export function registerRoutingTools(
|
|||||||
})
|
})
|
||||||
.describe("Via position"),
|
.describe("Via position"),
|
||||||
net: z.string().describe("Net name"),
|
net: z.string().describe("Net name"),
|
||||||
viaType: z
|
viaType: z.string().optional().describe("Via type (through, blind, buried)"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Via type (through, blind, buried)"),
|
|
||||||
},
|
},
|
||||||
async (args: any) => {
|
async (args: any) => {
|
||||||
const result = await callKicadScript("add_via", args);
|
const result = await callKicadScript("add_via", args);
|
||||||
@@ -130,10 +124,7 @@ export function registerRoutingTools(
|
|||||||
"delete_trace",
|
"delete_trace",
|
||||||
"Delete traces from the PCB. Can delete by UUID, position, or bulk-delete all traces on a net.",
|
"Delete traces from the PCB. Can delete by UUID, position, or bulk-delete all traces on a net.",
|
||||||
{
|
{
|
||||||
traceUuid: z
|
traceUuid: z.string().optional().describe("UUID of a specific trace to delete"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("UUID of a specific trace to delete"),
|
|
||||||
position: z
|
position: z
|
||||||
.object({
|
.object({
|
||||||
x: z.number(),
|
x: z.number(),
|
||||||
@@ -142,18 +133,9 @@ export function registerRoutingTools(
|
|||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Delete trace nearest to this position"),
|
.describe("Delete trace nearest to this position"),
|
||||||
net: z
|
net: z.string().optional().describe("Delete all traces on this net (bulk delete)"),
|
||||||
.string()
|
layer: z.string().optional().describe("Filter by layer when using net-based deletion"),
|
||||||
.optional()
|
includeVias: z.boolean().optional().describe("Include vias in net-based deletion"),
|
||||||
.describe("Delete all traces on this net (bulk delete)"),
|
|
||||||
layer: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Filter by layer when using net-based deletion"),
|
|
||||||
includeVias: z
|
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.describe("Include vias in net-based deletion"),
|
|
||||||
},
|
},
|
||||||
async (args: any) => {
|
async (args: any) => {
|
||||||
const result = await callKicadScript("delete_trace", args);
|
const result = await callKicadScript("delete_trace", args);
|
||||||
@@ -209,10 +191,7 @@ export function registerRoutingTools(
|
|||||||
.boolean()
|
.boolean()
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Include statistics (track count, total length, etc.)"),
|
.describe("Include statistics (track count, total length, etc.)"),
|
||||||
unit: z
|
unit: z.enum(["mm", "inch"]).optional().describe("Unit for length measurements"),
|
||||||
.enum(["mm", "inch"])
|
|
||||||
.optional()
|
|
||||||
.describe("Unit for length measurements"),
|
|
||||||
},
|
},
|
||||||
async (args: any) => {
|
async (args: any) => {
|
||||||
const result = await callKicadScript("get_nets_list", args);
|
const result = await callKicadScript("get_nets_list", args);
|
||||||
@@ -334,9 +313,13 @@ export function registerRoutingTools(
|
|||||||
"PREFERRED tool for pad-to-pad routing. Looks up pad positions automatically, detects the net from the pad, and — critically — if the two pads are on different copper layers (e.g. J1 on F.Cu and J2 on B.Cu) automatically inserts a via at the midpoint so the connection is complete. Always use this instead of route_trace when routing between named component pads.",
|
"PREFERRED tool for pad-to-pad routing. Looks up pad positions automatically, detects the net from the pad, and — critically — if the two pads are on different copper layers (e.g. J1 on F.Cu and J2 on B.Cu) automatically inserts a via at the midpoint so the connection is complete. Always use this instead of route_trace when routing between named component pads.",
|
||||||
{
|
{
|
||||||
fromRef: z.string().describe("Reference of the source component (e.g. 'U2')"),
|
fromRef: z.string().describe("Reference of the source component (e.g. 'U2')"),
|
||||||
fromPad: z.union([z.string(), z.number()]).describe("Pad number on the source component (e.g. '6' or 6)"),
|
fromPad: z
|
||||||
|
.union([z.string(), z.number()])
|
||||||
|
.describe("Pad number on the source component (e.g. '6' or 6)"),
|
||||||
toRef: z.string().describe("Reference of the target component (e.g. 'U1')"),
|
toRef: z.string().describe("Reference of the target component (e.g. 'U1')"),
|
||||||
toPad: z.union([z.string(), z.number()]).describe("Pad number on the target component (e.g. '15' or 15)"),
|
toPad: z
|
||||||
|
.union([z.string(), z.number()])
|
||||||
|
.describe("Pad number on the target component (e.g. '15' or 15)"),
|
||||||
layer: z.string().optional().describe("PCB layer (default: F.Cu)"),
|
layer: z.string().optional().describe("PCB layer (default: F.Cu)"),
|
||||||
width: z.number().optional().describe("Trace width in mm (default: board default)"),
|
width: z.number().optional().describe("Trace width in mm (default: board default)"),
|
||||||
net: z.string().optional().describe("Net name override (default: auto-detected from pad)"),
|
net: z.string().optional().describe("Net name override (default: auto-detected from pad)"),
|
||||||
@@ -362,10 +345,7 @@ export function registerRoutingTools(
|
|||||||
.describe(
|
.describe(
|
||||||
"References of the target components in same order as sourceRefs (e.g. ['U2', 'R2', 'C2'])",
|
"References of the target components in same order as sourceRefs (e.g. ['U2', 'R2', 'C2'])",
|
||||||
),
|
),
|
||||||
includeVias: z
|
includeVias: z.boolean().optional().describe("Also copy vias (default: true)"),
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.describe("Also copy vias (default: true)"),
|
|
||||||
traceWidth: z
|
traceWidth: z
|
||||||
.number()
|
.number()
|
||||||
.optional()
|
.optional()
|
||||||
|
|||||||
@@ -5,10 +5,7 @@
|
|||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export function registerSchematicTools(
|
export function registerSchematicTools(server: McpServer, callKicadScript: Function) {
|
||||||
server: McpServer,
|
|
||||||
callKicadScript: Function,
|
|
||||||
) {
|
|
||||||
// Create schematic tool
|
// Create schematic tool
|
||||||
server.tool(
|
server.tool(
|
||||||
"create_schematic",
|
"create_schematic",
|
||||||
@@ -38,9 +35,7 @@ export function registerSchematicTools(
|
|||||||
schematicPath: z.string().describe("Path to the schematic file"),
|
schematicPath: z.string().describe("Path to the schematic file"),
|
||||||
symbol: z
|
symbol: z
|
||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe("Symbol library:name reference (e.g., Device:R, EDA-MCP:ESP32-C3)"),
|
||||||
"Symbol library:name reference (e.g., Device:R, EDA-MCP:ESP32-C3)",
|
|
||||||
),
|
|
||||||
reference: z.string().describe("Component reference (e.g., R1, U1)"),
|
reference: z.string().describe("Component reference (e.g., R1, U1)"),
|
||||||
value: z.string().optional().describe("Component value"),
|
value: z.string().optional().describe("Component value"),
|
||||||
footprint: z
|
footprint: z
|
||||||
@@ -82,10 +77,7 @@ export function registerSchematicTools(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await callKicadScript(
|
const result = await callKicadScript("add_schematic_component", transformed);
|
||||||
"add_schematic_component",
|
|
||||||
transformed,
|
|
||||||
);
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
@@ -122,9 +114,7 @@ To remove a footprint from a PCB, use delete_component instead.`,
|
|||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
reference: z
|
reference: z
|
||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe("Reference designator of the component to remove (e.g. R1, U3)"),
|
||||||
"Reference designator of the component to remove (e.g. R1, U3)",
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string; reference: string }) => {
|
async (args: { schematicPath: string; reference: string }) => {
|
||||||
const result = await callKicadScript("delete_schematic_component", args);
|
const result = await callKicadScript("delete_schematic_component", args);
|
||||||
@@ -162,14 +152,27 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
reference: z.string().describe("Current reference designator of the component (e.g. R1, U3)"),
|
reference: z.string().describe("Current reference designator of the component (e.g. R1, U3)"),
|
||||||
footprint: z.string().optional().describe("New KiCAD footprint string (e.g. Resistor_SMD:R_0603_1608Metric)"),
|
footprint: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("New KiCAD footprint string (e.g. Resistor_SMD:R_0603_1608Metric)"),
|
||||||
value: z.string().optional().describe("New value string (e.g. 10k, 100nF)"),
|
value: z.string().optional().describe("New value string (e.g. 10k, 100nF)"),
|
||||||
newReference: z.string().optional().describe("Rename the reference designator (e.g. R1 → R10)"),
|
newReference: z
|
||||||
fieldPositions: z.record(z.object({
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Rename the reference designator (e.g. R1 → R10)"),
|
||||||
|
fieldPositions: z
|
||||||
|
.record(
|
||||||
|
z.object({
|
||||||
x: z.number(),
|
x: z.number(),
|
||||||
y: z.number(),
|
y: z.number(),
|
||||||
angle: z.number().optional().default(0),
|
angle: z.number().optional().default(0),
|
||||||
})).optional().describe("Reposition field labels: map of field name to {x, y, angle} (e.g. {\"Reference\": {\"x\": 12.5, \"y\": 17.0}})"),
|
}),
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
'Reposition field labels: map of field name to {x, y, angle} (e.g. {"Reference": {"x": 12.5, "y": 17.0}})',
|
||||||
|
),
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
@@ -220,20 +223,24 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
: "unknown";
|
: "unknown";
|
||||||
const fieldLines = Object.entries(result.fields ?? {}).map(
|
const fieldLines = Object.entries(result.fields ?? {}).map(
|
||||||
([name, f]: [string, any]) =>
|
([name, f]: [string, any]) =>
|
||||||
` ${name}: "${f.value}" @ (${f.x}, ${f.y}, angle=${f.angle}°)`
|
` ${name}: "${f.value}" @ (${f.x}, ${f.y}, angle=${f.angle}°)`,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Component ${result.reference} at ${pos}\nFields:\n${fieldLines.join("\n")}`,
|
text: `Component ${result.reference} at ${pos}\nFields:\n${fieldLines.join("\n")}`,
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Failed to get component: ${result.message || "Unknown error"}`,
|
text: `Failed to get component: ${result.message || "Unknown error"}`,
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -251,13 +258,8 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
snapToPins: z
|
snapToPins: z
|
||||||
.boolean()
|
.boolean()
|
||||||
.optional()
|
.optional()
|
||||||
.describe(
|
.describe("Snap the first and last waypoints to the nearest pin (default: true)"),
|
||||||
"Snap the first and last waypoints to the nearest pin (default: true)",
|
snapTolerance: z.number().optional().describe("Maximum snap distance in mm (default: 1.0)"),
|
||||||
),
|
|
||||||
snapTolerance: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Maximum snap distance in mm (default: 1.0)"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
@@ -294,10 +296,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"Place a junction dot at a wire intersection in the schematic. Required at T-branch and X-cross points so KiCAD recognises the electrical connection.",
|
"Place a junction dot at a wire intersection in the schematic. Required at T-branch and X-cross points so KiCAD recognises the electrical connection.",
|
||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
position: z
|
position: z.array(z.number()).length(2).describe("Junction position [x, y] in mm"),
|
||||||
.array(z.number())
|
|
||||||
.length(2)
|
|
||||||
.describe("Junction position [x, y] in mm"),
|
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string; position: number[] }) => {
|
async (args: { schematicPath: string; position: number[] }) => {
|
||||||
const result = await callKicadScript("add_schematic_junction", args);
|
const result = await callKicadScript("add_schematic_junction", args);
|
||||||
@@ -329,19 +328,10 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"Add a net label to the schematic",
|
"Add a net label to the schematic",
|
||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the schematic file"),
|
schematicPath: z.string().describe("Path to the schematic file"),
|
||||||
netName: z
|
netName: z.string().describe("Name of the net (e.g., VCC, GND, SIGNAL_1)"),
|
||||||
.string()
|
position: z.array(z.number()).length(2).describe("Position [x, y] for the label"),
|
||||||
.describe("Name of the net (e.g., VCC, GND, SIGNAL_1)"),
|
|
||||||
position: z
|
|
||||||
.array(z.number())
|
|
||||||
.length(2)
|
|
||||||
.describe("Position [x, y] for the label"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: { schematicPath: string; netName: string; position: number[] }) => {
|
||||||
schematicPath: string;
|
|
||||||
netName: string;
|
|
||||||
position: number[];
|
|
||||||
}) => {
|
|
||||||
const result = await callKicadScript("add_schematic_net_label", args);
|
const result = await callKicadScript("add_schematic_net_label", args);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
return {
|
return {
|
||||||
@@ -451,9 +441,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
async (args: { schematicPath: string; x: number; y: number }) => {
|
async (args: { schematicPath: string; x: number; y: number }) => {
|
||||||
const result = await callKicadScript("get_wire_connections", args);
|
const result = await callKicadScript("get_wire_connections", args);
|
||||||
if (result.success && result.pins) {
|
if (result.success && result.pins) {
|
||||||
const pinList = result.pins
|
const pinList = result.pins.map((p: any) => ` - ${p.component}/${p.pin}`).join("\n");
|
||||||
.map((p: any) => ` - ${p.component}/${p.pin}`)
|
|
||||||
.join("\n");
|
|
||||||
const wireList = (result.wires ?? [])
|
const wireList = (result.wires ?? [])
|
||||||
.map((w: any) => ` - (${w.start.x},${w.start.y}) → (${w.end.x},${w.end.y})`)
|
.map((w: any) => ` - (${w.start.x},${w.start.y}) → (${w.end.x},${w.end.y})`)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
@@ -484,9 +472,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"Returns the exact x/y coordinates of every pin on a schematic component. Use this before add_schematic_net_label to place labels correctly on pin endpoints.",
|
"Returns the exact x/y coordinates of every pin on a schematic component. Use this before add_schematic_net_label to place labels correctly on pin endpoints.",
|
||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the schematic file"),
|
schematicPath: z.string().describe("Path to the schematic file"),
|
||||||
reference: z
|
reference: z.string().describe("Component reference designator (e.g. U1, R1, J2)"),
|
||||||
.string()
|
|
||||||
.describe("Component reference designator (e.g. U1, R1, J2)"),
|
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string; reference: string }) => {
|
async (args: { schematicPath: string; reference: string }) => {
|
||||||
const result = await callKicadScript("get_schematic_pin_locations", args);
|
const result = await callKicadScript("get_schematic_pin_locations", args);
|
||||||
@@ -541,23 +527,16 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
pinOffset?: number;
|
pinOffset?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const result = await callKicadScript("connect_passthrough", args);
|
const result = await callKicadScript("connect_passthrough", args);
|
||||||
if (
|
if (result.success !== false || (result.connected && result.connected.length > 0)) {
|
||||||
result.success !== false ||
|
|
||||||
(result.connected && result.connected.length > 0)
|
|
||||||
) {
|
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
if (result.connected?.length)
|
if (result.connected?.length)
|
||||||
lines.push(
|
lines.push(
|
||||||
`Connected (${result.connected.length}): ${result.connected.slice(0, 5).join(", ")}${result.connected.length > 5 ? " ..." : ""}`,
|
`Connected (${result.connected.length}): ${result.connected.slice(0, 5).join(", ")}${result.connected.length > 5 ? " ..." : ""}`,
|
||||||
);
|
);
|
||||||
if (result.failed?.length)
|
if (result.failed?.length)
|
||||||
lines.push(
|
lines.push(`Failed (${result.failed.length}): ${result.failed.join(", ")}`);
|
||||||
`Failed (${result.failed.length}): ${result.failed.join(", ")}`,
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{ type: "text", text: result.message + "\n" + lines.join("\n") }],
|
||||||
{ type: "text", text: result.message + "\n" + lines.join("\n") },
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@@ -581,7 +560,10 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
filter: z
|
filter: z
|
||||||
.object({
|
.object({
|
||||||
libId: z.string().optional().describe("Filter by library ID (e.g., 'Device:R')"),
|
libId: z.string().optional().describe("Filter by library ID (e.g., 'Device:R')"),
|
||||||
referencePrefix: z.string().optional().describe("Filter by reference prefix (e.g., 'R', 'C', 'U')"),
|
referencePrefix: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter by reference prefix (e.g., 'R', 'C', 'U')"),
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Optional filters"),
|
.describe("Optional filters"),
|
||||||
@@ -640,9 +622,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const lines = nets.map((n: any) => {
|
const lines = nets.map((n: any) => {
|
||||||
const conns = (n.connections || [])
|
const conns = (n.connections || []).map((c: any) => `${c.component}/${c.pin}`).join(", ");
|
||||||
.map((c: any) => `${c.component}/${c.pin}`)
|
|
||||||
.join(", ");
|
|
||||||
return ` ${n.name}: ${conns || "(no connections)"}`;
|
return ` ${n.name}: ${conns || "(no connections)"}`;
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
@@ -680,8 +660,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const lines = wires.map(
|
const lines = wires.map(
|
||||||
(w: any) =>
|
(w: any) => ` (${w.start.x}, ${w.start.y}) → (${w.end.x}, ${w.end.y})`,
|
||||||
` (${w.start.x}, ${w.start.y}) → (${w.end.x}, ${w.end.y})`,
|
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
@@ -718,8 +697,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const lines = labels.map(
|
const lines = labels.map(
|
||||||
(l: any) =>
|
(l: any) => ` [${l.type}] ${l.name} at (${l.position.x}, ${l.position.y})`,
|
||||||
` [${l.type}] ${l.name} at (${l.position.x}, ${l.position.y})`,
|
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
@@ -789,10 +767,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
reference: z.string().describe("Reference designator (e.g., R1, U1)"),
|
reference: z.string().describe("Reference designator (e.g., R1, U1)"),
|
||||||
angle: z.number().describe("Rotation angle in degrees (0, 90, 180, 270)"),
|
angle: z.number().describe("Rotation angle in degrees (0, 90, 180, 270)"),
|
||||||
mirror: z
|
mirror: z.enum(["x", "y"]).optional().describe("Optional mirror axis"),
|
||||||
.enum(["x", "y"])
|
|
||||||
.optional()
|
|
||||||
.describe("Optional mirror axis"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
@@ -836,14 +811,10 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
const annotated = result.annotated || [];
|
const annotated = result.annotated || [];
|
||||||
if (annotated.length === 0) {
|
if (annotated.length === 0) {
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{ type: "text", text: "All components are already annotated." }],
|
||||||
{ type: "text", text: "All components are already annotated." },
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const lines = annotated.map(
|
const lines = annotated.map((a: any) => ` ${a.oldReference} → ${a.newReference}`);
|
||||||
(a: any) => ` ${a.oldReference} → ${a.newReference}`,
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
@@ -871,12 +842,8 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"Remove a wire from the schematic by start and end coordinates.",
|
"Remove a wire from the schematic by start and end coordinates.",
|
||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
start: z
|
start: z.object({ x: z.number(), y: z.number() }).describe("Wire start position"),
|
||||||
.object({ x: z.number(), y: z.number() })
|
end: z.object({ x: z.number(), y: z.number() }).describe("Wire end position"),
|
||||||
.describe("Wire start position"),
|
|
||||||
end: z
|
|
||||||
.object({ x: z.number(), y: z.number() })
|
|
||||||
.describe("Wire end position"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
@@ -953,16 +920,9 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
outputPath: z.string().describe("Output SVG file path"),
|
outputPath: z.string().describe("Output SVG file path"),
|
||||||
blackAndWhite: z
|
blackAndWhite: z.boolean().optional().describe("Export in black and white"),
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.describe("Export in black and white"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: { schematicPath: string; outputPath: string; blackAndWhite?: boolean }) => {
|
||||||
schematicPath: string;
|
|
||||||
outputPath: string;
|
|
||||||
blackAndWhite?: boolean;
|
|
||||||
}) => {
|
|
||||||
const result = await callKicadScript("export_schematic_svg", args);
|
const result = await callKicadScript("export_schematic_svg", args);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
return {
|
return {
|
||||||
@@ -993,16 +953,9 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
outputPath: z.string().describe("Output PDF file path"),
|
outputPath: z.string().describe("Output PDF file path"),
|
||||||
blackAndWhite: z
|
blackAndWhite: z.boolean().optional().describe("Export in black and white"),
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.describe("Export in black and white"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: { schematicPath: string; outputPath: string; blackAndWhite?: boolean }) => {
|
||||||
schematicPath: string;
|
|
||||||
outputPath: string;
|
|
||||||
blackAndWhite?: boolean;
|
|
||||||
}) => {
|
|
||||||
const result = await callKicadScript("export_schematic_pdf", args);
|
const result = await callKicadScript("export_schematic_pdf", args);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
return {
|
return {
|
||||||
@@ -1032,10 +985,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"Return a rasterized image of the schematic (PNG by default, or SVG). Uses kicad-cli to export SVG, then converts to PNG via cairosvg. Use this for visual feedback after placing or wiring components.",
|
"Return a rasterized image of the schematic (PNG by default, or SVG). Uses kicad-cli to export SVG, then converts to PNG via cairosvg. Use this for visual feedback after placing or wiring components.",
|
||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
format: z
|
format: z.enum(["png", "svg"]).optional().describe("Output format (default: png)"),
|
||||||
.enum(["png", "svg"])
|
|
||||||
.optional()
|
|
||||||
.describe("Output format (default: png)"),
|
|
||||||
width: z.number().optional().describe("Image width in pixels (default: 1200)"),
|
width: z.number().optional().describe("Image width in pixels (default: 1200)"),
|
||||||
height: z.number().optional().describe("Image height in pixels (default: 900)"),
|
height: z.number().optional().describe("Image height in pixels (default: 900)"),
|
||||||
},
|
},
|
||||||
@@ -1086,17 +1036,13 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"run_erc",
|
"run_erc",
|
||||||
"Runs the KiCAD Electrical Rules Check (ERC) on a schematic and returns all violations. Use after wiring to verify the schematic before generating a netlist.",
|
"Runs the KiCAD Electrical Rules Check (ERC) on a schematic and returns all violations. Use after wiring to verify the schematic before generating a netlist.",
|
||||||
{
|
{
|
||||||
schematicPath: z
|
schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
|
||||||
.string()
|
|
||||||
.describe("Path to the .kicad_sch schematic file"),
|
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string }) => {
|
async (args: { schematicPath: string }) => {
|
||||||
const result = await callKicadScript("run_erc", args);
|
const result = await callKicadScript("run_erc", args);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const violations: any[] = result.violations || [];
|
const violations: any[] = result.violations || [];
|
||||||
const lines: string[] = [
|
const lines: string[] = [`ERC result: ${violations.length} violation(s)`];
|
||||||
`ERC result: ${violations.length} violation(s)`,
|
|
||||||
];
|
|
||||||
if (result.summary?.by_severity) {
|
if (result.summary?.by_severity) {
|
||||||
const s = result.summary.by_severity;
|
const s = result.summary.by_severity;
|
||||||
lines.push(
|
lines.push(
|
||||||
@@ -1183,12 +1129,8 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"sync_schematic_to_board",
|
"sync_schematic_to_board",
|
||||||
"Import the schematic netlist into the PCB board — equivalent to pressing F8 in KiCAD (Tools → Update PCB from Schematic). MUST be called after the schematic is complete and before placing or routing components on the PCB. Without this step, the board has no footprints and no net assignments — place_component and route_pad_to_pad will produce an empty, unroutable board.",
|
"Import the schematic netlist into the PCB board — equivalent to pressing F8 in KiCAD (Tools → Update PCB from Schematic). MUST be called after the schematic is complete and before placing or routing components on the PCB. Without this step, the board has no footprints and no net assignments — place_component and route_pad_to_pad will produce an empty, unroutable board.",
|
||||||
{
|
{
|
||||||
schematicPath: z
|
schematicPath: z.string().describe("Absolute path to the .kicad_sch schematic file"),
|
||||||
.string()
|
boardPath: z.string().describe("Absolute path to the .kicad_pcb board file"),
|
||||||
.describe("Absolute path to the .kicad_sch schematic file"),
|
|
||||||
boardPath: z
|
|
||||||
.string()
|
|
||||||
.describe("Absolute path to the .kicad_pcb board file"),
|
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string; boardPath: string }) => {
|
async (args: { schematicPath: string; boardPath: string }) => {
|
||||||
const result = await callKicadScript("sync_schematic_to_board", args);
|
const result = await callKicadScript("sync_schematic_to_board", args);
|
||||||
@@ -1218,8 +1160,13 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
x1: number; y1: number; x2: number; y2: number;
|
x1: number;
|
||||||
format?: string; width?: number; height?: number;
|
y1: number;
|
||||||
|
x2: number;
|
||||||
|
y2: number;
|
||||||
|
format?: string;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const result = await callKicadScript("get_schematic_view_region", args);
|
const result = await callKicadScript("get_schematic_view_region", args);
|
||||||
if (result.success && result.imageData) {
|
if (result.success && result.imageData) {
|
||||||
@@ -1227,11 +1174,13 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
return { content: [{ type: "text", text: result.imageData }] };
|
return { content: [{ type: "text", text: result.imageData }] };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "image",
|
type: "image",
|
||||||
data: result.imageData,
|
data: result.imageData,
|
||||||
mimeType: "image/png",
|
mimeType: "image/png",
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -1240,14 +1189,18 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Find overlapping elements
|
// Find overlapping elements
|
||||||
server.tool(
|
server.tool(
|
||||||
"find_overlapping_elements",
|
"find_overlapping_elements",
|
||||||
"Detect spatially overlapping symbols, wires, and labels in the schematic. Finds duplicate power symbols at the same position, collinear overlapping wires, and labels stacked on top of each other.",
|
"Detect spatially overlapping symbols, wires, and labels in the schematic. Finds duplicate power symbols at the same position, collinear overlapping wires, and labels stacked on top of each other.",
|
||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
|
||||||
tolerance: z.number().optional().describe("Distance threshold in mm for label proximity and wire collinearity checks. Symbol overlap uses bounding-box intersection. (default: 0.5)"),
|
tolerance: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"Distance threshold in mm for label proximity and wire collinearity checks. Symbol overlap uses bounding-box intersection. (default: 0.5)",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string; tolerance?: number }) => {
|
async (args: { schematicPath: string; tolerance?: number }) => {
|
||||||
const result = await callKicadScript("find_overlapping_elements", args);
|
const result = await callKicadScript("find_overlapping_elements", args);
|
||||||
@@ -1259,7 +1212,9 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
if (syms.length) {
|
if (syms.length) {
|
||||||
lines.push(`\nOverlapping symbols (${syms.length}):`);
|
lines.push(`\nOverlapping symbols (${syms.length}):`);
|
||||||
syms.slice(0, 20).forEach((o: any) => {
|
syms.slice(0, 20).forEach((o: any) => {
|
||||||
lines.push(` ${o.element1.reference} ↔ ${o.element2.reference} (${o.distance}mm) [${o.type}]`);
|
lines.push(
|
||||||
|
` ${o.element1.reference} ↔ ${o.element2.reference} (${o.distance}mm) [${o.type}]`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (lbls.length) {
|
if (lbls.length) {
|
||||||
@@ -1271,7 +1226,9 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
if (wires.length) {
|
if (wires.length) {
|
||||||
lines.push(`\nOverlapping wires (${wires.length}):`);
|
lines.push(`\nOverlapping wires (${wires.length}):`);
|
||||||
wires.slice(0, 20).forEach((o: any) => {
|
wires.slice(0, 20).forEach((o: any) => {
|
||||||
lines.push(` wire @ (${o.wire1.start.x},${o.wire1.start.y})→(${o.wire1.end.x},${o.wire1.end.y}) overlaps with another`);
|
lines.push(
|
||||||
|
` wire @ (${o.wire1.start.x},${o.wire1.start.y})→(${o.wire1.end.x},${o.wire1.end.y}) overlaps with another`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { content: [{ type: "text", text: lines.join("\n") }] };
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
||||||
@@ -1293,20 +1250,21 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
x2: z.number().describe("Right X coordinate of the region in mm"),
|
x2: z.number().describe("Right X coordinate of the region in mm"),
|
||||||
y2: z.number().describe("Bottom Y coordinate of the region in mm"),
|
y2: z.number().describe("Bottom Y coordinate of the region in mm"),
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: { schematicPath: string; x1: number; y1: number; x2: number; y2: number }) => {
|
||||||
schematicPath: string;
|
|
||||||
x1: number; y1: number; x2: number; y2: number;
|
|
||||||
}) => {
|
|
||||||
const result = await callKicadScript("get_elements_in_region", args);
|
const result = await callKicadScript("get_elements_in_region", args);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const c = result.counts;
|
const c = result.counts;
|
||||||
const lines = [`Region (${args.x1},${args.y1})→(${args.x2},${args.y2}): ${c.symbols} symbols, ${c.wires} wires, ${c.labels} labels`];
|
const lines = [
|
||||||
|
`Region (${args.x1},${args.y1})→(${args.x2},${args.y2}): ${c.symbols} symbols, ${c.wires} wires, ${c.labels} labels`,
|
||||||
|
];
|
||||||
const syms: any[] = result.symbols || [];
|
const syms: any[] = result.symbols || [];
|
||||||
if (syms.length) {
|
if (syms.length) {
|
||||||
lines.push("\nSymbols:");
|
lines.push("\nSymbols:");
|
||||||
syms.forEach((s: any) => {
|
syms.forEach((s: any) => {
|
||||||
const pinCount = s.pins ? Object.keys(s.pins).length : 0;
|
const pinCount = s.pins ? Object.keys(s.pins).length : 0;
|
||||||
lines.push(` ${s.reference} (${s.libId}) @ (${s.position.x}, ${s.position.y}) [${pinCount} pins]`);
|
lines.push(
|
||||||
|
` ${s.reference} (${s.libId}) @ (${s.position.x}, ${s.position.y}) [${pinCount} pins]`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const wires: any[] = result.wires || [];
|
const wires: any[] = result.wires || [];
|
||||||
@@ -1346,7 +1304,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
const lines = [`Found ${collisions.length} wire(s) crossing symbols:`];
|
const lines = [`Found ${collisions.length} wire(s) crossing symbols:`];
|
||||||
collisions.slice(0, 30).forEach((c: any, i: number) => {
|
collisions.slice(0, 30).forEach((c: any, i: number) => {
|
||||||
lines.push(
|
lines.push(
|
||||||
` ${i + 1}. Wire (${c.wire.start.x},${c.wire.start.y})→(${c.wire.end.x},${c.wire.end.y}) crosses ${c.component.reference} (${c.component.libId})`
|
` ${i + 1}. Wire (${c.wire.start.x},${c.wire.start.y})→(${c.wire.end.x},${c.wire.end.y}) crosses ${c.component.reference} (${c.component.libId})`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (collisions.length > 30) lines.push(` ... and ${collisions.length - 30} more`);
|
if (collisions.length > 30) lines.push(` ... and ${collisions.length - 30} more`);
|
||||||
|
|||||||
@@ -15,45 +15,67 @@ const PinSchema = z.object({
|
|||||||
number: z.union([z.string(), z.number()]).describe("Pin number, e.g. '1', '2', 'A1'"),
|
number: z.union([z.string(), z.number()]).describe("Pin number, e.g. '1', '2', 'A1'"),
|
||||||
type: z
|
type: z
|
||||||
.enum([
|
.enum([
|
||||||
"input", "output", "bidirectional", "tri_state", "passive",
|
"input",
|
||||||
"free", "unspecified", "power_in", "power_out",
|
"output",
|
||||||
"open_collector", "open_emitter", "no_connect",
|
"bidirectional",
|
||||||
|
"tri_state",
|
||||||
|
"passive",
|
||||||
|
"free",
|
||||||
|
"unspecified",
|
||||||
|
"power_in",
|
||||||
|
"power_out",
|
||||||
|
"open_collector",
|
||||||
|
"open_emitter",
|
||||||
|
"no_connect",
|
||||||
])
|
])
|
||||||
.describe("Electrical pin type"),
|
.describe("Electrical pin type"),
|
||||||
at: z.object({
|
at: z
|
||||||
|
.object({
|
||||||
x: z.number().describe("X position in mm"),
|
x: z.number().describe("X position in mm"),
|
||||||
y: z.number().describe("Y position in mm"),
|
y: z.number().describe("Y position in mm"),
|
||||||
angle: z.number().describe(
|
angle: z
|
||||||
"Direction the pin wire extends FROM the symbol body: 0=right, 90=up, 180=left, 270=down"
|
.number()
|
||||||
|
.describe(
|
||||||
|
"Direction the pin wire extends FROM the symbol body: 0=right, 90=up, 180=left, 270=down",
|
||||||
),
|
),
|
||||||
}).describe("Pin endpoint position (where the wire connects)"),
|
})
|
||||||
|
.describe("Pin endpoint position (where the wire connects)"),
|
||||||
length: z.number().optional().describe("Pin length in mm (default 2.54)"),
|
length: z.number().optional().describe("Pin length in mm (default 2.54)"),
|
||||||
shape: z
|
shape: z
|
||||||
.enum(["line", "inverted", "clock", "inverted_clock", "input_low",
|
.enum([
|
||||||
"clock_low", "output_low", "falling_edge_clock", "non_logic"])
|
"line",
|
||||||
|
"inverted",
|
||||||
|
"clock",
|
||||||
|
"inverted_clock",
|
||||||
|
"input_low",
|
||||||
|
"clock_low",
|
||||||
|
"output_low",
|
||||||
|
"falling_edge_clock",
|
||||||
|
"non_logic",
|
||||||
|
])
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Pin graphic shape (default: line)"),
|
.describe("Pin graphic shape (default: line)"),
|
||||||
});
|
});
|
||||||
|
|
||||||
const RectSchema = z.object({
|
const RectSchema = z.object({
|
||||||
x1: z.number(), y1: z.number(),
|
x1: z.number(),
|
||||||
x2: z.number(), y2: z.number(),
|
y1: z.number(),
|
||||||
|
x2: z.number(),
|
||||||
|
y2: z.number(),
|
||||||
width: z.number().optional().describe("Stroke width in mm (default 0.254)"),
|
width: z.number().optional().describe("Stroke width in mm (default 0.254)"),
|
||||||
fill: z.enum(["none", "outline", "background"]).optional()
|
fill: z
|
||||||
|
.enum(["none", "outline", "background"])
|
||||||
|
.optional()
|
||||||
.describe("Fill type (default: background)"),
|
.describe("Fill type (default: background)"),
|
||||||
});
|
});
|
||||||
|
|
||||||
const PolylineSchema = z.object({
|
const PolylineSchema = z.object({
|
||||||
points: z.array(z.object({ x: z.number(), y: z.number() }))
|
points: z.array(z.object({ x: z.number(), y: z.number() })).describe("List of XY points in mm"),
|
||||||
.describe("List of XY points in mm"),
|
|
||||||
width: z.number().optional().describe("Stroke width in mm (default 0.254)"),
|
width: z.number().optional().describe("Stroke width in mm (default 0.254)"),
|
||||||
fill: z.enum(["none", "outline", "background"]).optional(),
|
fill: z.enum(["none", "outline", "background"]).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function registerSymbolCreatorTools(
|
export function registerSymbolCreatorTools(server: McpServer, callKicadScript: Function) {
|
||||||
server: McpServer,
|
|
||||||
callKicadScript: Function,
|
|
||||||
) {
|
|
||||||
// ── create_symbol ────────────────────────────────────────────────────── //
|
// ── create_symbol ────────────────────────────────────────────────────── //
|
||||||
server.tool(
|
server.tool(
|
||||||
"create_symbol",
|
"create_symbol",
|
||||||
@@ -68,14 +90,14 @@ export function registerSymbolCreatorTools(
|
|||||||
"- Pins on bottom: at.y = body_bottom - length, angle=90 (wire goes up)\n" +
|
"- Pins on bottom: at.y = body_bottom - length, angle=90 (wire goes up)\n" +
|
||||||
"- Standard pin length: 2.54 mm, standard grid: 2.54 mm",
|
"- Standard pin length: 2.54 mm, standard grid: 2.54 mm",
|
||||||
{
|
{
|
||||||
libraryPath: z
|
libraryPath: z.string().describe("Path to the .kicad_sym file (created if missing)"),
|
||||||
.string()
|
|
||||||
.describe("Path to the .kicad_sym file (created if missing)"),
|
|
||||||
name: z.string().describe("Symbol name, e.g. 'TMC2209', 'MyOpAmp'"),
|
name: z.string().describe("Symbol name, e.g. 'TMC2209', 'MyOpAmp'"),
|
||||||
referencePrefix: z
|
referencePrefix: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Schematic reference prefix: 'U' (IC), 'R' (resistor), 'J' (connector), etc. Default: 'U'"),
|
.describe(
|
||||||
|
"Schematic reference prefix: 'U' (IC), 'R' (resistor), 'J' (connector), etc. Default: 'U'",
|
||||||
|
),
|
||||||
description: z.string().optional().describe("Human-readable description"),
|
description: z.string().optional().describe("Human-readable description"),
|
||||||
keywords: z.string().optional().describe("Space-separated search keywords"),
|
keywords: z.string().optional().describe("Space-separated search keywords"),
|
||||||
datasheet: z.string().optional().describe("Datasheet URL or '~'"),
|
datasheet: z.string().optional().describe("Datasheet URL or '~'"),
|
||||||
@@ -161,9 +183,7 @@ export function registerSymbolCreatorTools(
|
|||||||
"Register a .kicad_sym library in KiCAD's sym-lib-table so symbols can be used in schematics. " +
|
"Register a .kicad_sym library in KiCAD's sym-lib-table so symbols can be used in schematics. " +
|
||||||
"Run this after create_symbol when KiCAD shows 'library not found'.",
|
"Run this after create_symbol when KiCAD shows 'library not found'.",
|
||||||
{
|
{
|
||||||
libraryPath: z
|
libraryPath: z.string().describe("Full path to the .kicad_sym file"),
|
||||||
.string()
|
|
||||||
.describe("Full path to the .kicad_sym file"),
|
|
||||||
libraryName: z
|
libraryName: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
|
|||||||
@@ -2,27 +2,24 @@
|
|||||||
* UI/Process management tools for KiCAD MCP server
|
* UI/Process management tools for KiCAD MCP server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { z } from 'zod';
|
import { z } from "zod";
|
||||||
import { logger } from '../logger.js';
|
import { logger } from "../logger.js";
|
||||||
|
|
||||||
export function registerUITools(server: McpServer, callKicadScript: Function) {
|
export function registerUITools(server: McpServer, callKicadScript: Function) {
|
||||||
// Check if KiCAD UI is running
|
// Check if KiCAD UI is running
|
||||||
server.tool(
|
server.tool("check_kicad_ui", "Check if KiCAD UI is currently running", {}, async () => {
|
||||||
"check_kicad_ui",
|
logger.info("Checking KiCAD UI status");
|
||||||
"Check if KiCAD UI is currently running",
|
|
||||||
{},
|
|
||||||
async () => {
|
|
||||||
logger.info('Checking KiCAD UI status');
|
|
||||||
const result = await callKicadScript("check_kicad_ui", {});
|
const result = await callKicadScript("check_kicad_ui", {});
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// Launch KiCAD UI
|
// Launch KiCAD UI
|
||||||
server.tool(
|
server.tool(
|
||||||
@@ -30,19 +27,26 @@ export function registerUITools(server: McpServer, callKicadScript: Function) {
|
|||||||
"Launch KiCAD UI, optionally with a project file",
|
"Launch KiCAD UI, optionally with a project file",
|
||||||
{
|
{
|
||||||
projectPath: z.string().optional().describe("Optional path to .kicad_pcb file to open"),
|
projectPath: z.string().optional().describe("Optional path to .kicad_pcb file to open"),
|
||||||
autoLaunch: z.boolean().optional().describe("Whether to launch KiCAD if not running (default: true)")
|
autoLaunch: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Whether to launch KiCAD if not running (default: true)"),
|
||||||
},
|
},
|
||||||
async (args: { projectPath?: string; autoLaunch?: boolean }) => {
|
async (args: { projectPath?: string; autoLaunch?: boolean }) => {
|
||||||
logger.info(`Launching KiCAD UI${args.projectPath ? ' with project: ' + args.projectPath : ''}`);
|
logger.info(
|
||||||
|
`Launching KiCAD UI${args.projectPath ? " with project: " + args.projectPath : ""}`,
|
||||||
|
);
|
||||||
const result = await callKicadScript("launch_kicad_ui", args);
|
const result = await callKicadScript("launch_kicad_ui", args);
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [
|
||||||
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: JSON.stringify(result, null, 2)
|
text: JSON.stringify(result, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('UI management tools registered');
|
logger.info("UI management tools registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,13 @@
|
|||||||
*/
|
*/
|
||||||
export function createJsonResponse(data: any, uri?: string) {
|
export function createJsonResponse(data: any, uri?: string) {
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri || "data:application/json",
|
uri: uri || "data:application/json",
|
||||||
mimeType: "application/json",
|
mimeType: "application/json",
|
||||||
text: JSON.stringify(data, null, 2)
|
text: JSON.stringify(data, null, 2),
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,14 +30,16 @@ export function createJsonResponse(data: any, uri?: string) {
|
|||||||
* @returns MCP resource response object
|
* @returns MCP resource response object
|
||||||
*/
|
*/
|
||||||
export function createBinaryResponse(data: Buffer | string, mimeType: string, uri?: string) {
|
export function createBinaryResponse(data: Buffer | string, mimeType: string, uri?: string) {
|
||||||
const blob = typeof data === 'string' ? data : data.toString('base64');
|
const blob = typeof data === "string" ? data : data.toString("base64");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri || `data:${mimeType}`,
|
uri: uri || `data:${mimeType}`,
|
||||||
mimeType: mimeType,
|
mimeType: mimeType,
|
||||||
blob: blob
|
blob: blob,
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,13 +53,19 @@ export function createBinaryResponse(data: Buffer | string, mimeType: string, ur
|
|||||||
*/
|
*/
|
||||||
export function createErrorResponse(error: string, details?: string, uri?: string) {
|
export function createErrorResponse(error: string, details?: string, uri?: string) {
|
||||||
return {
|
return {
|
||||||
contents: [{
|
contents: [
|
||||||
|
{
|
||||||
uri: uri || "data:application/json",
|
uri: uri || "data:application/json",
|
||||||
mimeType: "application/json",
|
mimeType: "application/json",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify(
|
||||||
|
{
|
||||||
error,
|
error,
|
||||||
details
|
details,
|
||||||
}, null, 2)
|
},
|
||||||
}]
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user