From 7d50fa1d4c8378c06af2cf71959b9e14c68a5b34 Mon Sep 17 00:00:00 2001 From: Eugene Mikhantyev Date: Sun, 29 Mar 2026 13:05:50 +0100 Subject: [PATCH] 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 --- .github/workflows/ci.yml | 388 ++-- .pre-commit-config.yaml | 8 +- .prettierignore | 9 + .prettierrc.json | 7 + CHANGELOG.md | 1334 ++++++------ CONTRIBUTING.md | 832 +++---- README.md | 2035 +++++++++--------- config/linux-config.example.json | 30 +- config/macos-config.example.json | 30 +- config/windows-config.example.json | 32 +- docs/ARCHITECTURE.md | 34 +- docs/CLIENT_CONFIGURATION.md | 1081 +++++----- docs/DATASHEET_TOOLS_GUIDE.md | 20 +- docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md | 254 +-- docs/FREEROUTING_GUIDE.md | 8 + docs/INDEX.md | 84 +- docs/IPC_BACKEND_STATUS.md | 435 ++-- docs/JLCPCB_INTEGRATION.md | 718 +++--- docs/JLCPCB_USAGE_GUIDE.md | 1067 ++++----- docs/KNOWN_ISSUES.md | 18 + docs/LIBRARY_INTEGRATION.md | 754 +++---- docs/LINUX_COMPATIBILITY_AUDIT.md | 649 +++--- docs/PCB_DESIGN_WORKFLOW.md | 7 + docs/PLATFORM_GUIDE.md | 1073 ++++----- docs/REALTIME_WORKFLOW.md | 857 ++++---- docs/ROADMAP.md | 12 +- docs/ROUTER_ARCHITECTURE.md | 736 ++++--- docs/ROUTER_QUICK_START.md | 362 ++-- docs/ROUTING_TOOLS_REFERENCE.md | 197 +- docs/SCHEMATIC_TOOLS_REFERENCE.md | 291 +-- docs/STATUS_SUMMARY.md | 97 +- docs/SVG_IMPORT_GUIDE.md | 42 +- docs/TOOL_INVENTORY.md | 396 ++-- docs/UI_AUTO_LAUNCH.md | 824 +++---- docs/VISUAL_FEEDBACK.md | 377 ++-- docs/WINDOWS_TROUBLESHOOTING.md | 968 +++++---- docs/archive/BUILD_AND_TEST_SESSION.md | 1013 ++++----- docs/archive/DYNAMIC_LIBRARY_LOADING_PLAN.md | 994 ++++----- docs/archive/DYNAMIC_LOADING_STATUS.md | 803 +++---- docs/archive/IPC_API_MIGRATION_PLAN.md | 970 +++++---- docs/archive/JLCPCB_INTEGRATION_PLAN.md | 1238 +++++------ docs/archive/ROUTER_IMPLEMENTATION_STATUS.md | 463 ++-- docs/archive/SCHEMATIC_WIRING_PLAN.md | 1381 ++++++------ docs/archive/SCHEMATIC_WORKFLOW_FIX.md | 258 +-- docs/archive/WEEK1_SESSION1_SUMMARY.md | 1043 ++++----- docs/archive/WEEK1_SESSION2_SUMMARY.md | 879 ++++---- docs/mcp-router-guide.md | 359 +-- package-lock.json | 17 + package.json | 99 +- src/config.ts | 26 +- src/index.ts | 38 +- src/kicad-server.ts | 1004 ++++----- src/logger.ts | 35 +- src/prompts/component.ts | 468 ++-- src/prompts/design.ts | 666 +++--- src/prompts/footprint.ts | 9 +- src/prompts/routing.ts | 596 ++--- src/resources/board.ts | 726 ++++--- src/resources/component.ts | 265 +-- src/resources/index.ts | 20 +- src/resources/library.ts | 613 +++--- src/resources/project.ts | 527 ++--- src/server.ts | 112 +- src/tools/board.ts | 815 +++---- src/tools/component.ts | 160 +- src/tools/datasheet.ts | 21 +- src/tools/design-rules.ts | 575 ++--- src/tools/export.ts | 577 ++--- src/tools/footprint.ts | 27 +- src/tools/freerouting.ts | 35 +- src/tools/jlcpcb-api.ts | 540 ++--- src/tools/library-symbol.ts | 134 +- src/tools/library.ts | 62 +- src/tools/project.ts | 215 +- src/tools/registry.ts | 603 +++--- src/tools/router.ts | 547 ++--- src/tools/routing.ts | 48 +- src/tools/schematic.ts | 248 +-- src/tools/symbol-creator.ts | 76 +- src/tools/ui.ts | 100 +- src/utils/resource-helpers.ts | 132 +- tsconfig.json | 28 +- 82 files changed, 18314 insertions(+), 17317 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c30a29a..606f32a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,194 +1,194 @@ -name: CI/CD Pipeline - -on: - push: - branches: [ main, develop ] - pull_request: - branches: [ main, develop ] - -jobs: - # TypeScript/Node.js tests - typescript-tests: - name: TypeScript Build & Test - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-24.04, ubuntu-22.04, windows-latest, macos-latest] - node-version: [18.x, 20.x, 22.x] - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Run TypeScript compiler - run: npm run build - - - name: Run linter - run: npm run lint || echo "Linter not configured yet" - - - name: Run tests - run: npm test || echo "Tests not configured yet" - - # Python tests - python-tests: - name: Python Tests - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-24.04, ubuntu-22.04] - python-version: ['3.10', '3.11', '3.12'] - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - cache: 'pip' - - - name: Install Python dependencies - run: | - python -m pip install --upgrade pip - pip install pytest pytest-cov black mypy pylint - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi - - - name: Run Black formatter check - run: black --check python/ || echo "Black not configured yet" - - - name: Run MyPy type checker - run: mypy python/ || echo "MyPy not configured yet" - - - name: Run Pylint - run: pylint python/ || echo "Pylint not configured yet" - - - name: Run pytest - run: pytest python/ --cov=python --cov-report=xml || echo "Tests not configured yet" - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - with: - file: ./coverage.xml - flags: python - name: python-${{ matrix.python-version }} - if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-24.04' - - # Integration tests (requires KiCAD) - integration-tests: - name: Integration Tests (Linux + KiCAD) - runs-on: ubuntu-24.04 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20.x' - cache: 'npm' - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - cache: 'pip' - - - name: Add KiCAD PPA and Install KiCAD 9.0 - run: | - sudo add-apt-repository --yes ppa:kicad/kicad-9.0-releases - sudo apt-get update - sudo apt-get install -y kicad kicad-libraries - - - name: Verify KiCAD installation - run: | - kicad-cli version || echo "kicad-cli not found" - python3 -c "import pcbnew; print(f'pcbnew version: {pcbnew.GetBuildVersion()}')" || echo "pcbnew module not found" - - - name: Install dependencies - run: | - npm ci - pip install -r requirements.txt - - - name: Build TypeScript - run: npm run build - - - name: Run integration tests - run: | - echo "Integration tests not yet configured" - # pytest tests/integration/ - - # Docker build test - docker-build: - name: Docker Build Test - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build Docker image - run: | - echo "Docker build not yet configured" - # docker build -t kicad-mcp-server:test . - - # Code quality checks - code-quality: - name: Code Quality - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20.x' - - - name: Install dependencies - run: npm ci - - - name: Run ESLint - run: npx eslint src/ || echo "ESLint not configured yet" - - - name: Run Prettier check - run: npx prettier --check "src/**/*.ts" || echo "Prettier not configured yet" - - - name: Check for security vulnerabilities - run: npm audit --audit-level=moderate || echo "No critical vulnerabilities" - - # Documentation check - docs-check: - name: Documentation Check - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Check README exists - run: test -f README.md - - - name: Check for broken links in docs - run: | - sudo apt-get install -y linkchecker || true - # linkchecker docs/ || echo "Link checker not configured" - - - name: Validate JSON files - run: | - find . -name "*.json" -not -path "./node_modules/*" -not -path "./dist/*" | xargs -I {} sh -c 'python3 -m json.tool {} > /dev/null && echo "✓ {}" || echo "✗ {}"' +name: CI/CD Pipeline + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + +jobs: + # TypeScript/Node.js tests + typescript-tests: + name: TypeScript Build & Test + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-24.04, ubuntu-22.04, windows-latest, macos-latest] + node-version: [18.x, 20.x, 22.x] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Run TypeScript compiler + run: npm run build + + - name: Run linter + run: npm run lint || echo "Linter not configured yet" + + - name: Run tests + run: npm test || echo "Tests not configured yet" + + # Python tests + python-tests: + name: Python Tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-24.04, ubuntu-22.04] + python-version: ["3.10", "3.11", "3.12"] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: "pip" + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-cov black mypy pylint + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi + + - name: Run Black formatter check + run: black --check python/ || echo "Black not configured yet" + + - name: Run MyPy type checker + run: mypy python/ || echo "MyPy not configured yet" + + - name: Run Pylint + run: pylint python/ || echo "Pylint not configured yet" + + - name: Run pytest + run: pytest python/ --cov=python --cov-report=xml || echo "Tests not configured yet" + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + file: ./coverage.xml + flags: python + name: python-${{ matrix.python-version }} + if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-24.04' + + # Integration tests (requires KiCAD) + integration-tests: + name: Integration Tests (Linux + KiCAD) + runs-on: ubuntu-24.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.x" + cache: "npm" + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + + - name: Add KiCAD PPA and Install KiCAD 9.0 + run: | + sudo add-apt-repository --yes ppa:kicad/kicad-9.0-releases + sudo apt-get update + sudo apt-get install -y kicad kicad-libraries + + - name: Verify KiCAD installation + run: | + kicad-cli version || echo "kicad-cli not found" + python3 -c "import pcbnew; print(f'pcbnew version: {pcbnew.GetBuildVersion()}')" || echo "pcbnew module not found" + + - name: Install dependencies + run: | + npm ci + pip install -r requirements.txt + + - name: Build TypeScript + run: npm run build + + - name: Run integration tests + run: | + echo "Integration tests not yet configured" + # pytest tests/integration/ + + # Docker build test + docker-build: + name: Docker Build Test + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + run: | + echo "Docker build not yet configured" + # docker build -t kicad-mcp-server:test . + + # Code quality checks + code-quality: + name: Code Quality + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.x" + + - name: Install dependencies + run: npm ci + + - name: Run ESLint + run: npx eslint src/ || echo "ESLint not configured yet" + + - name: Run Prettier check + run: npx prettier --check "src/**/*.ts" || echo "Prettier not configured yet" + + - name: Check for security vulnerabilities + run: npm audit --audit-level=moderate || echo "No critical vulnerabilities" + + # Documentation check + docs-check: + name: Documentation Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check README exists + run: test -f README.md + + - name: Check for broken links in docs + run: | + sudo apt-get install -y linkchecker || true + # linkchecker docs/ || echo "Link checker not configured" + + - name: Validate JSON files + run: | + find . -name "*.json" -not -path "./node_modules/*" -not -path "./dist/*" | xargs -I {} sh -c 'python3 -m json.tool {} > /dev/null && echo "✓ {}" || echo "✗ {}"' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e5ce50d..e34355f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: - id: check-yaml - id: check-json - id: check-added-large-files - args: ['--maxkb=500'] + args: ["--maxkb=500"] - id: check-merge-conflict - repo: https://github.com/psf/black @@ -22,3 +22,9 @@ repos: hooks: - id: isort 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/) diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..3910bf6 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +dist/ +node_modules/ +coverage.xml +htmlcov/ +data/ +*.kicad_* +python/ +package-lock.json +.venv/ diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..cf7c9eb --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "semi": true, + "trailingComma": "all", + "singleQuote": false, + "printWidth": 100, + "tabWidth": 2 +} diff --git a/CHANGELOG.md b/CHANGELOG.md index cc382a1..b4ebaf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,641 +1,693 @@ -# Changelog - -All notable changes to the KiCAD MCP Server project are documented here. - -## [2.2.3] - 2026-03-11 - -### Merged: PR #57 (Kletternaut/demo/rpiCSI-videotest → main) - -This release incorporates 28 commits developed and live-tested during a full -Raspberry Pi CSI adapter PCB design session. All tools listed below were validated -end-to-end using Claude Desktop + KiCAD 9 on Windows. - -### New MCP Tools - -- `connect_passthrough` — Schematic-only tool that wires all pins of one connector - directly to the matching pins of another (e.g. J1 pin N → J2 pin N). Creates nets - named with a configurable prefix (`netPrefix`). Designed for FFC/ribbon cable - passthrough adapters. **Schematic only — do not call for PCB routing.** - -- `sync_schematic_to_board` — Imports all net/pad assignments from the schematic - into the open PCB file. Required after `connect_passthrough` before routing can - start. Returns `pads_assigned` count for verification. - -- `snapshot_project` — Saves a named checkpoint of the entire project folder into a - `snapshots/` subdirectory inside the project. Allows resuming from a known-good - state without redoing earlier steps. Accepts `step`, `label`, and optional `prompt` - parameters. - -- `run_erc` — Runs KiCAD's Electrical Rules Check on the schematic and returns - violations as structured JSON. - -- `import_svg_logo` — Converts an SVG file to PCB silkscreen polygons and places - them on a specified layer. - -### Bug Fixes - -- `route_pad_to_pad`: **Critical fix for B.Cu footprints in KiCAD 9.** `pad.GetLayerName()` - always returned `F.Cu` for SMD pads on flipped footprints (KiCAD 9 SWIG bug). - Fix: use `footprint.GetLayer()` instead, which correctly reflects the placed layer - after `Flip()`. Without this fix, no vias were inserted for back-to-back connectors. - -- `route_pad_to_pad`: Via was placed at the geometric midpoint between the two pads. - For back-to-back mirrored connectors (J1 F.Cu / J2 B.Cu) this caused all 15 vias - to stack at the same X coordinate (board center). Fix: via is now placed at the - X coordinate of the start pad (`via_x = start_pos.x`), producing 15 parallel - vertical traces. - -- `place_component` (B.Cu footprints): `Flip()` was called before `board.Add()`, - causing KiCAD 9 to hang for ~30 seconds. Fix: `board.Add()` first, then `Flip()`. - -- `add_board_outline`: Three separate bugs fixed — incorrect cornerRadius fallback, - wrong top-left origin default, and broken arc delegation for IPC rounded rectangles. - -- `snapshot_project`: Snapshots were saved one level above the project directory, - cluttering the parent folder. Fix: snapshots now go into `/snapshots/`. - -- MCP server log timestamp was always UTC/ISO. Fix: now uses local system time. - -- `search_tools` (router pattern): direct tools like `snapshot_project` were invisible - to the router. Fix: direct tool names added to the router's known-tool list. - -### Developer Mode (`KICAD_MCP_DEV=1`) - -Set the environment variable `KICAD_MCP_DEV=1` in your Claude Desktop config to -enable developer features: - -```json -"env": { - "KICAD_MCP_DEV": "1" -} -``` - -**What it does:** -- `export_gerber` automatically copies the current MCP session log into the project's - `logs/` subdirectory as `mcp_log_.txt`. -- `snapshot_project` copies the MCP session log into `logs/` at every checkpoint as - `mcp_log_step_.txt`. -- If a `prompt` parameter is passed to `snapshot_project`, it is saved as - `PROMPT_step_.md` alongside the log. - -**Purpose:** Makes it easy to include the full tool call history when filing a bug -report or GitHub issue — just attach the log file from the project's `logs/` folder. - -> ⚠️ **Privacy warning:** The MCP session log contains the **complete conversation -> history** between Claude and the MCP server, including all tool parameters and -> responses. When sharing a project directory (e.g. as a ZIP attachment in a GitHub -> issue), **review or delete the `logs/` folder first** to avoid accidentally -> disclosing sensitive file paths, component names, or design details. - -### Snapshot Logging (always active) - -Regardless of dev mode, `snapshot_project` now always saves a copy of the current -MCP session log into `/logs/` at each checkpoint. This means every project -automatically retains a traceable record of which tools were called and in what order. - -> ⚠️ **Same privacy note applies:** the `logs/` directory inside your project folder -> contains tool call history. Do not share it publicly without reviewing its contents. - ---- - -## [2.2.2-alpha] - 2026-03-01 - -### New MCP Tools - -- `route_pad_to_pad` – Convenience wrapper around `route_trace` that looks up pad positions - automatically. Accepts `fromRef`/`fromPad`/`toRef`/`toPad` instead of raw XY coordinates. - Auto-detects net from pad assignment (overridable via `net` param). Saves ~2 tool calls per - connection (~64 calls for a full TMC2209 board compared to the 3-step get_pad_position flow). - Live tested: ESP32 ↔ TMC2209 STEP/DIR traces routed without prior coordinate lookup. ✅ - -- `copy_routing_pattern` – Now registered as MCP tool in TypeScript layer (`routing.ts`). - Was previously implemented in Python but missing from the MCP tool registry. - Parameters: `sourceRefs`, `targetRefs`, `includeVias?`, `traceWidth?`. - -### Bug Fixes - -- `add_schematic_component` / `DynamicSymbolLoader`: ignored project-local `sym-lib-table`. - `find_library_file()` only searched global KiCAD install directories, causing "library not - found" errors for any symbol in a project-local `.kicad_sym` file. Fix: added `project_path` - parameter; reads project `sym-lib-table` first via new `_resolve_library_from_table()` helper - before falling back to global dirs. `project_path` is auto-derived from the schematic path. - -- `place_component`: ignored project-local `fp-lib-table`. `FootprintLibraryManager` was - initialised once at server start without a project path, so self-created `.kicad_mod` - footprints were never found. Fix: new `boardPath` parameter in TypeScript + Python; - `_handle_place_component` wrapper recreates `FootprintLibraryManager(project_path=…)` whenever - the active project changes (cached to avoid redundant recreation). - -- `copy_routing_pattern`: copied 0 traces when pads had no net assignments. The filter - `track.GetNetname() in source_nets` always returned empty when pads were placed without net - assignment. Fix: geometric fallback using bounding box of source footprint pads ±5mm - tolerance. Response includes `filterMethod` field indicating which mode was used - (`"net-based"` or `"geometric (pads have no nets)"`). - -- `template_with_symbols.kicad_sch`, `template_with_symbols_expanded.kicad_sch`: restored - format version `20250114` (KiCAD 9) after upstream commit `2b38796` accidentally downgraded - both files to `20240101`. KiCAD 9 rejects schematics with outdated version numbers. - -- **CRITICAL: `template_with_symbols_expanded.kicad_sch`**: removed 7 invalid `;;` comment - lines introduced by upstream commit `b98c94b`. KiCAD's S-expression parser does not support - any comment syntax — it expects every non-empty, non-whitespace line to start with `(`. - The comments (`;; PASSIVES`, `;; SEMICONDUCTORS`, `;; INTEGRATED CIRCUITS`, `;; CONNECTORS`, - `;; POWER/REGULATORS`, `;; MISC`, `;; TEMPLATE INSTANCES (...)`) caused KiCAD 9 to reject - every schematic created from this template with a hard parse error: - > `Expecting '(' in .kicad_sch, line 8, offset 5` - **Action required for existing projects:** delete every line beginning with `;;` from any - `.kicad_sch` file created between upstream commit `b98c94b` and this fix. - -- `add_schematic_component` / `inject_symbol_into_schematic`: symbol definition in - `lib_symbols` was never refreshed after editing via `create_symbol` / `edit_symbol`. - If the symbol was already present in the schematic's embedded `lib_symbols` section, - the function returned immediately — `delete + re-add` still pulled in the stale cached - definition. Fix: always read the current definition from the `.kicad_sym` file; if a - stale entry exists in `lib_symbols`, remove it first, then inject the fresh one. - Verified live. ✅ - -- `template_with_symbols_expanded.kicad_sch`: removed 13 legacy `_TEMPLATE_*` offscreen - instances (`_TEMPLATE_R`, `_TEMPLATE_C`, `_TEMPLATE_U`, etc.) that were placed at - `x=-100` as clone-sources for the old `ComponentManager` approach. `DynamicSymbolLoader` - (the current implementation) injects symbols directly and never needs these placeholders. - They appeared as dangling reference designators in KiCAD's component navigator and in - the schematic canvas when zoomed far out. - -### Maintenance - -- `.gitignore`: added `*.kicad_pcb.bak`, `*.kicad_pro.bak` alongside existing `-bak` variants; - consolidated personal/local files under `myContribution/`. - ---- - -## [2.2.1-alpha] - 2026-02-28 - -### New MCP Tools - -- `edit_schematic_component` – Update properties of a placed symbol in-place (footprint, - value, reference rename). More efficient than delete + re-add: preserves position and UUID. - -### Bug Fixes - -- `add_schematic_component`: `footprint` parameter was accepted but silently ignored – the - value was never passed through to `DynamicSymbolLoader.add_component()` / - `create_component_instance()`. All newly placed symbols always had an empty Footprint - field. Fix: added `footprint: str = ""` to both functions and threaded it through every - call site including the TypeScript tool schema. - -- `delete_schematic_component`: only deleted the first matching instance when duplicate - references existed (e.g. after an aborted add attempt). Root cause: loop used `break` - after the first match. Fix: collect all matching blocks first, then delete them all back- - to-front (to preserve line indices). Response now includes `deleted_count`. - -- `templates/*.kicad_sch`, `project.py`, `schematic.py`: Update KiCAD schematic format - version from `20230121` (KiCAD 7) to `20250114` (KiCAD 9). The MCP server targets - KiCAD 9 exclusively (`pcbnew.pyd` compiled for KiCAD 9.0, Python 3.11.5) – generating - files in an outdated format caused a spurious "This file was created with an older - KiCAD version" warning on every newly created schematic. - -- `template_with_symbols_expanded.kicad_sch`: Remove 13 corrupt `_TEMPLATE_*` placed-symbol - blocks with `(lib_id -100)` – an integer caused by old sexpdata serializer (same bug - PR #40 fixed for the add path). KiCAD crashed with a null-pointer when selecting these - symbols. They appeared as grey `_TEMPLATE_R?`, `_TEMPLATE_U_REG?` etc. labels far - outside the sheet boundary (~5000mm off-sheet). - - **Discovered via:** live testing on a real JLCPCB/KiCAD 9 project. - **Affected users:** schematics created from this template before this fix contain the - same corrupt blocks – remove all `(symbol (lib_id -100) ...)` blocks whose Reference - starts with `_TEMPLATE_`. - ---- - ---- - -## [2.2.0-alpha] - 2026-02-27 - -### New MCP Tools (TypeScript layer – previously Python-only) - -**Routing tools:** -- `delete_trace` - Delete traces by UUID, position or net name -- `query_traces` - Query/filter traces on the board -- `get_nets_list` - List all nets with net code and class -- `modify_trace` - Modify trace width or layer -- `create_netclass` - Create or update a net class -- `route_differential_pair` - Route a differential pair between two points -- `refill_zones` - Refill all copper zones ⚠️ SWIG segfault risk, prefer IPC/UI - -**Component tools:** -- `get_component_pads` - Get all pad data for a component -- `get_component_list` - List all components on the board -- `get_pad_position` - Get absolute position of a specific pad -- `place_component_array` - Place components in a grid array -- `align_components` - Align components along an axis -- `duplicate_component` - Duplicate a component with offset - -### Bug Fixes - -- `routing.py`: Fix SwigPyObject UUID comparison (`str()` → `m_Uuid.AsString()`) -- `routing.py`: Fix SWIG iterator invalidation after `board.Remove()` by snapshotting `list(board.Tracks())` -- `routing.py`: Add `board.SetModified()` + `track = None` after `Remove()` to prevent dangling SWIG pointer crashes -- `routing.py`: Per-track `try/except` in `query_traces()` to skip invalid objects after bulk delete -- `routing.py`: Add missing return statement (mypy) -- `library.py`: Fix `search_footprints` parameter mapping (`search_term` → `pattern`) -- `library.py`: Fix field access (`fp.name` → `fp.full_name`) -- `library.py`: Accept both `pattern` and `search_term` parameter names -- `library.py`: Fix loop variable shadowing `Path` object (mypy) -- `design_rules.py`: Add type annotation for `violation_counts` (mypy) - -### New MCP Tools (cont.) - -**Datasheet tools:** -- `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`). - No API key required – URL is constructed directly from the LCSC number. -- `enrich_datasheets` - Scan a `.kicad_sch` file and write LCSC datasheet URLs into - every symbol that has an `LCSC` property but an empty `Datasheet` field. After - enrichment the URL appears natively in KiCAD's symbol properties, footprint browser - and any other tool that reads the standard KiCAD `Datasheet` field. - Supports `dry_run=true` for preview without writing. - Implementation: `python/commands/datasheet_manager.py` (text-based, no `skip` writes) - -**Schematic tools:** -- `delete_schematic_component` - Remove a placed symbol from a `.kicad_sch` file by - reference designator (e.g. `R1`, `U3`). - -### Bug Fixes (cont.) - -- `schematic.ts` / `kicad_interface.py`: Fix missing `delete_schematic_component` MCP tool. - - **Root cause (two separate issues):** - 1. No MCP tool named `delete_schematic_component` existed. Claude had no way to call - it, so any "delete schematic component" request fell through to the PCB-only - `delete_component` tool, which searches `pcbnew.BOARD` and always returned - "Component not found" for schematic symbols. - 2. `component_schematic.py::remove_component()` still used `skip` for writes. - PR #40 rewrote `DynamicSymbolLoader` (add path) to avoid `skip`-induced schematic - corruption, but `remove_component` (delete path) was not touched by that PR. - - **Fix:** - - Added `delete_schematic_component` to the TypeScript tool layer (`schematic.ts`) - with clear docstring distinguishing it from the PCB `delete_component`. - - Implemented `_handle_delete_schematic_component` in `kicad_interface.py` using - direct text manipulation (parenthesis-depth tracking, same approach as PR #40). - Does not call `component_schematic.py::remove_component()` at all. - - Error message explicitly guides the user when the wrong tool is used: - *"note: this tool removes schematic symbols, use delete_component for PCB footprints"* - -### Additional Bug Fixes - -- `connection_schematic.py` / `kicad_interface.py`: Fix `generate_netlist` missing - `schematic_path` parameter – without it `get_net_connections` always fell back to - proximity matching which only returns one connection per component (first wire hit, - then `break`). PinLocator was never invoked. Fix: added `schematic_path: Optional[Path]` - to `generate_netlist` signature and threaded it through to `get_net_connections`, - and updated `_handle_generate_netlist` in `kicad_interface.py` to pass `schematic_path`. -- `server.ts`: Fix KiCAD bundled Python (3.11.5) not being selected on Windows – the - detection condition `process.env.PYTHONPATH?.includes("KiCad")` was fragile and failed - in some environments, causing System Python 3.12 to be used instead. Since `pcbnew.pyd` - is compiled for KiCAD's Python 3.11.5, this resulted in `No module named 'pcbnew'`. - Fix: removed the condition, KiCAD bundled Python is now always preferred on Windows - when it exists at `C:\Program Files\KiCad\9.0\bin\python.exe`. - Also added `KICAD_PYTHON` to `claude_desktop_config.json` as explicit override. -- `pin_locator.py`: Fix `generate_netlist` timeout – `get_pin_location` and - `get_all_symbol_pins` called `Schematic(schematic_path)` on every single pin lookup, - causing O(nets × components × pins) schematic file loads (e.g. 400+ loads for a - medium schematic). Fix: added `_schematic_cache` dict to `PinLocator.__init__`, - schematic is now loaded once per path and reused. - ---- - -## [2.1.0-alpha] - 2026-01-10 - -### Phase 1: Intelligent Schematic Wiring System - Core Infrastructure - -**Major Features:** -- Automatic pin location discovery with rotation support -- Smart wire routing (direct, orthogonal horizontal/vertical) -- Net label management (local, global, hierarchical) -- S-expression-based wire creation -- Professional right-angle routing - -**New Components:** -- `python/commands/wire_manager.py` - S-expression wire creation engine -- `python/commands/pin_locator.py` - Intelligent pin discovery with rotation -- Updated `python/commands/connection_schematic.py` - High-level connection API -- `docs/SCHEMATIC_WIRING_PLAN.md` - Implementation roadmap - -**MCP Tools Enhanced:** -- `add_schematic_wire` - Create wires with stroke customization -- `add_schematic_connection` - Auto-connect pins with routing options (NEW) -- `add_schematic_net_label` - Add labels with type and orientation control (NEW) -- `connect_to_net` - Connect pins to named nets (ENHANCED) - -**Technical Implementation:** -- Rotation transformation matrix for pin coordinates -- S-expression injection for guaranteed format compliance -- Pin definition caching for performance -- Orthogonal path generation for professional schematics - -**Testing:** -- End-to-end integration test: 100% passing -- MCP handler integration test: 100% passing -- Pin discovery with rotation: Verified working -- KiCad-skip verification: All wires/labels correctly formed - ---- - -### Phase 2: Power Nets & Wire Connectivity - COMPLETE - -**Major Features:** -- Power symbol support (VCC, GND, +3V3, +5V, etc.) via dynamic loading -- Wire graph analysis for net connectivity tracking -- Geometric wire tracing with tolerance-based point matching -- Accurate netlist generation with component/pin connections -- Critical template mapping bug fixes - -**Updates:** -- `connect_to_net()` - Migrated to WireManager + PinLocator -- `get_net_connections()` - Complete rewrite with geometric wire tracing -- `generate_netlist()` - Now uses wire graph analysis for connectivity -- `get_or_create_template()` - Fixed special character handling, auto-reload after dynamic loading -- `add_component()` - Fixed template lookup with symbol iteration - -**Bug Fixes:** -- CRITICAL: Template mapping after dynamic symbol loading -- Special character handling in symbol names (+ prefix in +3V3, +5V) -- Schematic reload synchronization after S-expression injection -- Multi-format template reference detection - -**Wire Graph Analysis Algorithm:** -1. Find all labels matching target net name -2. Trace wires connected to label positions (point coincidence) -3. Collect all wire endpoints and polyline segments -4. Match component pins at wire connection points using PinLocator -5. Return accurate component/pin connection pairs - -**Technical Implementation:** -- Tolerance-based point matching (0.5mm for grid alignment) -- Multi-segment wire (polyline) support -- Rotation-aware pin location matching via PinLocator -- Fallback proximity detection (10mm threshold) -- Template existence checking via symbol iteration (handles special characters) - -**Testing:** -- Power symbols: 4/4 loaded (VCC, GND, +3V3, +5V) -- Components: 4/4 placed -- Connections: 8/8 created successfully -- Net connectivity: 100% accurate (VCC: 2, GND: 4, +3V3: 1, +5V: 1) -- Netlist generation: 4 nets with accurate connections -- Comprehensive integration test: 100% PASSING - -**Commits:** -- `c67f400` - Updated connect_to_net to use WireManager -- `b77f008` - Fixed template mapping bug (critical) -- `a5a542b` - Implemented wire graph analysis - -**Addresses:** -- Issue #26 - Schematic workflow wiring functionality (Phase 2) - ---- - -### Phase 2: JLCPCB Integration Complete - -**Major Features:** -- ✅ Complete JLCPCB parts integration via JLCSearch public API -- ✅ Access to ~100k JLCPCB parts catalog -- ✅ Real-time stock and pricing data -- ✅ Parametric component search -- ✅ Cost optimization (Basic vs Extended library) -- ✅ KiCad footprint mapping -- ✅ Alternative part suggestions - -**New Components:** -- `python/commands/jlcsearch.py` - JLCSearch API client (no auth required) -- `python/commands/jlcpcb_parts.py` - Enhanced with `import_jlcsearch_parts()` -- `docs/JLCPCB_INTEGRATION.md` - Comprehensive integration guide - -**MCP Tools Available:** -- `download_jlcpcb_database` - Download full parts catalog -- `search_jlcpcb_parts` - Parametric search with filters -- `get_jlcpcb_part` - Part details + footprint suggestions -- `get_jlcpcb_database_stats` - Database statistics -- `suggest_jlcpcb_alternatives` - Find similar/cheaper parts - -**Technical Improvements:** -- SQLite database with full-text search (FTS5) -- Package-to-footprint mapping for standard SMD packages -- Price comparison and cost optimization algorithms -- HMAC-SHA256 authentication support (for official JLCPCB API) - -**Testing:** -- All integration tests passing -- Database operations validated -- Live API connectivity confirmed -- End-to-end MCP tool testing complete - -**Documentation:** -- Complete API reference with examples -- Package mapping tables (0402, 0603, 0805, SOT-23, etc.) -- Best practices guide -- Troubleshooting section - ---- - -## [2.1.0-alpha] - 2025-11-30 - -### Phase 1: Schematic Workflow Fix - -**Critical Bug Fix:** -- ✅ Fixed completely broken schematic workflow (Issue #26) -- Created template-based symbol cloning approach -- All schematic tests now passing - -**Root Cause:** -- kicad-skip library limitation: cannot create symbols from scratch, only clone existing ones - -**Solution:** -- Template schematic with cloneable R, C, LED symbols -- Updated `create_project` to create both PCB and schematic -- Rewrote `add_schematic_component` to use `clone()` API -- Proper UUID generation and position setting - -**Files Modified:** -- `python/commands/project.py` - Now creates schematic files -- `python/commands/schematic.py` - Uses template approach -- `python/commands/component_schematic.py` - Complete rewrite - -**Files Created:** -- `python/templates/template_with_symbols.kicad_sch` -- `python/templates/empty.kicad_sch` -- `docs/SCHEMATIC_WORKFLOW_FIX.md` - -**Testing:** -- Created comprehensive test suite -- All 7 tests passing -- KiCad CLI validation successful - ---- - -## [2.0.0-alpha] - 2025-11-05 - -### Router Pattern & Tool Organization - -**Major Architecture Change:** -- Implemented tool router pattern (70% context reduction) -- 12 direct tools, 47 routed tools in 7 categories -- Smart tool discovery system - -**New Router Tools:** -- `list_tool_categories` - Browse available categories -- `get_category_tools` - View tools in category -- `search_tools` - Find tools by keyword -- `execute_tool` - Run any routed tool - -**Benefits:** -- Dramatically reduced AI context usage -- Maintained full functionality (64 tools) -- Improved tool discoverability -- Better organization for users - ---- - -## [2.0.0-alpha] - 2025-11-01 - -### IPC Backend Integration - -**Experimental Feature:** -- KiCad 9.0 IPC API integration for real-time UI sync -- Changes appear immediately in KiCad (no manual reload) -- Hybrid backend: IPC + SWIG fallback -- 20+ commands with IPC support - -**Implementation:** -- Routing operations (interactive push-and-shove) -- Component placement and modification -- Zone operations and fills -- DRC and verification - -**Status:** -- Under active development -- Enable via KiCad: Preferences > Plugins > Enable IPC API Server -- Automatic fallback to SWIG when IPC unavailable - ---- - -## [2.0.0-alpha] - 2025-10-26 - -### Initial JLCPCB Integration (Local Libraries) - -**Features:** -- Local JLCPCB symbol library search -- Integration with KiCad Plugin and Content Manager -- Search by LCSC part number, manufacturer, description - -**Credit:** -- Contributed by [@l3wi](https://github.com/l3wi) - -**Components:** -- `python/commands/symbol_library.py` -- Basic library search functionality - ---- - -## [1.0.0] - 2025-10-01 - -### Initial Release - -**Core Features:** -- 64 fully-documented MCP tools -- JSON Schema validation for all tools -- 8 dynamic resources for project state -- Cross-platform support (Linux, Windows, macOS) -- Comprehensive error handling -- Detailed logging - -**Tool Categories:** -- Project Management (4 tools) -- Board Operations (9 tools) -- Component Management (8 tools) -- Routing (6 tools) -- Export & Manufacturing (5 tools) -- Design Rule Checking (4 tools) -- Schematic Operations (6 tools) -- Symbol Library (3 tools) -- JLCPCB Integration (5 tools) - -**Platform Support:** -- Linux (KiCad 7.x, 8.x, 9.x) -- Windows (KiCad 9.x) -- macOS (KiCad 9.x) - -**Documentation:** -- Complete README with setup instructions -- Platform-specific guides -- Tool reference documentation -- Contributing guidelines - ---- - -## Version Numbering - -- **2.1.0-alpha**: Current development version with JLCPCB integration -- **2.0.0-alpha**: Router pattern and IPC backend -- **1.0.0**: Initial stable release - -## Breaking Changes - -### 2.1.0-alpha -- None (additive changes only) - -### 2.0.0-alpha -- Tool execution now requires router for 47 tools -- Direct tool access limited to 12 high-frequency tools -- Schema validation stricter (catches errors earlier) - -## Deprecations - -### 2.1.0-alpha -- `docs/JLCPCB_USAGE_GUIDE.md` - Superseded by `docs/JLCPCB_INTEGRATION.md` -- `docs/JLCPCB_INTEGRATION_PLAN.md` - Implementation complete - -## Migration Guide - -### Upgrading to 2.1.0-alpha from 2.0.0-alpha - -**New Dependencies:** -- No new system dependencies -- Python packages: `requests` (already in requirements.txt) - -**Database Setup:** -1. Run `download_jlcpcb_database` tool (one-time, ~5-10 minutes) -2. Database created at `data/jlcpcb_parts.db` -3. Subsequent searches use local database (instant) - -**API Changes:** -- All existing tools remain compatible -- 5 new JLCPCB tools available -- No breaking changes to existing functionality - -### Upgrading to 2.0.0-alpha from 1.0.0 - -**Router Pattern:** -- Some tools now accessed via `execute_tool` instead of direct calls -- Use `list_tool_categories` to discover available tools -- Search with `search_tools` to find specific functionality - -**IPC Backend (Optional):** -- Enable in KiCad: Preferences > Plugins > Enable IPC API Server -- Set `KICAD_BACKEND=ipc` environment variable -- Falls back to SWIG if unavailable - ---- - -## Credits - -- **JLCSearch API**: [@tscircuit](https://github.com/tscircuit/jlcsearch) -- **JLCParts Database**: [@yaqwsx](https://github.com/yaqwsx/jlcparts) -- **Local JLCPCB Search**: [@l3wi](https://github.com/l3wi) -- **KiCad**: KiCad Development Team -- **MCP Protocol**: Anthropic - -## License - -See LICENSE file for details. +# Changelog + +All notable changes to the KiCAD MCP Server project are documented here. + +## [2.2.3] - 2026-03-11 + +### Merged: PR #57 (Kletternaut/demo/rpiCSI-videotest → main) + +This release incorporates 28 commits developed and live-tested during a full +Raspberry Pi CSI adapter PCB design session. All tools listed below were validated +end-to-end using Claude Desktop + KiCAD 9 on Windows. + +### New MCP Tools + +- `connect_passthrough` — Schematic-only tool that wires all pins of one connector + directly to the matching pins of another (e.g. J1 pin N → J2 pin N). Creates nets + named with a configurable prefix (`netPrefix`). Designed for FFC/ribbon cable + passthrough adapters. **Schematic only — do not call for PCB routing.** + +- `sync_schematic_to_board` — Imports all net/pad assignments from the schematic + into the open PCB file. Required after `connect_passthrough` before routing can + start. Returns `pads_assigned` count for verification. + +- `snapshot_project` — Saves a named checkpoint of the entire project folder into a + `snapshots/` subdirectory inside the project. Allows resuming from a known-good + state without redoing earlier steps. Accepts `step`, `label`, and optional `prompt` + parameters. + +- `run_erc` — Runs KiCAD's Electrical Rules Check on the schematic and returns + violations as structured JSON. + +- `import_svg_logo` — Converts an SVG file to PCB silkscreen polygons and places + them on a specified layer. + +### Bug Fixes + +- `route_pad_to_pad`: **Critical fix for B.Cu footprints in KiCAD 9.** `pad.GetLayerName()` + always returned `F.Cu` for SMD pads on flipped footprints (KiCAD 9 SWIG bug). + Fix: use `footprint.GetLayer()` instead, which correctly reflects the placed layer + after `Flip()`. Without this fix, no vias were inserted for back-to-back connectors. + +- `route_pad_to_pad`: Via was placed at the geometric midpoint between the two pads. + For back-to-back mirrored connectors (J1 F.Cu / J2 B.Cu) this caused all 15 vias + to stack at the same X coordinate (board center). Fix: via is now placed at the + X coordinate of the start pad (`via_x = start_pos.x`), producing 15 parallel + vertical traces. + +- `place_component` (B.Cu footprints): `Flip()` was called before `board.Add()`, + causing KiCAD 9 to hang for ~30 seconds. Fix: `board.Add()` first, then `Flip()`. + +- `add_board_outline`: Three separate bugs fixed — incorrect cornerRadius fallback, + wrong top-left origin default, and broken arc delegation for IPC rounded rectangles. + +- `snapshot_project`: Snapshots were saved one level above the project directory, + cluttering the parent folder. Fix: snapshots now go into `/snapshots/`. + +- MCP server log timestamp was always UTC/ISO. Fix: now uses local system time. + +- `search_tools` (router pattern): direct tools like `snapshot_project` were invisible + to the router. Fix: direct tool names added to the router's known-tool list. + +### Developer Mode (`KICAD_MCP_DEV=1`) + +Set the environment variable `KICAD_MCP_DEV=1` in your Claude Desktop config to +enable developer features: + +```json +"env": { + "KICAD_MCP_DEV": "1" +} +``` + +**What it does:** + +- `export_gerber` automatically copies the current MCP session log into the project's + `logs/` subdirectory as `mcp_log_.txt`. +- `snapshot_project` copies the MCP session log into `logs/` at every checkpoint as + `mcp_log_step_.txt`. +- If a `prompt` parameter is passed to `snapshot_project`, it is saved as + `PROMPT_step_.md` alongside the log. + +**Purpose:** Makes it easy to include the full tool call history when filing a bug +report or GitHub issue — just attach the log file from the project's `logs/` folder. + +> ⚠️ **Privacy warning:** The MCP session log contains the **complete conversation +> history** between Claude and the MCP server, including all tool parameters and +> responses. When sharing a project directory (e.g. as a ZIP attachment in a GitHub +> issue), **review or delete the `logs/` folder first** to avoid accidentally +> disclosing sensitive file paths, component names, or design details. + +### Snapshot Logging (always active) + +Regardless of dev mode, `snapshot_project` now always saves a copy of the current +MCP session log into `/logs/` at each checkpoint. This means every project +automatically retains a traceable record of which tools were called and in what order. + +> ⚠️ **Same privacy note applies:** the `logs/` directory inside your project folder +> contains tool call history. Do not share it publicly without reviewing its contents. + +--- + +## [2.2.2-alpha] - 2026-03-01 + +### New MCP Tools + +- `route_pad_to_pad` – Convenience wrapper around `route_trace` that looks up pad positions + automatically. Accepts `fromRef`/`fromPad`/`toRef`/`toPad` instead of raw XY coordinates. + Auto-detects net from pad assignment (overridable via `net` param). Saves ~2 tool calls per + connection (~64 calls for a full TMC2209 board compared to the 3-step get_pad_position flow). + Live tested: ESP32 ↔ TMC2209 STEP/DIR traces routed without prior coordinate lookup. ✅ + +- `copy_routing_pattern` – Now registered as MCP tool in TypeScript layer (`routing.ts`). + Was previously implemented in Python but missing from the MCP tool registry. + Parameters: `sourceRefs`, `targetRefs`, `includeVias?`, `traceWidth?`. + +### Bug Fixes + +- `add_schematic_component` / `DynamicSymbolLoader`: ignored project-local `sym-lib-table`. + `find_library_file()` only searched global KiCAD install directories, causing "library not + found" errors for any symbol in a project-local `.kicad_sym` file. Fix: added `project_path` + parameter; reads project `sym-lib-table` first via new `_resolve_library_from_table()` helper + before falling back to global dirs. `project_path` is auto-derived from the schematic path. + +- `place_component`: ignored project-local `fp-lib-table`. `FootprintLibraryManager` was + initialised once at server start without a project path, so self-created `.kicad_mod` + footprints were never found. Fix: new `boardPath` parameter in TypeScript + Python; + `_handle_place_component` wrapper recreates `FootprintLibraryManager(project_path=…)` whenever + the active project changes (cached to avoid redundant recreation). + +- `copy_routing_pattern`: copied 0 traces when pads had no net assignments. The filter + `track.GetNetname() in source_nets` always returned empty when pads were placed without net + assignment. Fix: geometric fallback using bounding box of source footprint pads ±5mm + tolerance. Response includes `filterMethod` field indicating which mode was used + (`"net-based"` or `"geometric (pads have no nets)"`). + +- `template_with_symbols.kicad_sch`, `template_with_symbols_expanded.kicad_sch`: restored + format version `20250114` (KiCAD 9) after upstream commit `2b38796` accidentally downgraded + both files to `20240101`. KiCAD 9 rejects schematics with outdated version numbers. + +- **CRITICAL: `template_with_symbols_expanded.kicad_sch`**: removed 7 invalid `;;` comment + lines introduced by upstream commit `b98c94b`. KiCAD's S-expression parser does not support + any comment syntax — it expects every non-empty, non-whitespace line to start with `(`. + The comments (`;; PASSIVES`, `;; SEMICONDUCTORS`, `;; INTEGRATED CIRCUITS`, `;; CONNECTORS`, + `;; POWER/REGULATORS`, `;; MISC`, `;; TEMPLATE INSTANCES (...)`) caused KiCAD 9 to reject + every schematic created from this template with a hard parse error: + + > `Expecting '(' in .kicad_sch, line 8, offset 5` + > **Action required for existing projects:** delete every line beginning with `;;` from any + > `.kicad_sch` file created between upstream commit `b98c94b` and this fix. + +- `add_schematic_component` / `inject_symbol_into_schematic`: symbol definition in + `lib_symbols` was never refreshed after editing via `create_symbol` / `edit_symbol`. + If the symbol was already present in the schematic's embedded `lib_symbols` section, + the function returned immediately — `delete + re-add` still pulled in the stale cached + definition. Fix: always read the current definition from the `.kicad_sym` file; if a + stale entry exists in `lib_symbols`, remove it first, then inject the fresh one. + Verified live. ✅ + +- `template_with_symbols_expanded.kicad_sch`: removed 13 legacy `_TEMPLATE_*` offscreen + instances (`_TEMPLATE_R`, `_TEMPLATE_C`, `_TEMPLATE_U`, etc.) that were placed at + `x=-100` as clone-sources for the old `ComponentManager` approach. `DynamicSymbolLoader` + (the current implementation) injects symbols directly and never needs these placeholders. + They appeared as dangling reference designators in KiCAD's component navigator and in + the schematic canvas when zoomed far out. + +### Maintenance + +- `.gitignore`: added `*.kicad_pcb.bak`, `*.kicad_pro.bak` alongside existing `-bak` variants; + consolidated personal/local files under `myContribution/`. + +--- + +## [2.2.1-alpha] - 2026-02-28 + +### New MCP Tools + +- `edit_schematic_component` – Update properties of a placed symbol in-place (footprint, + value, reference rename). More efficient than delete + re-add: preserves position and UUID. + +### Bug Fixes + +- `add_schematic_component`: `footprint` parameter was accepted but silently ignored – the + value was never passed through to `DynamicSymbolLoader.add_component()` / + `create_component_instance()`. All newly placed symbols always had an empty Footprint + field. Fix: added `footprint: str = ""` to both functions and threaded it through every + call site including the TypeScript tool schema. + +- `delete_schematic_component`: only deleted the first matching instance when duplicate + references existed (e.g. after an aborted add attempt). Root cause: loop used `break` + after the first match. Fix: collect all matching blocks first, then delete them all back- + to-front (to preserve line indices). Response now includes `deleted_count`. + +- `templates/*.kicad_sch`, `project.py`, `schematic.py`: Update KiCAD schematic format + version from `20230121` (KiCAD 7) to `20250114` (KiCAD 9). The MCP server targets + KiCAD 9 exclusively (`pcbnew.pyd` compiled for KiCAD 9.0, Python 3.11.5) – generating + files in an outdated format caused a spurious "This file was created with an older + KiCAD version" warning on every newly created schematic. + +- `template_with_symbols_expanded.kicad_sch`: Remove 13 corrupt `_TEMPLATE_*` placed-symbol + blocks with `(lib_id -100)` – an integer caused by old sexpdata serializer (same bug + PR #40 fixed for the add path). KiCAD crashed with a null-pointer when selecting these + symbols. They appeared as grey `_TEMPLATE_R?`, `_TEMPLATE_U_REG?` etc. labels far + outside the sheet boundary (~5000mm off-sheet). + + **Discovered via:** live testing on a real JLCPCB/KiCAD 9 project. + **Affected users:** schematics created from this template before this fix contain the + same corrupt blocks – remove all `(symbol (lib_id -100) ...)` blocks whose Reference + starts with `_TEMPLATE_`. + +--- + +--- + +## [2.2.0-alpha] - 2026-02-27 + +### New MCP Tools (TypeScript layer – previously Python-only) + +**Routing tools:** + +- `delete_trace` - Delete traces by UUID, position or net name +- `query_traces` - Query/filter traces on the board +- `get_nets_list` - List all nets with net code and class +- `modify_trace` - Modify trace width or layer +- `create_netclass` - Create or update a net class +- `route_differential_pair` - Route a differential pair between two points +- `refill_zones` - Refill all copper zones ⚠️ SWIG segfault risk, prefer IPC/UI + +**Component tools:** + +- `get_component_pads` - Get all pad data for a component +- `get_component_list` - List all components on the board +- `get_pad_position` - Get absolute position of a specific pad +- `place_component_array` - Place components in a grid array +- `align_components` - Align components along an axis +- `duplicate_component` - Duplicate a component with offset + +### Bug Fixes + +- `routing.py`: Fix SwigPyObject UUID comparison (`str()` → `m_Uuid.AsString()`) +- `routing.py`: Fix SWIG iterator invalidation after `board.Remove()` by snapshotting `list(board.Tracks())` +- `routing.py`: Add `board.SetModified()` + `track = None` after `Remove()` to prevent dangling SWIG pointer crashes +- `routing.py`: Per-track `try/except` in `query_traces()` to skip invalid objects after bulk delete +- `routing.py`: Add missing return statement (mypy) +- `library.py`: Fix `search_footprints` parameter mapping (`search_term` → `pattern`) +- `library.py`: Fix field access (`fp.name` → `fp.full_name`) +- `library.py`: Accept both `pattern` and `search_term` parameter names +- `library.py`: Fix loop variable shadowing `Path` object (mypy) +- `design_rules.py`: Add type annotation for `violation_counts` (mypy) + +### New MCP Tools (cont.) + +**Datasheet tools:** + +- `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`). + No API key required – URL is constructed directly from the LCSC number. +- `enrich_datasheets` - Scan a `.kicad_sch` file and write LCSC datasheet URLs into + every symbol that has an `LCSC` property but an empty `Datasheet` field. After + enrichment the URL appears natively in KiCAD's symbol properties, footprint browser + and any other tool that reads the standard KiCAD `Datasheet` field. + Supports `dry_run=true` for preview without writing. + Implementation: `python/commands/datasheet_manager.py` (text-based, no `skip` writes) + +**Schematic tools:** + +- `delete_schematic_component` - Remove a placed symbol from a `.kicad_sch` file by + reference designator (e.g. `R1`, `U3`). + +### Bug Fixes (cont.) + +- `schematic.ts` / `kicad_interface.py`: Fix missing `delete_schematic_component` MCP tool. + + **Root cause (two separate issues):** + 1. No MCP tool named `delete_schematic_component` existed. Claude had no way to call + it, so any "delete schematic component" request fell through to the PCB-only + `delete_component` tool, which searches `pcbnew.BOARD` and always returned + "Component not found" for schematic symbols. + 2. `component_schematic.py::remove_component()` still used `skip` for writes. + PR #40 rewrote `DynamicSymbolLoader` (add path) to avoid `skip`-induced schematic + corruption, but `remove_component` (delete path) was not touched by that PR. + + **Fix:** + - Added `delete_schematic_component` to the TypeScript tool layer (`schematic.ts`) + with clear docstring distinguishing it from the PCB `delete_component`. + - Implemented `_handle_delete_schematic_component` in `kicad_interface.py` using + direct text manipulation (parenthesis-depth tracking, same approach as PR #40). + Does not call `component_schematic.py::remove_component()` at all. + - Error message explicitly guides the user when the wrong tool is used: + _"note: this tool removes schematic symbols, use delete_component for PCB footprints"_ + +### Additional Bug Fixes + +- `connection_schematic.py` / `kicad_interface.py`: Fix `generate_netlist` missing + `schematic_path` parameter – without it `get_net_connections` always fell back to + proximity matching which only returns one connection per component (first wire hit, + then `break`). PinLocator was never invoked. Fix: added `schematic_path: Optional[Path]` + to `generate_netlist` signature and threaded it through to `get_net_connections`, + and updated `_handle_generate_netlist` in `kicad_interface.py` to pass `schematic_path`. +- `server.ts`: Fix KiCAD bundled Python (3.11.5) not being selected on Windows – the + detection condition `process.env.PYTHONPATH?.includes("KiCad")` was fragile and failed + in some environments, causing System Python 3.12 to be used instead. Since `pcbnew.pyd` + is compiled for KiCAD's Python 3.11.5, this resulted in `No module named 'pcbnew'`. + Fix: removed the condition, KiCAD bundled Python is now always preferred on Windows + when it exists at `C:\Program Files\KiCad\9.0\bin\python.exe`. + Also added `KICAD_PYTHON` to `claude_desktop_config.json` as explicit override. +- `pin_locator.py`: Fix `generate_netlist` timeout – `get_pin_location` and + `get_all_symbol_pins` called `Schematic(schematic_path)` on every single pin lookup, + causing O(nets × components × pins) schematic file loads (e.g. 400+ loads for a + medium schematic). Fix: added `_schematic_cache` dict to `PinLocator.__init__`, + schematic is now loaded once per path and reused. + +--- + +## [2.1.0-alpha] - 2026-01-10 + +### Phase 1: Intelligent Schematic Wiring System - Core Infrastructure + +**Major Features:** + +- Automatic pin location discovery with rotation support +- Smart wire routing (direct, orthogonal horizontal/vertical) +- Net label management (local, global, hierarchical) +- S-expression-based wire creation +- Professional right-angle routing + +**New Components:** + +- `python/commands/wire_manager.py` - S-expression wire creation engine +- `python/commands/pin_locator.py` - Intelligent pin discovery with rotation +- Updated `python/commands/connection_schematic.py` - High-level connection API +- `docs/SCHEMATIC_WIRING_PLAN.md` - Implementation roadmap + +**MCP Tools Enhanced:** + +- `add_schematic_wire` - Create wires with stroke customization +- `add_schematic_connection` - Auto-connect pins with routing options (NEW) +- `add_schematic_net_label` - Add labels with type and orientation control (NEW) +- `connect_to_net` - Connect pins to named nets (ENHANCED) + +**Technical Implementation:** + +- Rotation transformation matrix for pin coordinates +- S-expression injection for guaranteed format compliance +- Pin definition caching for performance +- Orthogonal path generation for professional schematics + +**Testing:** + +- End-to-end integration test: 100% passing +- MCP handler integration test: 100% passing +- Pin discovery with rotation: Verified working +- KiCad-skip verification: All wires/labels correctly formed + +--- + +### Phase 2: Power Nets & Wire Connectivity - COMPLETE + +**Major Features:** + +- Power symbol support (VCC, GND, +3V3, +5V, etc.) via dynamic loading +- Wire graph analysis for net connectivity tracking +- Geometric wire tracing with tolerance-based point matching +- Accurate netlist generation with component/pin connections +- Critical template mapping bug fixes + +**Updates:** + +- `connect_to_net()` - Migrated to WireManager + PinLocator +- `get_net_connections()` - Complete rewrite with geometric wire tracing +- `generate_netlist()` - Now uses wire graph analysis for connectivity +- `get_or_create_template()` - Fixed special character handling, auto-reload after dynamic loading +- `add_component()` - Fixed template lookup with symbol iteration + +**Bug Fixes:** + +- CRITICAL: Template mapping after dynamic symbol loading +- Special character handling in symbol names (+ prefix in +3V3, +5V) +- Schematic reload synchronization after S-expression injection +- Multi-format template reference detection + +**Wire Graph Analysis Algorithm:** + +1. Find all labels matching target net name +2. Trace wires connected to label positions (point coincidence) +3. Collect all wire endpoints and polyline segments +4. Match component pins at wire connection points using PinLocator +5. Return accurate component/pin connection pairs + +**Technical Implementation:** + +- Tolerance-based point matching (0.5mm for grid alignment) +- Multi-segment wire (polyline) support +- Rotation-aware pin location matching via PinLocator +- Fallback proximity detection (10mm threshold) +- Template existence checking via symbol iteration (handles special characters) + +**Testing:** + +- Power symbols: 4/4 loaded (VCC, GND, +3V3, +5V) +- Components: 4/4 placed +- Connections: 8/8 created successfully +- Net connectivity: 100% accurate (VCC: 2, GND: 4, +3V3: 1, +5V: 1) +- Netlist generation: 4 nets with accurate connections +- Comprehensive integration test: 100% PASSING + +**Commits:** + +- `c67f400` - Updated connect_to_net to use WireManager +- `b77f008` - Fixed template mapping bug (critical) +- `a5a542b` - Implemented wire graph analysis + +**Addresses:** + +- Issue #26 - Schematic workflow wiring functionality (Phase 2) + +--- + +### Phase 2: JLCPCB Integration Complete + +**Major Features:** + +- ✅ Complete JLCPCB parts integration via JLCSearch public API +- ✅ Access to ~100k JLCPCB parts catalog +- ✅ Real-time stock and pricing data +- ✅ Parametric component search +- ✅ Cost optimization (Basic vs Extended library) +- ✅ KiCad footprint mapping +- ✅ Alternative part suggestions + +**New Components:** + +- `python/commands/jlcsearch.py` - JLCSearch API client (no auth required) +- `python/commands/jlcpcb_parts.py` - Enhanced with `import_jlcsearch_parts()` +- `docs/JLCPCB_INTEGRATION.md` - Comprehensive integration guide + +**MCP Tools Available:** + +- `download_jlcpcb_database` - Download full parts catalog +- `search_jlcpcb_parts` - Parametric search with filters +- `get_jlcpcb_part` - Part details + footprint suggestions +- `get_jlcpcb_database_stats` - Database statistics +- `suggest_jlcpcb_alternatives` - Find similar/cheaper parts + +**Technical Improvements:** + +- SQLite database with full-text search (FTS5) +- Package-to-footprint mapping for standard SMD packages +- Price comparison and cost optimization algorithms +- HMAC-SHA256 authentication support (for official JLCPCB API) + +**Testing:** + +- All integration tests passing +- Database operations validated +- Live API connectivity confirmed +- End-to-end MCP tool testing complete + +**Documentation:** + +- Complete API reference with examples +- Package mapping tables (0402, 0603, 0805, SOT-23, etc.) +- Best practices guide +- Troubleshooting section + +--- + +## [2.1.0-alpha] - 2025-11-30 + +### Phase 1: Schematic Workflow Fix + +**Critical Bug Fix:** + +- ✅ Fixed completely broken schematic workflow (Issue #26) +- Created template-based symbol cloning approach +- All schematic tests now passing + +**Root Cause:** + +- kicad-skip library limitation: cannot create symbols from scratch, only clone existing ones + +**Solution:** + +- Template schematic with cloneable R, C, LED symbols +- Updated `create_project` to create both PCB and schematic +- Rewrote `add_schematic_component` to use `clone()` API +- Proper UUID generation and position setting + +**Files Modified:** + +- `python/commands/project.py` - Now creates schematic files +- `python/commands/schematic.py` - Uses template approach +- `python/commands/component_schematic.py` - Complete rewrite + +**Files Created:** + +- `python/templates/template_with_symbols.kicad_sch` +- `python/templates/empty.kicad_sch` +- `docs/SCHEMATIC_WORKFLOW_FIX.md` + +**Testing:** + +- Created comprehensive test suite +- All 7 tests passing +- KiCad CLI validation successful + +--- + +## [2.0.0-alpha] - 2025-11-05 + +### Router Pattern & Tool Organization + +**Major Architecture Change:** + +- Implemented tool router pattern (70% context reduction) +- 12 direct tools, 47 routed tools in 7 categories +- Smart tool discovery system + +**New Router Tools:** + +- `list_tool_categories` - Browse available categories +- `get_category_tools` - View tools in category +- `search_tools` - Find tools by keyword +- `execute_tool` - Run any routed tool + +**Benefits:** + +- Dramatically reduced AI context usage +- Maintained full functionality (64 tools) +- Improved tool discoverability +- Better organization for users + +--- + +## [2.0.0-alpha] - 2025-11-01 + +### IPC Backend Integration + +**Experimental Feature:** + +- KiCad 9.0 IPC API integration for real-time UI sync +- Changes appear immediately in KiCad (no manual reload) +- Hybrid backend: IPC + SWIG fallback +- 20+ commands with IPC support + +**Implementation:** + +- Routing operations (interactive push-and-shove) +- Component placement and modification +- Zone operations and fills +- DRC and verification + +**Status:** + +- Under active development +- Enable via KiCad: Preferences > Plugins > Enable IPC API Server +- Automatic fallback to SWIG when IPC unavailable + +--- + +## [2.0.0-alpha] - 2025-10-26 + +### Initial JLCPCB Integration (Local Libraries) + +**Features:** + +- Local JLCPCB symbol library search +- Integration with KiCad Plugin and Content Manager +- Search by LCSC part number, manufacturer, description + +**Credit:** + +- Contributed by [@l3wi](https://github.com/l3wi) + +**Components:** + +- `python/commands/symbol_library.py` +- Basic library search functionality + +--- + +## [1.0.0] - 2025-10-01 + +### Initial Release + +**Core Features:** + +- 64 fully-documented MCP tools +- JSON Schema validation for all tools +- 8 dynamic resources for project state +- Cross-platform support (Linux, Windows, macOS) +- Comprehensive error handling +- Detailed logging + +**Tool Categories:** + +- Project Management (4 tools) +- Board Operations (9 tools) +- Component Management (8 tools) +- Routing (6 tools) +- Export & Manufacturing (5 tools) +- Design Rule Checking (4 tools) +- Schematic Operations (6 tools) +- Symbol Library (3 tools) +- JLCPCB Integration (5 tools) + +**Platform Support:** + +- Linux (KiCad 7.x, 8.x, 9.x) +- Windows (KiCad 9.x) +- macOS (KiCad 9.x) + +**Documentation:** + +- Complete README with setup instructions +- Platform-specific guides +- Tool reference documentation +- Contributing guidelines + +--- + +## Version Numbering + +- **2.1.0-alpha**: Current development version with JLCPCB integration +- **2.0.0-alpha**: Router pattern and IPC backend +- **1.0.0**: Initial stable release + +## Breaking Changes + +### 2.1.0-alpha + +- None (additive changes only) + +### 2.0.0-alpha + +- Tool execution now requires router for 47 tools +- Direct tool access limited to 12 high-frequency tools +- Schema validation stricter (catches errors earlier) + +## Deprecations + +### 2.1.0-alpha + +- `docs/JLCPCB_USAGE_GUIDE.md` - Superseded by `docs/JLCPCB_INTEGRATION.md` +- `docs/JLCPCB_INTEGRATION_PLAN.md` - Implementation complete + +## Migration Guide + +### Upgrading to 2.1.0-alpha from 2.0.0-alpha + +**New Dependencies:** + +- No new system dependencies +- Python packages: `requests` (already in requirements.txt) + +**Database Setup:** + +1. Run `download_jlcpcb_database` tool (one-time, ~5-10 minutes) +2. Database created at `data/jlcpcb_parts.db` +3. Subsequent searches use local database (instant) + +**API Changes:** + +- All existing tools remain compatible +- 5 new JLCPCB tools available +- No breaking changes to existing functionality + +### Upgrading to 2.0.0-alpha from 1.0.0 + +**Router Pattern:** + +- Some tools now accessed via `execute_tool` instead of direct calls +- Use `list_tool_categories` to discover available tools +- Search with `search_tools` to find specific functionality + +**IPC Backend (Optional):** + +- Enable in KiCad: Preferences > Plugins > Enable IPC API Server +- Set `KICAD_BACKEND=ipc` environment variable +- Falls back to SWIG if unavailable + +--- + +## Credits + +- **JLCSearch API**: [@tscircuit](https://github.com/tscircuit/jlcsearch) +- **JLCParts Database**: [@yaqwsx](https://github.com/yaqwsx/jlcparts) +- **Local JLCPCB Search**: [@l3wi](https://github.com/l3wi) +- **KiCad**: KiCad Development Team +- **MCP Protocol**: Anthropic + +## License + +See LICENSE file for details. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f4f204..2415801 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,414 +1,418 @@ -# Contributing to KiCAD MCP Server - -Thank you for your interest in contributing to the KiCAD MCP Server! This guide will help you get started with development. - -## Table of Contents - -- [Development Environment Setup](#development-environment-setup) -- [Project Structure](#project-structure) -- [Architecture Overview](#architecture-overview) -- [Development Workflow](#development-workflow) -- [Testing](#testing) -- [Code Style](#code-style) -- [Pull Request Process](#pull-request-process) -- [Roadmap & Planning](#roadmap--planning) - ---- - -## Development Environment Setup - -### Prerequisites - -- **KiCAD 9.0 or higher** - [Download here](https://www.kicad.org/download/) -- **Node.js v18+** - [Download here](https://nodejs.org/) -- **Python 3.10+** - Should come with KiCAD, or install separately -- **Git** - For version control - -### Platform-Specific Setup - -#### Linux (Ubuntu/Debian) - -```bash -# Install KiCAD 9.0 from official PPA -sudo add-apt-repository --yes ppa:kicad/kicad-9.0-releases -sudo apt-get update -sudo apt-get install -y kicad kicad-libraries - -# Install Node.js (if not already installed) -curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - -sudo apt-get install -y nodejs - -# Clone the repository -git clone https://github.com/yourusername/kicad-mcp-server.git -cd kicad-mcp-server - -# Install Node.js dependencies -npm install - -# Install Python dependencies -pip3 install -r requirements-dev.txt - -# Build TypeScript -npm run build - -# Run tests -npm test -pytest -``` - -#### Windows - -```powershell -# Install KiCAD 9.0 from https://www.kicad.org/download/windows/ - -# Install Node.js from https://nodejs.org/ - -# Clone the repository -git clone https://github.com/yourusername/kicad-mcp-server.git -cd kicad-mcp-server - -# Install Node.js dependencies -npm install - -# Install Python dependencies -pip install -r requirements-dev.txt - -# Build TypeScript -npm run build - -# Run tests -npm test -pytest -``` - -#### macOS - -```bash -# Install KiCAD 9.0 from https://www.kicad.org/download/macos/ - -# Install Node.js via Homebrew -brew install node - -# Clone the repository -git clone https://github.com/yourusername/kicad-mcp-server.git -cd kicad-mcp-server - -# Install Node.js dependencies -npm install - -# Install Python dependencies -pip3 install -r requirements-dev.txt - -# Build TypeScript -npm run build - -# Run tests -npm test -pytest -``` - ---- - -## Project Structure - -``` -kicad-mcp-server/ -├── .github/ -│ └── workflows/ # CI/CD pipelines -├── config/ # Configuration examples -│ ├── linux-config.example.json -│ ├── windows-config.example.json -│ └── macos-config.example.json -├── docs/ # Documentation -├── python/ # Python interface layer -│ ├── commands/ # KiCAD command handlers -│ ├── integrations/ # External API integrations (JLCPCB, Digikey) -│ ├── utils/ # Utility modules -│ └── kicad_interface.py # Main Python entry point -├── src/ # TypeScript MCP server -│ ├── tools/ # MCP tool implementations -│ ├── resources/ # MCP resource implementations -│ ├── prompts/ # MCP prompt implementations -│ └── server.ts # Main server -├── tests/ # Test suite -│ ├── unit/ -│ ├── integration/ -│ └── fixtures/ -├── dist/ # Compiled JavaScript (generated) -├── node_modules/ # Node dependencies (generated) -├── package.json # Node.js configuration -├── tsconfig.json # TypeScript configuration -├── pytest.ini # Pytest configuration -├── requirements.txt # Python production dependencies -└── requirements-dev.txt # Python dev dependencies -``` - ---- - -## Architecture Overview - -The KiCAD MCP Server is organized into several key components: - -- **TypeScript MCP Server** (`src/`) - Handles MCP protocol communication and tool routing -- **Python KiCAD Interface** (`python/`) - Interfaces with KiCAD's Python API (pcbnew) -- **Tool Router** - Organizes 122+ tools into 8 discoverable categories -- **Resource System** - Provides dynamic project/board state information -- **Prompt System** - Offers context-aware design prompts - -**Current Tool Count:** 122+ tools across 8 categories (direct + routed) - -For detailed architecture information, see `docs/ROUTER_ARCHITECTURE.md`. - ---- - -## Development Workflow - -### 1. Create a Feature Branch - -```bash -git checkout -b feature/your-feature-name -``` - -### 2. Make Changes - -- Edit TypeScript files in `src/` -- Edit Python files in `python/` -- Add tests for new features - -### 3. Build & Test - -```bash -# Build TypeScript -npm run build - -# Run TypeScript linter -npm run lint - -# Run Python formatter -black python/ - -# Run Python type checker -mypy python/ - -# Run all tests -npm test -pytest - -# Run specific test file -pytest tests/test_platform_helper.py -v - -# Run with coverage -pytest --cov=python --cov-report=html -``` - -### 4. Commit Changes - -```bash -git add . -git commit -m "feat: Add your feature description" -``` - -**Commit Message Convention:** -- `feat:` - New feature -- `fix:` - Bug fix -- `docs:` - Documentation changes -- `test:` - Adding/updating tests -- `refactor:` - Code refactoring -- `chore:` - Maintenance tasks - -### 5. Push and Create Pull Request - -```bash -git push origin feature/your-feature-name -``` - -Then create a Pull Request on GitHub. - ---- - -## Testing - -### Running Tests - -```bash -# All tests -pytest - -# Unit tests only -pytest -m unit - -# Integration tests (requires KiCAD installed) -pytest -m integration - -# Platform-specific tests -pytest -m linux # Linux tests only -pytest -m windows # Windows tests only - -# With coverage report -pytest --cov=python --cov-report=term-missing - -# Verbose output -pytest -v - -# Stop on first failure -pytest -x -``` - -### Writing Tests - -Tests should be placed in `tests/` directory: - -```python -# tests/test_my_feature.py -import pytest - -@pytest.mark.unit -def test_my_feature(): - """Test description""" - # Arrange - expected = "result" - - # Act - result = my_function() - - # Assert - assert result == expected - -@pytest.mark.integration -@pytest.mark.linux -def test_linux_integration(): - """Integration test for Linux""" - # This test will only run on Linux in CI - pass -``` - ---- - -## Code Style - -### Python - -We use **Black** for code formatting and **MyPy** for type checking. - -```bash -# Format all Python files -black python/ - -# Check types -mypy python/ - -# Run linter -pylint python/ -``` - -**Python Style Guidelines:** -- Use type hints for all function signatures -- Use pathlib.Path for file paths (not os.path) -- Use descriptive variable names -- Add docstrings to all public functions/classes -- Follow PEP 8 - -**Example:** -```python -from pathlib import Path -from typing import List, Optional - -def find_kicad_libraries(search_path: Path) -> List[Path]: - """ - Find all KiCAD symbol libraries in the given path. - - Args: - search_path: Directory to search for .kicad_sym files - - Returns: - List of paths to found library files - - Raises: - ValueError: If search_path doesn't exist - """ - if not search_path.exists(): - raise ValueError(f"Search path does not exist: {search_path}") - - return list(search_path.glob("**/*.kicad_sym")) -``` - -### TypeScript - -We use **ESLint** and **Prettier** for TypeScript. - -```bash -# Format TypeScript files -npx prettier --write "src/**/*.ts" - -# Run linter -npx eslint src/ -``` - -**TypeScript Style Guidelines:** -- Use interfaces for data structures -- Use async/await for asynchronous code -- Use descriptive variable names -- Add JSDoc comments to exported functions - ---- - -## Pull Request Process - -1. **Update Documentation** - If you change functionality, update docs -2. **Add Tests** - All new features should have tests -3. **Run CI Locally** - Ensure all tests pass before pushing -4. **Create PR** - Use a clear, descriptive title -5. **Request Review** - Tag relevant maintainers -6. **Address Feedback** - Make requested changes -7. **Merge** - Maintainer will merge when approved - -### PR Checklist - -- [ ] Code follows style guidelines -- [ ] All tests pass locally -- [ ] New tests added for new features -- [ ] Documentation updated -- [ ] Commit messages follow convention -- [ ] No merge conflicts -- [ ] CI/CD pipeline passes - ---- - -## Roadmap & Planning - -We track work using GitHub Projects and Issues: - -- **GitHub Projects** - High-level roadmap and sprints -- **GitHub Issues** - Specific bugs and features -- **GitHub Discussions** - Design discussions and proposals - -### Current Priorities (Week 1-4) - -1. ✅ Linux compatibility fixes -2. ✅ Platform-agnostic path handling -3. ✅ CI/CD pipeline setup -4. 🔄 Migrate to KiCAD IPC API -5. ⏳ Add JLCPCB integration -6. ⏳ Add Digikey integration - -See [docs/REBUILD_PLAN.md](docs/REBUILD_PLAN.md) for the complete 12-week roadmap. - ---- - -## Getting Help - -- **GitHub Discussions** - Ask questions, propose ideas -- **GitHub Issues** - Report bugs, request features -- **Discord** - Real-time chat (link TBD) - ---- - -## License - -By contributing, you agree that your contributions will be licensed under the MIT License. - ---- - -## Thank You! 🎉 - -Your contributions make this project better for everyone. We appreciate your time and effort! +# Contributing to KiCAD MCP Server + +Thank you for your interest in contributing to the KiCAD MCP Server! This guide will help you get started with development. + +## Table of Contents + +- [Development Environment Setup](#development-environment-setup) +- [Project Structure](#project-structure) +- [Architecture Overview](#architecture-overview) +- [Development Workflow](#development-workflow) +- [Testing](#testing) +- [Code Style](#code-style) +- [Pull Request Process](#pull-request-process) +- [Roadmap & Planning](#roadmap--planning) + +--- + +## Development Environment Setup + +### Prerequisites + +- **KiCAD 9.0 or higher** - [Download here](https://www.kicad.org/download/) +- **Node.js v18+** - [Download here](https://nodejs.org/) +- **Python 3.10+** - Should come with KiCAD, or install separately +- **Git** - For version control + +### Platform-Specific Setup + +#### Linux (Ubuntu/Debian) + +```bash +# Install KiCAD 9.0 from official PPA +sudo add-apt-repository --yes ppa:kicad/kicad-9.0-releases +sudo apt-get update +sudo apt-get install -y kicad kicad-libraries + +# Install Node.js (if not already installed) +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt-get install -y nodejs + +# Clone the repository +git clone https://github.com/yourusername/kicad-mcp-server.git +cd kicad-mcp-server + +# Install Node.js dependencies +npm install + +# Install Python dependencies +pip3 install -r requirements-dev.txt + +# Build TypeScript +npm run build + +# Run tests +npm test +pytest +``` + +#### Windows + +```powershell +# Install KiCAD 9.0 from https://www.kicad.org/download/windows/ + +# Install Node.js from https://nodejs.org/ + +# Clone the repository +git clone https://github.com/yourusername/kicad-mcp-server.git +cd kicad-mcp-server + +# Install Node.js dependencies +npm install + +# Install Python dependencies +pip install -r requirements-dev.txt + +# Build TypeScript +npm run build + +# Run tests +npm test +pytest +``` + +#### macOS + +```bash +# Install KiCAD 9.0 from https://www.kicad.org/download/macos/ + +# Install Node.js via Homebrew +brew install node + +# Clone the repository +git clone https://github.com/yourusername/kicad-mcp-server.git +cd kicad-mcp-server + +# Install Node.js dependencies +npm install + +# Install Python dependencies +pip3 install -r requirements-dev.txt + +# Build TypeScript +npm run build + +# Run tests +npm test +pytest +``` + +--- + +## Project Structure + +``` +kicad-mcp-server/ +├── .github/ +│ └── workflows/ # CI/CD pipelines +├── config/ # Configuration examples +│ ├── linux-config.example.json +│ ├── windows-config.example.json +│ └── macos-config.example.json +├── docs/ # Documentation +├── python/ # Python interface layer +│ ├── commands/ # KiCAD command handlers +│ ├── integrations/ # External API integrations (JLCPCB, Digikey) +│ ├── utils/ # Utility modules +│ └── kicad_interface.py # Main Python entry point +├── src/ # TypeScript MCP server +│ ├── tools/ # MCP tool implementations +│ ├── resources/ # MCP resource implementations +│ ├── prompts/ # MCP prompt implementations +│ └── server.ts # Main server +├── tests/ # Test suite +│ ├── unit/ +│ ├── integration/ +│ └── fixtures/ +├── dist/ # Compiled JavaScript (generated) +├── node_modules/ # Node dependencies (generated) +├── package.json # Node.js configuration +├── tsconfig.json # TypeScript configuration +├── pytest.ini # Pytest configuration +├── requirements.txt # Python production dependencies +└── requirements-dev.txt # Python dev dependencies +``` + +--- + +## Architecture Overview + +The KiCAD MCP Server is organized into several key components: + +- **TypeScript MCP Server** (`src/`) - Handles MCP protocol communication and tool routing +- **Python KiCAD Interface** (`python/`) - Interfaces with KiCAD's Python API (pcbnew) +- **Tool Router** - Organizes 122+ tools into 8 discoverable categories +- **Resource System** - Provides dynamic project/board state information +- **Prompt System** - Offers context-aware design prompts + +**Current Tool Count:** 122+ tools across 8 categories (direct + routed) + +For detailed architecture information, see `docs/ROUTER_ARCHITECTURE.md`. + +--- + +## Development Workflow + +### 1. Create a Feature Branch + +```bash +git checkout -b feature/your-feature-name +``` + +### 2. Make Changes + +- Edit TypeScript files in `src/` +- Edit Python files in `python/` +- Add tests for new features + +### 3. Build & Test + +```bash +# Build TypeScript +npm run build + +# Run TypeScript linter +npm run lint + +# Run Python formatter +black python/ + +# Run Python type checker +mypy python/ + +# Run all tests +npm test +pytest + +# Run specific test file +pytest tests/test_platform_helper.py -v + +# Run with coverage +pytest --cov=python --cov-report=html +``` + +### 4. Commit Changes + +```bash +git add . +git commit -m "feat: Add your feature description" +``` + +**Commit Message Convention:** + +- `feat:` - New feature +- `fix:` - Bug fix +- `docs:` - Documentation changes +- `test:` - Adding/updating tests +- `refactor:` - Code refactoring +- `chore:` - Maintenance tasks + +### 5. Push and Create Pull Request + +```bash +git push origin feature/your-feature-name +``` + +Then create a Pull Request on GitHub. + +--- + +## Testing + +### Running Tests + +```bash +# All tests +pytest + +# Unit tests only +pytest -m unit + +# Integration tests (requires KiCAD installed) +pytest -m integration + +# Platform-specific tests +pytest -m linux # Linux tests only +pytest -m windows # Windows tests only + +# With coverage report +pytest --cov=python --cov-report=term-missing + +# Verbose output +pytest -v + +# Stop on first failure +pytest -x +``` + +### Writing Tests + +Tests should be placed in `tests/` directory: + +```python +# tests/test_my_feature.py +import pytest + +@pytest.mark.unit +def test_my_feature(): + """Test description""" + # Arrange + expected = "result" + + # Act + result = my_function() + + # Assert + assert result == expected + +@pytest.mark.integration +@pytest.mark.linux +def test_linux_integration(): + """Integration test for Linux""" + # This test will only run on Linux in CI + pass +``` + +--- + +## Code Style + +### Python + +We use **Black** for code formatting and **MyPy** for type checking. + +```bash +# Format all Python files +black python/ + +# Check types +mypy python/ + +# Run linter +pylint python/ +``` + +**Python Style Guidelines:** + +- Use type hints for all function signatures +- Use pathlib.Path for file paths (not os.path) +- Use descriptive variable names +- Add docstrings to all public functions/classes +- Follow PEP 8 + +**Example:** + +```python +from pathlib import Path +from typing import List, Optional + +def find_kicad_libraries(search_path: Path) -> List[Path]: + """ + Find all KiCAD symbol libraries in the given path. + + Args: + search_path: Directory to search for .kicad_sym files + + Returns: + List of paths to found library files + + Raises: + ValueError: If search_path doesn't exist + """ + if not search_path.exists(): + raise ValueError(f"Search path does not exist: {search_path}") + + return list(search_path.glob("**/*.kicad_sym")) +``` + +### TypeScript + +We use **ESLint** and **Prettier** for TypeScript. + +```bash +# Format TypeScript files +npx prettier --write "src/**/*.ts" + +# Run linter +npx eslint src/ +``` + +**TypeScript Style Guidelines:** + +- Use interfaces for data structures +- Use async/await for asynchronous code +- Use descriptive variable names +- Add JSDoc comments to exported functions + +--- + +## Pull Request Process + +1. **Update Documentation** - If you change functionality, update docs +2. **Add Tests** - All new features should have tests +3. **Run CI Locally** - Ensure all tests pass before pushing +4. **Create PR** - Use a clear, descriptive title +5. **Request Review** - Tag relevant maintainers +6. **Address Feedback** - Make requested changes +7. **Merge** - Maintainer will merge when approved + +### PR Checklist + +- [ ] Code follows style guidelines +- [ ] All tests pass locally +- [ ] New tests added for new features +- [ ] Documentation updated +- [ ] Commit messages follow convention +- [ ] No merge conflicts +- [ ] CI/CD pipeline passes + +--- + +## Roadmap & Planning + +We track work using GitHub Projects and Issues: + +- **GitHub Projects** - High-level roadmap and sprints +- **GitHub Issues** - Specific bugs and features +- **GitHub Discussions** - Design discussions and proposals + +### Current Priorities (Week 1-4) + +1. ✅ Linux compatibility fixes +2. ✅ Platform-agnostic path handling +3. ✅ CI/CD pipeline setup +4. 🔄 Migrate to KiCAD IPC API +5. ⏳ Add JLCPCB integration +6. ⏳ Add Digikey integration + +See [docs/REBUILD_PLAN.md](docs/REBUILD_PLAN.md) for the complete 12-week roadmap. + +--- + +## Getting Help + +- **GitHub Discussions** - Ask questions, propose ideas +- **GitHub Issues** - Report bugs, request features +- **Discord** - Real-time chat (link TBD) + +--- + +## License + +By contributing, you agree that your contributions will be licensed under the MIT License. + +--- + +## Thank You! 🎉 + +Your contributions make this project better for everyone. We appreciate your time and effort! diff --git a/README.md b/README.md index 1c88ddb..4f284fc 100644 --- a/README.md +++ b/README.md @@ -1,988 +1,1047 @@ -# Discussions. Get in here. -https://github.com/mixelpixx/KiCAD-MCP-Server/discussions/73 - - -# KiCAD MCP Server - -A Model Context Protocol (MCP) server that enables AI assistants like Claude to interact with KiCAD for PCB design automation. Built on the MCP 2025-06-18 specification, this server provides comprehensive tool schemas and real-time project state access for intelligent PCB design workflows. - -## Overview - -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:** -- 122 tools across 16 categories with JSON Schema validation -- Smart tool discovery with router pattern (reduces AI context by 70%) -- 8 dynamic resources exposing project state -- Complete schematic workflow with 27 tools and dynamic symbol loading (~10,000 symbols) -- Freerouting autorouter integration (Java, Docker, or Podman) -- Custom footprint and symbol creation tools -- JLCPCB parts integration with 2.5M+ component catalog and local library search -- Datasheet enrichment via LCSC -- Full MCP 2025-06-18 protocol compliance -- Cross-platform support (Linux, Windows, macOS) -- Real-time KiCAD UI integration via IPC API (experimental) -- Comprehensive error handling and logging - - - -## Try out Arduino MCP - now you can get Claude to help in the IDE, real time!: -https://github.com/mixelpixx/arduino-ide - - - - - -## What's New in v2.2.3 - -### New Tools: FFC/Ribbon Cable Passthrough Workflow - -A complete workflow for designing passthrough adapter boards (e.g. Raspberry Pi CSI -cable adapters) is now supported: - -1. `connect_passthrough` — wires all pins of one connector to the matching pins of - another in the schematic (J1 pin N → J2 pin N, auto-named nets). -2. `sync_schematic_to_board` — imports the net assignments into the PCB. -3. `route_pad_to_pad` — routes each connection with automatic via insertion when - pads are on opposite copper layers. -4. `snapshot_project` — saves a named checkpoint into `/snapshots/`. - -### Bug Fixes (KiCAD 9 / Windows) - -- **Via insertion for B.Cu footprints** — `route_pad_to_pad` now correctly detects - when a footprint is on B.Cu and inserts the required via. (KiCAD 9 SWIG returned - `F.Cu` for all SMD pads regardless of layer — fixed.) -- **Board outline rounded corners** — `add_board_outline` now correctly applies - `cornerRadius` when `shape="rounded_rectangle"`. -- **B.Cu placement hang** — placing a footprint on B.Cu no longer causes a ~30s - freeze in KiCAD 9. - -### Developer Mode - -Set `KICAD_MCP_DEV=1` in your Claude Desktop MCP environment to automatically save -the MCP session log into the project's `logs/` folder on every `export_gerber` and -`snapshot_project` call. Useful for debugging and for attaching to GitHub issues. - -```json -"env": { - "KICAD_MCP_DEV": "1" -} -``` - -> **Privacy warning:** The session log contains your full tool call history -> (including file paths and design details). **Review or delete `logs/` before -> sharing a project directory publicly.** - -See [CHANGELOG](CHANGELOG.md) for the full list of changes in this release. - ---- - -## What's New in v2.1.0 - -### 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!** - -**What was broken:** -- `create_project` only created PCB files, no schematics -- `add_schematic_component` called non-existent API methods -- Schematics couldn't be created or edited at all -- Only 13 component types available (severe limitation) -- No working wire/connection functionality - -**Complete Implementation (3 Phases):** - -**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 - - Rewrote component placement to use proper `clone()` API - -**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 - - Zero configuration required - just specify library and symbol name - - Seamless integration with existing MCP tools - - Full S-expression parsing and injection system - -**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) - - **Power symbol support** (VCC, GND, +3V3, +5V, etc.) - - **Wire graph analysis** - geometric tracing for net connectivity - - **Net label management** (local, global, hierarchical labels) - - **Netlist generation** with accurate component/pin connections - -**Technical Architecture:** -The kicad-skip library cannot create symbols or wires from scratch. We implemented a comprehensive solution: - -1. **Static Templates:** 13 pre-configured symbols (R, C, L, LED, etc.) for instant use -2. **Dynamic Loading:** On-demand injection of ANY symbol from KiCad libraries: - - Parse `.kicad_sym` library files using S-expression parser - - Inject symbol definition into schematic's `lib_symbols` section - - Create offscreen template instance - - Reload schematic so kicad-skip sees new template - - Clone template to create actual component -3. **Wire Creation:** S-expression-based wire injection (bypasses kicad-skip API limitations) -4. **Pin Discovery:** Parse symbol definitions, apply rotation transformations, calculate absolute positions -5. **Connectivity Analysis:** Geometric wire tracing to build net connection graphs - -**Example - Complete Circuit Creation:** -```python -# Load power symbols dynamically -loader.load_symbol_dynamically(sch_path, "power", "VCC") - -# Place components with auto-rotation -ComponentManager.add_component(sch, { - "type": "STM32F103C8Tx", - "library": "MCU_ST_STM32F1", - "reference": "U1", - "x": 100, "y": 100, "rotation": 0 -}) - -# Connect with intelligent routing -ConnectionManager.add_connection(sch_path, "U1", "1", "R1", "2", routing="orthogonal_h") - -# Connect to power nets -ConnectionManager.connect_to_net(sch_path, "U1", "VDD", "VCC") - -# Analyze connectivity -connections = ConnectionManager.get_net_connections(sch, "VCC", sch_path) -# Returns: [{"component": "U1", "pin": "VDD"}, {"component": "R1", "pin": "1"}] -``` - -**Test Results:** -- Component placement: 100% passing -- Dynamic symbol loading: 10,000+ symbols accessible -- Wire creation: 100% passing (8/8 connections in test circuit) -- Pin discovery: Rotation-aware, sub-millimeter accuracy -- Net connectivity: 100% accurate (VCC: 2 connections, GND: 4 connections) -- Netlist generation: Working with accurate pin-level connections - -See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for the complete schematic tool documentation. - -### IPC Backend (Experimental) -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 -- No manual reload required when IPC is active -- Hybrid backend: uses IPC when available, falls back to SWIG API -- 20+ commands now support IPC including routing, component placement, and zone operations - -Note: IPC features are under active development and testing. Enable IPC in KiCAD via Preferences > Plugins > Enable IPC API Server. - -### Tool Discovery & Router Pattern -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 -- **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) -- **4 router tools** for discovery and execution: - - `list_tool_categories` - Browse all available categories - - `get_category_tools` - View tools in a specific category - - `search_tools` - Find tools by keyword - - `execute_tool` - Run any tool with parameters - -**Why this matters:** By organizing tools into discoverable categories, Claude can intelligently find and use the right tool for your task without loading all 122 tool schemas into every conversation. This reduces context consumption while maintaining full access to all functionality. - -**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 -### JLCPCB Parts Integration (New!) -Complete integration with JLCPCB's parts catalog, providing two complementary approaches for component selection: - -**Dual-Mode Architecture:** -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 - -**Key Features:** -- Real-time pricing with quantity breaks (1+, 10+, 100+, 1000+) -- Stock availability checking -- Basic vs Extended library type identification (Basic = free assembly) -- Intelligent cost optimization with alternative part suggestions -- Package-to-footprint mapping for KiCAD compatibility -- Parametric search by category, package, manufacturer -- Local SQLite database for fast offline searching -- No API credentials required for local library search - -**Why this matters:** JLCPCB offers PCB assembly services where Basic parts have no assembly fee, while Extended parts charge $3 per unique component. This integration helps you find the cheapest components with the best availability, potentially saving hundreds of dollars on assembly costs for production runs. - -See [JLCPCB Usage Guide](docs/JLCPCB_USAGE_GUIDE.md) for detailed setup and usage instructions. - -### Comprehensive Tool Schemas -Every tool now includes complete JSON Schema definitions with: -- Detailed parameter descriptions and constraints -- Input validation with type checking -- Required vs. optional parameter specifications -- Enumerated values for categorical inputs -- Clear documentation of what each tool does - -### Resources Capability -Access project state without executing tools: -- `kicad://project/current/info` - Project metadata -- `kicad://project/current/board` - Board properties -- `kicad://project/current/components` - Component list (JSON) -- `kicad://project/current/nets` - Electrical nets -- `kicad://project/current/layers` - Layer stack configuration -- `kicad://project/current/design-rules` - Current DRC settings -- `kicad://project/current/drc-report` - Design rule violations -- `kicad://board/preview.png` - Board visualization (PNG) - -### Protocol Compliance -- Updated to MCP SDK 1.21.0 (latest) -- Full JSON-RPC 2.0 support -- Proper capability negotiation -- Standards-compliant error codes - -## Available Tools - -The server provides **122 tools** organized into 16 functional categories. With the router pattern, tools are automatically discovered as needed -- just ask Claude what you want to accomplish. - -For the complete tool reference with access types (direct/routed/additional), see [Tool Inventory](docs/TOOL_INVENTORY.md). - -### Project Management (5 tools) -- `create_project` - Initialize new KiCAD projects -- `open_project` - Load existing project files -- `save_project` - Save current project state -- `get_project_info` - Retrieve project metadata -- `snapshot_project` - Save named checkpoint snapshot - -### Board Operations (12 tools) -- `set_board_size` - Configure PCB dimensions -- `add_board_outline` - Create board edge (rectangle, circle, polygon, rounded rectangle) -- `add_layer` - Add custom layers to stack -- `set_active_layer` - Switch working layer -- `get_layer_list` - List all board layers -- `get_board_info` - Retrieve board properties -- `get_board_2d_view` - Generate board preview image -- `get_board_extents` - Get board bounding box -- `add_mounting_hole` - Place mounting holes -- `add_board_text` - Add text annotations -- `add_zone` - Add copper zone/pour with clearance settings -- `import_svg_logo` - Import SVG file as PCB silkscreen polygons - -### Component Management (16 tools) -- `place_component` - Place single component with footprint -- `move_component` - Reposition existing component -- `rotate_component` - Rotate component by angle -- `delete_component` - Remove component from board -- `edit_component` - Modify component properties -- `find_component` - Search by reference or value -- `get_component_properties` - Query component details -- `add_component_annotation` - Add annotation/comment -- `group_components` - Group multiple components -- `replace_component` - Replace with different footprint -- `get_component_pads` - Get all pad information -- `get_component_list` - List all placed components -- `get_pad_position` - Get precise pad position -- `place_component_array` - Create component grids/patterns -- `align_components` - Align multiple components -- `duplicate_component` - Copy existing component - -### Routing (13 tools) -- `add_net` - Create electrical net -- `route_trace` - Route copper traces between XY points -- `route_pad_to_pad` - Route between pads with auto-via insertion -- `add_via` - Place vias for layer transitions -- `delete_trace` - Remove traces (by UUID, position, or net) -- `query_traces` - Query/filter traces -- `get_nets_list` - List all nets with statistics -- `modify_trace` - Change trace width, layer, or net -- `create_netclass` - Define net class with rules -- `add_copper_pour` - Create copper zones/pours -- `route_differential_pair` - Route differential signals -- `refill_zones` - Refill all copper zones -- `copy_routing_pattern` - Replicate routing between component groups - -### Schematic (27 tools) -Complete schematic workflow with dynamic symbol loading (~10,000 symbols) and intelligent wiring. - -**Component Operations:** -- `add_schematic_component` - Place symbols from any KiCad library -- `delete_schematic_component` - Remove component -- `edit_schematic_component` - Edit properties and fields -- `get_schematic_component` - Get component info with field positions -- `list_schematic_components` - List all components -- `move_schematic_component` - Reposition component -- `rotate_schematic_component` - Rotate component -- `annotate_schematic` - Auto-assign reference designators - -**Wiring and Connections:** -- `add_wire` - Create wire between points -- `delete_schematic_wire` - Remove wire segment -- `add_schematic_connection` - Auto-connect pins with routing -- `add_schematic_net_label` - Add net labels (VCC, GND, signals) -- `delete_schematic_net_label` - Remove net label -- `connect_to_net` - Connect pin to named net -- `connect_passthrough` - Wire all matching pins between connectors (FFC/ribbon) -- `get_schematic_pin_locations` - Get pin locations for component - -**Analysis and Export:** -- `get_net_connections` - Trace net connectivity -- `list_schematic_nets` / `list_schematic_wires` / `list_schematic_labels` -- `create_schematic` - Create new schematic file -- `get_schematic_view` - Rasterized schematic preview -- `export_schematic_svg` / `export_schematic_pdf` -- `run_erc` - Electrical rule check -- `generate_netlist` - Generate netlist from schematic -- `sync_schematic_to_board` - Import nets/pads to PCB (F8 equivalent) - -See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for details and examples. - -### Design Rules / DRC (8 tools) -- `set_design_rules` / `get_design_rules` - Configure and inspect rules -- `run_drc` - Execute design rule check -- `get_drc_violations` - Get violation list by severity -- `add_net_class` / `assign_net_to_class` - Net class management -- `set_layer_constraints` / `check_clearance` - Layer and clearance rules - -### Export (8 tools) -- `export_gerber` - Gerber fabrication files -- `export_pdf` / `export_svg` - Documentation and vector graphics -- `export_3d` - 3D models (STEP, STL, VRML, OBJ) -- `export_bom` - Bill of materials (CSV, XML, HTML, JSON) -- `export_netlist` - Netlist (KiCad, Spice, Cadstar, OrcadPCB2) -- `export_position_file` - Component positions for pick and place -- `export_vrml` - VRML 3D model - -### Footprint Libraries (4 tools) and Symbol Libraries (4 tools) -- `list_libraries` / `list_symbol_libraries` - Browse available libraries -- `search_footprints` / `search_symbols` - Search across all libraries -- `list_library_footprints` / `list_library_symbols` - Browse specific library -- `get_footprint_info` / `get_symbol_info` - Detailed information - -### Footprint Creator (4 tools) and Symbol Creator (4 tools) -Create custom components when existing libraries do not have what you need. -- `create_footprint` / `create_symbol` - Build from scratch with pads/pins -- `edit_footprint_pad` - Modify pad properties -- `register_footprint_library` / `register_symbol_library` - Register in lib-table -- `list_footprint_libraries` / `list_symbols_in_library` - Browse custom libraries -- `delete_symbol` - Remove symbol from library - -See [Footprint and Symbol Creator Guide](docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md) for details. - -### Datasheet Tools (2 tools) -- `enrich_datasheets` - Auto-populate datasheet URLs using LCSC part numbers -- `get_datasheet_url` - Get LCSC datasheet URL for a component - -### JLCPCB Integration (5 tools) -- `download_jlcpcb_database` - Download 2.5M+ parts catalog (one-time setup) -- `search_jlcpcb_parts` - Search with parametric filters -- `get_jlcpcb_part` - Detailed part info with pricing -- `get_jlcpcb_database_stats` - Database statistics -- `suggest_jlcpcb_alternatives` - Find cheaper or in-stock alternatives - -### Freerouting Autorouter (4 tools) -- `autoroute` - Run Freerouting autorouter (DSN export, route, SES import) -- `export_dsn` / `import_ses` - Manual Specctra DSN/SES workflow -- `check_freerouting` - Verify Java and Freerouting availability - -See [Freerouting Guide](docs/FREEROUTING_GUIDE.md) for setup and usage. - -### UI Management (2 tools) -- `check_kicad_ui` - Check if KiCAD is running -- `launch_kicad_ui` - Launch KiCAD application - -## Prerequisites - -### Required Software - -**KiCAD 9.0 or Higher** -- Download from [kicad.org/download](https://www.kicad.org/download/) -- Must include Python module (pcbnew) -- Verify installation: - ```bash - python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" - ``` - -**Node.js 18 or Higher** -- Download from [nodejs.org](https://nodejs.org/) -- Verify: `node --version` and `npm --version` - -**Python 3.10 or Higher** -- Usually included with KiCAD -- Required packages (auto-installed): - - kicad-python (kipy) >= 0.5.0 (IPC API support, optional but recommended) - - kicad-skip >= 0.1.0 (schematic support) - - Pillow >= 9.0.0 (image processing) - - cairosvg >= 2.7.0 (SVG rendering) - - colorlog >= 6.7.0 (logging) - - pydantic >= 2.5.0 (validation) - - requests >= 2.32.5 (HTTP client) - - python-dotenv >= 1.0.0 (environment) - -**MCP Client** -Choose one: -- [Claude Desktop](https://claude.ai/download) - Official Anthropic desktop app -- [Claude Code](https://docs.claude.com/claude-code) - Official CLI tool -- [Cline](https://github.com/cline/cline) - VSCode extension - -### Supported Platforms -- **Linux** (Ubuntu 22.04+, Fedora, Arch) - Primary platform, fully tested -- **Windows 10/11** - Fully supported with automated setup -- **macOS** - Experimental support - -## Installation - -### Linux (Ubuntu/Debian) - -```bash -# Install KiCAD 9.0 -sudo add-apt-repository --yes ppa:kicad/kicad-9.0-releases -sudo apt-get update -sudo apt-get install -y kicad kicad-libraries - -# Install Node.js -curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - -sudo apt-get install -y nodejs - -# Clone and build -git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git -cd KiCAD-MCP-Server -npm install -pip3 install -r requirements.txt -npm run build - -# Verify -python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" -``` - -### Windows 10/11 - -**Automated Setup (Recommended):** -```powershell -git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git -cd KiCAD-MCP-Server -.\setup-windows.ps1 -``` - -The script will: -- Detect KiCAD installation -- Verify prerequisites -- Install dependencies -- Build project -- Generate configuration -- Run diagnostics - -**Manual Setup:** -See [Windows Installation Guide](docs/WINDOWS_SETUP.md) for detailed instructions. - -### macOS - -**Important:** On macOS, use KiCAD's bundled Python to ensure proper access to pcbnew module. - -```bash -# Install KiCAD 9.0 from kicad.org/download/macos - -# Install Node.js -brew install node@20 - -# Clone repository -git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git -cd KiCAD-MCP-Server - -# Create virtual environment using KiCAD's bundled Python -/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3 -m venv venv --system-site-packages - -# Activate virtual environment -source venv/bin/activate - -# Install dependencies -npm install -pip install -r requirements.txt -npm run build -``` - -**Note:** The `--system-site-packages` flag is required to access KiCAD's pcbnew module from the virtual environment. - -## Configuration - -### Claude Desktop - -Edit configuration file: -- **Linux/macOS:** `~/.config/Claude/claude_desktop_config.json` -- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json` - -**Configuration:** -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/path/to/kicad/python", - "LOG_LEVEL": "info" - } - } - } -} -``` - -**Platform-specific PYTHONPATH:** -- **Linux:** `/usr/lib/kicad/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` - -#### Linux Python Detection - -The server automatically detects Python on Linux in this priority order: - -1. **Virtual environment** - `venv/bin/python` or `.venv/bin/python` (highest priority) -2. **KICAD_PYTHON env var** - User override for non-standard installations -3. **KiCad bundled Python** - `/usr/lib/kicad/bin/python3`, `/usr/local/lib/kicad/bin/python3`, `/opt/kicad/bin/python3` -4. **System Python via which** - Resolves `which python3` to absolute path (e.g., `/usr/bin/python3`) -5. **Common system paths** - `/usr/bin/python3`, `/bin/python3` - -**For most standard Linux installations (Ubuntu, Debian, Fedora, Arch), no KICAD_PYTHON configuration is needed** - the server will automatically find your Python installation. - -**Troubleshooting:** - -If you see "Python executable not found: python3", you can manually specify the Python path: - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], - "env": { - "KICAD_PYTHON": "/usr/bin/python3", - "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" - } - } - } -} -``` - -To find your Python path: -```bash -which python3 # Example output: /usr/bin/python3 -python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" # Verify pcbnew access -``` - -### Cline (VSCode) - -Edit: `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json` - -Use the same configuration format as Claude Desktop above. - -### Claude Code - -Claude Code automatically detects MCP servers in the current directory. No additional configuration needed. - -### JLCPCB Integration Setup (Optional) - -The JLCPCB integration provides two modes that can be used independently or together: - -**Mode 1: JLCSearch Public API (Recommended - No Setup Required)** - -The easiest way to access JLCPCB's parts catalog: -- No API credentials needed -- No JLCPCB account required -- 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) - -To download the database: -``` -Ask Claude: "Download the JLCPCB parts database" -``` - -This creates a local SQLite database at `data/jlcpcb_parts.db` (3-5 GB for full 2.5M+ part catalog). - -**Mode 2: Local Symbol Libraries (No Setup Required)** - -Install JLCPCB libraries via KiCAD's Plugin and Content Manager: -1. Open KiCAD -2. Go to Tools > Plugin and Content Manager -3. Search for "JLCPCB" or "JLC" -4. Install libraries like `JLCPCB-KiCAD-Library` or `EDA_MCP` -5. Use `search_symbols` to find components with pre-configured footprints and LCSC IDs - -**Mode 3: Official JLCPCB API (Advanced - Requires Enterprise Account)** - -For users with JLCPCB enterprise accounts and order history: - -1. **Get API Credentials** - - Log in to [JLCPCB](https://jlcpcb.com/) - - Navigate to Account > API Management (requires enterprise approval) - - Create API Key and save your `appKey` and `appSecret` - - Note: This requires prior order history and enterprise account approval - -2. **Configure Environment Variables** - - Add to your shell profile (`~/.bashrc`, `~/.zshrc`, or `~/.profile`): - ```bash - export JLCPCB_API_KEY="your_app_key_here" - export JLCPCB_API_SECRET="your_app_secret_here" - ``` - - Or create a `.env` file in the project root: - ``` - JLCPCB_API_KEY=your_app_key_here - JLCPCB_API_SECRET=your_app_secret_here - ``` - -See [JLCPCB Usage Guide](docs/JLCPCB_USAGE_GUIDE.md) for detailed documentation. - -## Usage Examples - -### Basic PCB Design Workflow - -```text -Create a new KiCAD project named 'LEDBoard' in my Documents folder. -Set the board size to 50mm x 50mm and add a rectangular outline. -Place a mounting hole at each corner, 3mm from the edges, with 3mm diameter. -Add text 'LED Controller v1.0' on the front silkscreen at position x=25mm, y=45mm. -``` - -### Component Placement - -```text -Place an LED at x=10mm, y=10mm using footprint LED_SMD:LED_0805_2012Metric. -Create a grid of 4 resistors (R1-R4) starting at x=20mm, y=20mm with 5mm spacing. -Align all resistors horizontally and distribute them evenly. -``` - -### Routing - -```text -Create a net named 'LED1' and route a 0.3mm trace from R1 pad 2 to LED1 anode. -Add a copper pour for GND on the bottom layer covering the entire board. -Create a differential pair for USB_P and USB_N with 0.2mm width and 0.15mm gap. -``` - -### Autoroute with Freerouting - -Automatically route all unconnected nets using the [Freerouting](https://github.com/freerouting/freerouting) autorouter. - -**Setup (one-time):** - -```bash -# 1. Download the Freerouting JAR -mkdir -p ~/.kicad-mcp -curl -L -o ~/.kicad-mcp/freerouting.jar \ - https://github.com/freerouting/freerouting/releases/download/v2.0.1/freerouting-2.0.1-executable.jar - -# 2. Runtime — pick ONE: -# Option A: Docker (recommended, no Java install needed) -docker pull eclipse-temurin:21-jre - -# Option B: Install Java 21+ locally -# (Ubuntu/Debian) sudo apt install openjdk-21-jre -``` - -The autorouter auto-detects which runtime is available (Java 21+ direct, or Docker/Podman fallback). - -```text -Check if Freerouting is ready on my system. -Autoroute the current board using Freerouting with a 5-minute timeout. -``` - -**Step-by-step workflow:** - -```text -1. Open the project at ~/Projects/LEDBoard/LEDBoard.kicad_pcb -2. Check Freerouting dependencies are installed -3. Run autoroute with max 10 passes -4. Run DRC to verify the autorouted result -5. Export Gerbers to the fabrication folder -``` - -**Manual DSN/SES workflow** (for advanced users or external autorouters): - -```text -Export the board to Specctra DSN format. -# ... run Freerouting GUI or another autorouter externally ... -Import the routed SES file from ~/Projects/LEDBoard/LEDBoard.ses -``` - -### Design Verification - -```text -Set design rules with 0.15mm clearance and 0.2mm minimum track width. -Run a design rule check and show me any violations. -Export Gerber files to the 'fabrication' folder. -``` - -### Using Resources - -Resources provide read-only access to project state: - -```text -Show me the current component list. -What are the current design rules? -Display the board preview. -List all electrical nets. -``` - -### JLCPCB Component Selection - -**Finding Components with Local Libraries:** - -```text -Search for ESP32 modules in JLCPCB libraries. -Find a 10k resistor in 0603 package from installed libraries. -Show me details for LCSC part C2934196. -``` - -**Optimizing Costs with JLCPCB API:** - -```text -Search for 10k ohm resistors in 0603 package, only Basic parts. -Find the cheapest capacitor 10uF 25V in 0805 package with good stock. -Show me pricing and stock for JLCPCB part C25804. -Suggest cheaper alternatives to C25804. -``` - -**Complete Design Workflow:** - -```text -I'm designing a board with an ESP32 and need to select components for JLCPCB assembly. -Search JLCPCB for ESP32-C3 modules. -Find Basic parts for: 10k resistor 0603, 100nF capacitor 0603, LED 0805. -For each component, show me the cheapest option with good stock availability. -Place these components on my board using the suggested footprints. -``` - -**Database Management:** - -```text -Download the JLCPCB parts database (first time setup). -Show me JLCPCB database statistics. -How many Basic parts are available? -``` - -## Architecture - -### MCP Protocol Layer -- **JSON-RPC 2.0 Transport:** Bi-directional communication via STDIO -- **Protocol Version:** MCP 2025-06-18 -- **Capabilities:** Tools (122), Resources (8) -- **Tool Router:** Intelligent discovery system with 8 categories -- **Error Handling:** Standard JSON-RPC error codes - -### TypeScript Server (`src/`) -- Implements MCP protocol specification -- Manages Python subprocess lifecycle -- Handles message routing and validation -- Provides logging and error recovery -- **Router System:** - - `src/tools/registry.ts` - Tool categorization and lookup - - `src/tools/router.ts` - Discovery and execution tools - - Reduces AI context usage by 70% while maintaining full functionality - -### Python Interface (`python/`) -- **kicad_interface.py:** Main entry point, MCP message handler, command routing -- **kicad_api/:** Backend implementations - - `base.py` - Abstract base classes for backends - - `ipc_backend.py` - KiCAD 9.0 IPC API backend (real-time UI sync) - - `swig_backend.py` - pcbnew SWIG API backend (file-based operations) - - `factory.py` - Backend auto-detection and instantiation -- **schemas/tool_schemas.py:** JSON Schema definitions for all tools -- **resources/resource_definitions.py:** Resource handlers and URIs -- **commands/:** Modular command implementations - - `project.py` - Project operations - - `board.py` - Board manipulation - - `component.py` - Component placement - - `routing.py` - Trace routing and nets - - `design_rules.py` - DRC operations - - `export.py` - File generation - - `schematic.py` - Schematic design - - `library.py` - Footprint libraries - - `library_symbol.py` - Symbol library search (local JLCPCB libraries) - - `jlcpcb.py` - JLCPCB API client - - `jlcpcb_parts.py` - JLCPCB parts database manager - -### KiCAD Integration -- **pcbnew API (SWIG):** Direct Python bindings to KiCAD for file operations -- **IPC API (kipy):** Real-time communication with running KiCAD instance (experimental) -- **Hybrid Backend:** Automatically uses IPC when available, falls back to SWIG -- **kicad-skip:** Schematic file manipulation -- **Platform Detection:** Cross-platform path handling -- **UI Management:** Automatic KiCAD UI launch/detection - -## Development - -### Building from Source - -```bash -# Install dependencies -npm install -pip3 install -r requirements.txt - -# Build TypeScript -npm run build - -# Watch mode for development -npm run dev -``` - -### Running Tests - -```bash -# TypeScript tests -npm run test:ts - -# Python tests -npm run test:py - -# All tests with coverage -npm run test:coverage -``` - -### Linting and Formatting - -```bash -# Lint TypeScript and Python -npm run lint - -# Format code -npm run format -``` - -## Troubleshooting - -### Server Not Appearing in Client - -**Symptoms:** MCP server doesn't show up in Claude Desktop or Cline - -**Solutions:** -1. Verify build completed: `ls dist/index.js` -2. Check configuration paths are absolute -3. Restart MCP client completely -4. Check client logs for error messages - -### Python Module Import Errors - -**Symptoms:** `ModuleNotFoundError: No module named 'pcbnew'` - -**Solutions:** -1. Verify KiCAD installation: `python3 -c "import pcbnew"` -2. Check PYTHONPATH in configuration matches your KiCAD installation -3. Ensure KiCAD was installed with Python support - -### Tool Execution Failures - -**Symptoms:** Tools fail with unclear errors - -**Solutions:** -1. Check server logs: `~/.kicad-mcp/logs/kicad_interface.log` -2. Verify a project is loaded before running board operations -3. Ensure file paths are absolute, not relative -4. Check tool parameter types match schema requirements - -### Windows-Specific Issues - -**Symptoms:** Server fails to start on Windows - -**Solutions:** -1. Run automated diagnostics: `.\setup-windows.ps1` -2. Verify Python path uses double backslashes: `C:\\Program Files\\KiCad\\9.0` -3. Check Windows Event Viewer for Node.js errors -4. See [Windows Troubleshooting Guide](docs/WINDOWS_TROUBLESHOOTING.md) - -### Getting Help - -1. Check the [GitHub Issues](https://github.com/mixelpixx/KiCAD-MCP-Server/issues) -2. Review server logs: `~/.kicad-mcp/logs/kicad_interface.log` -3. Open a new issue with: - - Operating system and version - - KiCAD version (`python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"`) - - Node.js version (`node --version`) - - Full error message and stack trace - - Relevant log excerpts - -## Project Status - -**Current Version:** 2.2.3 - -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):** -- Project management with snapshot checkpointing -- Complete board design (outline, layers, zones, mounting holes, text, SVG logos) -- Component placement with arrays, alignment, and duplication -- Advanced routing (pad-to-pad with auto-via, differential pairs, pattern copying) -- Complete schematic workflow with dynamic symbol loading (~10,000 symbols) -- Intelligent wiring system with pin discovery and smart routing -- FFC/ribbon cable passthrough workflow -- Schematic-to-board synchronization -- Design rule checking (DRC and ERC) -- Export to Gerber, PDF, SVG, 3D, BOM, netlist, position file -- Custom footprint and symbol creation -- JLCPCB parts integration (2.5M+ parts catalog) -- Datasheet enrichment via LCSC -- Freerouting autorouter integration (Java, Docker, Podman) -- UI auto-launch and management -- Full MCP 2025-06-18 protocol compliance - -**IPC Backend (Experimental):** -- Real-time UI synchronization via KiCAD 9.0 IPC API -- 21 IPC-enabled commands with automatic SWIG fallback -- Hybrid footprint loading (SWIG for library access, IPC for placement) - -**Developer Mode:** -Set `KICAD_MCP_DEV=1` to capture MCP session logs for debugging. See CHANGELOG v2.2.3 for details. - -See [ROADMAP.md](docs/ROADMAP.md) for planned features. - -## What Do You Want to See Next? - -We are actively developing new features. Your feedback directly shapes development priorities. - -**Share your ideas:** -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) -3. Star the repo if you find it useful - -## Contributing - -Contributions are welcome! Please follow these guidelines: - -1. **Report Bugs:** Open an issue with reproduction steps -2. **Suggest Features:** Describe use case and expected behavior -3. **Submit Pull Requests:** - - Fork the repository - - Create a feature branch - - Follow existing code style - - Add tests for new functionality - - Update documentation - - Submit PR with clear description - -See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines. - -## License - -This project is licensed under the MIT License. See [LICENSE](LICENSE) for details. - -## Acknowledgments - -- Built on the [Model Context Protocol](https://modelcontextprotocol.io/) by Anthropic -- Powered by [KiCAD](https://www.kicad.org/) open-source PCB design software -- Uses [kicad-skip](https://github.com/kicad-skip) for schematic manipulation -- [JLCSearch API](https://jlcsearch.tscircuit.com/) by [@tscircuit](https://github.com/tscircuit/jlcsearch) - Public JLCPCB parts API -- [JLCParts Database](https://github.com/yaqwsx/jlcparts) by [@yaqwsx](https://github.com/yaqwsx) - JLCPCB parts data - -### Community Contributors - -- [@Kletternaut](https://github.com/Kletternaut) - Routing/component tools, footprint/symbol creators, passthrough workflow, template fixes (PRs #44, #48, #49, #51, #53, #57, #59) -- [@Mehanik](https://github.com/Mehanik) - Schematic inspection/editing tools, component field positions (PRs #60, #66, #67) -- [@jflaflamme](https://github.com/jflaflamme) - Freerouting autorouter integration with Docker/Podman support (PR #68) -- [@l3wi](https://github.com/l3wi) - Local symbol library search, JLCPCB third-party library support (PR #25) -- [@gwall-ceres](https://github.com/gwall-ceres) - MCP protocol compliance, Windows compatibility (PR #10) -- [@fariouche](https://github.com/fariouche) - Bug fixes (PR #17) -- [@shuofengzhang](https://github.com/shuofengzhang) - XDG relative path handling (PR #58) -- [@sid115](https://github.com/sid115) - Windows setup script improvements (PR #13) -- [@pasrom](https://github.com/pasrom) - MCP server bug fixes (PR #50) - -## Citation - -If you use this project in your research or publication, please cite: - -```bibtex -@software{kicad_mcp_server, - title = {KiCAD MCP Server: AI-Assisted PCB Design}, - author = {mixelpixx}, - year = {2025}, - url = {https://github.com/mixelpixx/KiCAD-MCP-Server}, - version = {2.2.3} -} -``` +# Discussions. Get in here. + +https://github.com/mixelpixx/KiCAD-MCP-Server/discussions/73 + +# KiCAD MCP Server + +A Model Context Protocol (MCP) server that enables AI assistants like Claude to interact with KiCAD for PCB design automation. Built on the MCP 2025-06-18 specification, this server provides comprehensive tool schemas and real-time project state access for intelligent PCB design workflows. + +## Overview + +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:** + +- 122 tools across 16 categories with JSON Schema validation +- Smart tool discovery with router pattern (reduces AI context by 70%) +- 8 dynamic resources exposing project state +- Complete schematic workflow with 27 tools and dynamic symbol loading (~10,000 symbols) +- Freerouting autorouter integration (Java, Docker, or Podman) +- Custom footprint and symbol creation tools +- JLCPCB parts integration with 2.5M+ component catalog and local library search +- Datasheet enrichment via LCSC +- Full MCP 2025-06-18 protocol compliance +- Cross-platform support (Linux, Windows, macOS) +- Real-time KiCAD UI integration via IPC API (experimental) +- Comprehensive error handling and logging + +## Try out Arduino MCP - now you can get Claude to help in the IDE, real time!: + +https://github.com/mixelpixx/arduino-ide + +## What's New in v2.2.3 + +### New Tools: FFC/Ribbon Cable Passthrough Workflow + +A complete workflow for designing passthrough adapter boards (e.g. Raspberry Pi CSI +cable adapters) is now supported: + +1. `connect_passthrough` — wires all pins of one connector to the matching pins of + another in the schematic (J1 pin N → J2 pin N, auto-named nets). +2. `sync_schematic_to_board` — imports the net assignments into the PCB. +3. `route_pad_to_pad` — routes each connection with automatic via insertion when + pads are on opposite copper layers. +4. `snapshot_project` — saves a named checkpoint into `/snapshots/`. + +### Bug Fixes (KiCAD 9 / Windows) + +- **Via insertion for B.Cu footprints** — `route_pad_to_pad` now correctly detects + when a footprint is on B.Cu and inserts the required via. (KiCAD 9 SWIG returned + `F.Cu` for all SMD pads regardless of layer — fixed.) +- **Board outline rounded corners** — `add_board_outline` now correctly applies + `cornerRadius` when `shape="rounded_rectangle"`. +- **B.Cu placement hang** — placing a footprint on B.Cu no longer causes a ~30s + freeze in KiCAD 9. + +### Developer Mode + +Set `KICAD_MCP_DEV=1` in your Claude Desktop MCP environment to automatically save +the MCP session log into the project's `logs/` folder on every `export_gerber` and +`snapshot_project` call. Useful for debugging and for attaching to GitHub issues. + +```json +"env": { + "KICAD_MCP_DEV": "1" +} +``` + +> **Privacy warning:** The session log contains your full tool call history +> (including file paths and design details). **Review or delete `logs/` before +> sharing a project directory publicly.** + +See [CHANGELOG](CHANGELOG.md) for the full list of changes in this release. + +--- + +## What's New in v2.1.0 + +### 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!** + +**What was broken:** + +- `create_project` only created PCB files, no schematics +- `add_schematic_component` called non-existent API methods +- Schematics couldn't be created or edited at all +- Only 13 component types available (severe limitation) +- No working wire/connection functionality + +**Complete Implementation (3 Phases):** + +**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 +- Rewrote component placement to use proper `clone()` API + +**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 +- Zero configuration required - just specify library and symbol name +- Seamless integration with existing MCP tools +- Full S-expression parsing and injection system + +**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) +- **Power symbol support** (VCC, GND, +3V3, +5V, etc.) +- **Wire graph analysis** - geometric tracing for net connectivity +- **Net label management** (local, global, hierarchical labels) +- **Netlist generation** with accurate component/pin connections + +**Technical Architecture:** +The kicad-skip library cannot create symbols or wires from scratch. We implemented a comprehensive solution: + +1. **Static Templates:** 13 pre-configured symbols (R, C, L, LED, etc.) for instant use +2. **Dynamic Loading:** On-demand injection of ANY symbol from KiCad libraries: + - Parse `.kicad_sym` library files using S-expression parser + - Inject symbol definition into schematic's `lib_symbols` section + - Create offscreen template instance + - Reload schematic so kicad-skip sees new template + - Clone template to create actual component +3. **Wire Creation:** S-expression-based wire injection (bypasses kicad-skip API limitations) +4. **Pin Discovery:** Parse symbol definitions, apply rotation transformations, calculate absolute positions +5. **Connectivity Analysis:** Geometric wire tracing to build net connection graphs + +**Example - Complete Circuit Creation:** + +```python +# Load power symbols dynamically +loader.load_symbol_dynamically(sch_path, "power", "VCC") + +# Place components with auto-rotation +ComponentManager.add_component(sch, { + "type": "STM32F103C8Tx", + "library": "MCU_ST_STM32F1", + "reference": "U1", + "x": 100, "y": 100, "rotation": 0 +}) + +# Connect with intelligent routing +ConnectionManager.add_connection(sch_path, "U1", "1", "R1", "2", routing="orthogonal_h") + +# Connect to power nets +ConnectionManager.connect_to_net(sch_path, "U1", "VDD", "VCC") + +# Analyze connectivity +connections = ConnectionManager.get_net_connections(sch, "VCC", sch_path) +# Returns: [{"component": "U1", "pin": "VDD"}, {"component": "R1", "pin": "1"}] +``` + +**Test Results:** + +- Component placement: 100% passing +- Dynamic symbol loading: 10,000+ symbols accessible +- Wire creation: 100% passing (8/8 connections in test circuit) +- Pin discovery: Rotation-aware, sub-millimeter accuracy +- Net connectivity: 100% accurate (VCC: 2 connections, GND: 4 connections) +- Netlist generation: Working with accurate pin-level connections + +See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for the complete schematic tool documentation. + +### IPC Backend (Experimental) + +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 +- No manual reload required when IPC is active +- Hybrid backend: uses IPC when available, falls back to SWIG API +- 20+ commands now support IPC including routing, component placement, and zone operations + +Note: IPC features are under active development and testing. Enable IPC in KiCAD via Preferences > Plugins > Enable IPC API Server. + +### Tool Discovery & Router Pattern + +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 +- **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) +- **4 router tools** for discovery and execution: + - `list_tool_categories` - Browse all available categories + - `get_category_tools` - View tools in a specific category + - `search_tools` - Find tools by keyword + - `execute_tool` - Run any tool with parameters + +**Why this matters:** By organizing tools into discoverable categories, Claude can intelligently find and use the right tool for your task without loading all 122 tool schemas into every conversation. This reduces context consumption while maintaining full access to all functionality. + +**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 + +### JLCPCB Parts Integration (New!) + +Complete integration with JLCPCB's parts catalog, providing two complementary approaches for component selection: + +**Dual-Mode Architecture:** + +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 + +**Key Features:** + +- Real-time pricing with quantity breaks (1+, 10+, 100+, 1000+) +- Stock availability checking +- Basic vs Extended library type identification (Basic = free assembly) +- Intelligent cost optimization with alternative part suggestions +- Package-to-footprint mapping for KiCAD compatibility +- Parametric search by category, package, manufacturer +- Local SQLite database for fast offline searching +- No API credentials required for local library search + +**Why this matters:** JLCPCB offers PCB assembly services where Basic parts have no assembly fee, while Extended parts charge $3 per unique component. This integration helps you find the cheapest components with the best availability, potentially saving hundreds of dollars on assembly costs for production runs. + +See [JLCPCB Usage Guide](docs/JLCPCB_USAGE_GUIDE.md) for detailed setup and usage instructions. + +### Comprehensive Tool Schemas + +Every tool now includes complete JSON Schema definitions with: + +- Detailed parameter descriptions and constraints +- Input validation with type checking +- Required vs. optional parameter specifications +- Enumerated values for categorical inputs +- Clear documentation of what each tool does + +### Resources Capability + +Access project state without executing tools: + +- `kicad://project/current/info` - Project metadata +- `kicad://project/current/board` - Board properties +- `kicad://project/current/components` - Component list (JSON) +- `kicad://project/current/nets` - Electrical nets +- `kicad://project/current/layers` - Layer stack configuration +- `kicad://project/current/design-rules` - Current DRC settings +- `kicad://project/current/drc-report` - Design rule violations +- `kicad://board/preview.png` - Board visualization (PNG) + +### Protocol Compliance + +- Updated to MCP SDK 1.21.0 (latest) +- Full JSON-RPC 2.0 support +- Proper capability negotiation +- Standards-compliant error codes + +## Available Tools + +The server provides **122 tools** organized into 16 functional categories. With the router pattern, tools are automatically discovered as needed -- just ask Claude what you want to accomplish. + +For the complete tool reference with access types (direct/routed/additional), see [Tool Inventory](docs/TOOL_INVENTORY.md). + +### Project Management (5 tools) + +- `create_project` - Initialize new KiCAD projects +- `open_project` - Load existing project files +- `save_project` - Save current project state +- `get_project_info` - Retrieve project metadata +- `snapshot_project` - Save named checkpoint snapshot + +### Board Operations (12 tools) + +- `set_board_size` - Configure PCB dimensions +- `add_board_outline` - Create board edge (rectangle, circle, polygon, rounded rectangle) +- `add_layer` - Add custom layers to stack +- `set_active_layer` - Switch working layer +- `get_layer_list` - List all board layers +- `get_board_info` - Retrieve board properties +- `get_board_2d_view` - Generate board preview image +- `get_board_extents` - Get board bounding box +- `add_mounting_hole` - Place mounting holes +- `add_board_text` - Add text annotations +- `add_zone` - Add copper zone/pour with clearance settings +- `import_svg_logo` - Import SVG file as PCB silkscreen polygons + +### Component Management (16 tools) + +- `place_component` - Place single component with footprint +- `move_component` - Reposition existing component +- `rotate_component` - Rotate component by angle +- `delete_component` - Remove component from board +- `edit_component` - Modify component properties +- `find_component` - Search by reference or value +- `get_component_properties` - Query component details +- `add_component_annotation` - Add annotation/comment +- `group_components` - Group multiple components +- `replace_component` - Replace with different footprint +- `get_component_pads` - Get all pad information +- `get_component_list` - List all placed components +- `get_pad_position` - Get precise pad position +- `place_component_array` - Create component grids/patterns +- `align_components` - Align multiple components +- `duplicate_component` - Copy existing component + +### Routing (13 tools) + +- `add_net` - Create electrical net +- `route_trace` - Route copper traces between XY points +- `route_pad_to_pad` - Route between pads with auto-via insertion +- `add_via` - Place vias for layer transitions +- `delete_trace` - Remove traces (by UUID, position, or net) +- `query_traces` - Query/filter traces +- `get_nets_list` - List all nets with statistics +- `modify_trace` - Change trace width, layer, or net +- `create_netclass` - Define net class with rules +- `add_copper_pour` - Create copper zones/pours +- `route_differential_pair` - Route differential signals +- `refill_zones` - Refill all copper zones +- `copy_routing_pattern` - Replicate routing between component groups + +### Schematic (27 tools) + +Complete schematic workflow with dynamic symbol loading (~10,000 symbols) and intelligent wiring. + +**Component Operations:** + +- `add_schematic_component` - Place symbols from any KiCad library +- `delete_schematic_component` - Remove component +- `edit_schematic_component` - Edit properties and fields +- `get_schematic_component` - Get component info with field positions +- `list_schematic_components` - List all components +- `move_schematic_component` - Reposition component +- `rotate_schematic_component` - Rotate component +- `annotate_schematic` - Auto-assign reference designators + +**Wiring and Connections:** + +- `add_wire` - Create wire between points +- `delete_schematic_wire` - Remove wire segment +- `add_schematic_connection` - Auto-connect pins with routing +- `add_schematic_net_label` - Add net labels (VCC, GND, signals) +- `delete_schematic_net_label` - Remove net label +- `connect_to_net` - Connect pin to named net +- `connect_passthrough` - Wire all matching pins between connectors (FFC/ribbon) +- `get_schematic_pin_locations` - Get pin locations for component + +**Analysis and Export:** + +- `get_net_connections` - Trace net connectivity +- `list_schematic_nets` / `list_schematic_wires` / `list_schematic_labels` +- `create_schematic` - Create new schematic file +- `get_schematic_view` - Rasterized schematic preview +- `export_schematic_svg` / `export_schematic_pdf` +- `run_erc` - Electrical rule check +- `generate_netlist` - Generate netlist from schematic +- `sync_schematic_to_board` - Import nets/pads to PCB (F8 equivalent) + +See [Schematic Tools Reference](docs/SCHEMATIC_TOOLS_REFERENCE.md) for details and examples. + +### Design Rules / DRC (8 tools) + +- `set_design_rules` / `get_design_rules` - Configure and inspect rules +- `run_drc` - Execute design rule check +- `get_drc_violations` - Get violation list by severity +- `add_net_class` / `assign_net_to_class` - Net class management +- `set_layer_constraints` / `check_clearance` - Layer and clearance rules + +### Export (8 tools) + +- `export_gerber` - Gerber fabrication files +- `export_pdf` / `export_svg` - Documentation and vector graphics +- `export_3d` - 3D models (STEP, STL, VRML, OBJ) +- `export_bom` - Bill of materials (CSV, XML, HTML, JSON) +- `export_netlist` - Netlist (KiCad, Spice, Cadstar, OrcadPCB2) +- `export_position_file` - Component positions for pick and place +- `export_vrml` - VRML 3D model + +### Footprint Libraries (4 tools) and Symbol Libraries (4 tools) + +- `list_libraries` / `list_symbol_libraries` - Browse available libraries +- `search_footprints` / `search_symbols` - Search across all libraries +- `list_library_footprints` / `list_library_symbols` - Browse specific library +- `get_footprint_info` / `get_symbol_info` - Detailed information + +### Footprint Creator (4 tools) and Symbol Creator (4 tools) + +Create custom components when existing libraries do not have what you need. + +- `create_footprint` / `create_symbol` - Build from scratch with pads/pins +- `edit_footprint_pad` - Modify pad properties +- `register_footprint_library` / `register_symbol_library` - Register in lib-table +- `list_footprint_libraries` / `list_symbols_in_library` - Browse custom libraries +- `delete_symbol` - Remove symbol from library + +See [Footprint and Symbol Creator Guide](docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md) for details. + +### Datasheet Tools (2 tools) + +- `enrich_datasheets` - Auto-populate datasheet URLs using LCSC part numbers +- `get_datasheet_url` - Get LCSC datasheet URL for a component + +### JLCPCB Integration (5 tools) + +- `download_jlcpcb_database` - Download 2.5M+ parts catalog (one-time setup) +- `search_jlcpcb_parts` - Search with parametric filters +- `get_jlcpcb_part` - Detailed part info with pricing +- `get_jlcpcb_database_stats` - Database statistics +- `suggest_jlcpcb_alternatives` - Find cheaper or in-stock alternatives + +### Freerouting Autorouter (4 tools) + +- `autoroute` - Run Freerouting autorouter (DSN export, route, SES import) +- `export_dsn` / `import_ses` - Manual Specctra DSN/SES workflow +- `check_freerouting` - Verify Java and Freerouting availability + +See [Freerouting Guide](docs/FREEROUTING_GUIDE.md) for setup and usage. + +### UI Management (2 tools) + +- `check_kicad_ui` - Check if KiCAD is running +- `launch_kicad_ui` - Launch KiCAD application + +## Prerequisites + +### Required Software + +**KiCAD 9.0 or Higher** + +- Download from [kicad.org/download](https://www.kicad.org/download/) +- Must include Python module (pcbnew) +- Verify installation: + ```bash + python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" + ``` + +**Node.js 18 or Higher** + +- Download from [nodejs.org](https://nodejs.org/) +- Verify: `node --version` and `npm --version` + +**Python 3.10 or Higher** + +- Usually included with KiCAD +- Required packages (auto-installed): + - kicad-python (kipy) >= 0.5.0 (IPC API support, optional but recommended) + - kicad-skip >= 0.1.0 (schematic support) + - Pillow >= 9.0.0 (image processing) + - cairosvg >= 2.7.0 (SVG rendering) + - colorlog >= 6.7.0 (logging) + - pydantic >= 2.5.0 (validation) + - requests >= 2.32.5 (HTTP client) + - python-dotenv >= 1.0.0 (environment) + +**MCP Client** +Choose one: + +- [Claude Desktop](https://claude.ai/download) - Official Anthropic desktop app +- [Claude Code](https://docs.claude.com/claude-code) - Official CLI tool +- [Cline](https://github.com/cline/cline) - VSCode extension + +### Supported Platforms + +- **Linux** (Ubuntu 22.04+, Fedora, Arch) - Primary platform, fully tested +- **Windows 10/11** - Fully supported with automated setup +- **macOS** - Experimental support + +## Installation + +### Linux (Ubuntu/Debian) + +```bash +# Install KiCAD 9.0 +sudo add-apt-repository --yes ppa:kicad/kicad-9.0-releases +sudo apt-get update +sudo apt-get install -y kicad kicad-libraries + +# Install Node.js +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt-get install -y nodejs + +# Clone and build +git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git +cd KiCAD-MCP-Server +npm install +pip3 install -r requirements.txt +npm run build + +# Verify +python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" +``` + +### Windows 10/11 + +**Automated Setup (Recommended):** + +```powershell +git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git +cd KiCAD-MCP-Server +.\setup-windows.ps1 +``` + +The script will: + +- Detect KiCAD installation +- Verify prerequisites +- Install dependencies +- Build project +- Generate configuration +- Run diagnostics + +**Manual Setup:** +See [Windows Installation Guide](docs/WINDOWS_SETUP.md) for detailed instructions. + +### macOS + +**Important:** On macOS, use KiCAD's bundled Python to ensure proper access to pcbnew module. + +```bash +# Install KiCAD 9.0 from kicad.org/download/macos + +# Install Node.js +brew install node@20 + +# Clone repository +git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git +cd KiCAD-MCP-Server + +# Create virtual environment using KiCAD's bundled Python +/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3 -m venv venv --system-site-packages + +# Activate virtual environment +source venv/bin/activate + +# Install dependencies +npm install +pip install -r requirements.txt +npm run build +``` + +**Note:** The `--system-site-packages` flag is required to access KiCAD's pcbnew module from the virtual environment. + +## Configuration + +### Claude Desktop + +Edit configuration file: + +- **Linux/macOS:** `~/.config/Claude/claude_desktop_config.json` +- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json` + +**Configuration:** + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/path/to/kicad/python", + "LOG_LEVEL": "info" + } + } + } +} +``` + +**Platform-specific PYTHONPATH:** + +- **Linux:** `/usr/lib/kicad/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` + +#### Linux Python Detection + +The server automatically detects Python on Linux in this priority order: + +1. **Virtual environment** - `venv/bin/python` or `.venv/bin/python` (highest priority) +2. **KICAD_PYTHON env var** - User override for non-standard installations +3. **KiCad bundled Python** - `/usr/lib/kicad/bin/python3`, `/usr/local/lib/kicad/bin/python3`, `/opt/kicad/bin/python3` +4. **System Python via which** - Resolves `which python3` to absolute path (e.g., `/usr/bin/python3`) +5. **Common system paths** - `/usr/bin/python3`, `/bin/python3` + +**For most standard Linux installations (Ubuntu, Debian, Fedora, Arch), no KICAD_PYTHON configuration is needed** - the server will automatically find your Python installation. + +**Troubleshooting:** + +If you see "Python executable not found: python3", you can manually specify the Python path: + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], + "env": { + "KICAD_PYTHON": "/usr/bin/python3", + "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" + } + } + } +} +``` + +To find your Python path: + +```bash +which python3 # Example output: /usr/bin/python3 +python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" # Verify pcbnew access +``` + +### Cline (VSCode) + +Edit: `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json` + +Use the same configuration format as Claude Desktop above. + +### Claude Code + +Claude Code automatically detects MCP servers in the current directory. No additional configuration needed. + +### JLCPCB Integration Setup (Optional) + +The JLCPCB integration provides two modes that can be used independently or together: + +**Mode 1: JLCSearch Public API (Recommended - No Setup Required)** + +The easiest way to access JLCPCB's parts catalog: + +- No API credentials needed +- No JLCPCB account required +- 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) + +To download the database: + +``` +Ask Claude: "Download the JLCPCB parts database" +``` + +This creates a local SQLite database at `data/jlcpcb_parts.db` (3-5 GB for full 2.5M+ part catalog). + +**Mode 2: Local Symbol Libraries (No Setup Required)** + +Install JLCPCB libraries via KiCAD's Plugin and Content Manager: + +1. Open KiCAD +2. Go to Tools > Plugin and Content Manager +3. Search for "JLCPCB" or "JLC" +4. Install libraries like `JLCPCB-KiCAD-Library` or `EDA_MCP` +5. Use `search_symbols` to find components with pre-configured footprints and LCSC IDs + +**Mode 3: Official JLCPCB API (Advanced - Requires Enterprise Account)** + +For users with JLCPCB enterprise accounts and order history: + +1. **Get API Credentials** + - Log in to [JLCPCB](https://jlcpcb.com/) + - Navigate to Account > API Management (requires enterprise approval) + - Create API Key and save your `appKey` and `appSecret` + - Note: This requires prior order history and enterprise account approval + +2. **Configure Environment Variables** + + Add to your shell profile (`~/.bashrc`, `~/.zshrc`, or `~/.profile`): + + ```bash + export JLCPCB_API_KEY="your_app_key_here" + export JLCPCB_API_SECRET="your_app_secret_here" + ``` + + Or create a `.env` file in the project root: + + ``` + JLCPCB_API_KEY=your_app_key_here + JLCPCB_API_SECRET=your_app_secret_here + ``` + +See [JLCPCB Usage Guide](docs/JLCPCB_USAGE_GUIDE.md) for detailed documentation. + +## Usage Examples + +### Basic PCB Design Workflow + +```text +Create a new KiCAD project named 'LEDBoard' in my Documents folder. +Set the board size to 50mm x 50mm and add a rectangular outline. +Place a mounting hole at each corner, 3mm from the edges, with 3mm diameter. +Add text 'LED Controller v1.0' on the front silkscreen at position x=25mm, y=45mm. +``` + +### Component Placement + +```text +Place an LED at x=10mm, y=10mm using footprint LED_SMD:LED_0805_2012Metric. +Create a grid of 4 resistors (R1-R4) starting at x=20mm, y=20mm with 5mm spacing. +Align all resistors horizontally and distribute them evenly. +``` + +### Routing + +```text +Create a net named 'LED1' and route a 0.3mm trace from R1 pad 2 to LED1 anode. +Add a copper pour for GND on the bottom layer covering the entire board. +Create a differential pair for USB_P and USB_N with 0.2mm width and 0.15mm gap. +``` + +### Autoroute with Freerouting + +Automatically route all unconnected nets using the [Freerouting](https://github.com/freerouting/freerouting) autorouter. + +**Setup (one-time):** + +```bash +# 1. Download the Freerouting JAR +mkdir -p ~/.kicad-mcp +curl -L -o ~/.kicad-mcp/freerouting.jar \ + https://github.com/freerouting/freerouting/releases/download/v2.0.1/freerouting-2.0.1-executable.jar + +# 2. Runtime — pick ONE: +# Option A: Docker (recommended, no Java install needed) +docker pull eclipse-temurin:21-jre + +# Option B: Install Java 21+ locally +# (Ubuntu/Debian) sudo apt install openjdk-21-jre +``` + +The autorouter auto-detects which runtime is available (Java 21+ direct, or Docker/Podman fallback). + +```text +Check if Freerouting is ready on my system. +Autoroute the current board using Freerouting with a 5-minute timeout. +``` + +**Step-by-step workflow:** + +```text +1. Open the project at ~/Projects/LEDBoard/LEDBoard.kicad_pcb +2. Check Freerouting dependencies are installed +3. Run autoroute with max 10 passes +4. Run DRC to verify the autorouted result +5. Export Gerbers to the fabrication folder +``` + +**Manual DSN/SES workflow** (for advanced users or external autorouters): + +```text +Export the board to Specctra DSN format. +# ... run Freerouting GUI or another autorouter externally ... +Import the routed SES file from ~/Projects/LEDBoard/LEDBoard.ses +``` + +### Design Verification + +```text +Set design rules with 0.15mm clearance and 0.2mm minimum track width. +Run a design rule check and show me any violations. +Export Gerber files to the 'fabrication' folder. +``` + +### Using Resources + +Resources provide read-only access to project state: + +```text +Show me the current component list. +What are the current design rules? +Display the board preview. +List all electrical nets. +``` + +### JLCPCB Component Selection + +**Finding Components with Local Libraries:** + +```text +Search for ESP32 modules in JLCPCB libraries. +Find a 10k resistor in 0603 package from installed libraries. +Show me details for LCSC part C2934196. +``` + +**Optimizing Costs with JLCPCB API:** + +```text +Search for 10k ohm resistors in 0603 package, only Basic parts. +Find the cheapest capacitor 10uF 25V in 0805 package with good stock. +Show me pricing and stock for JLCPCB part C25804. +Suggest cheaper alternatives to C25804. +``` + +**Complete Design Workflow:** + +```text +I'm designing a board with an ESP32 and need to select components for JLCPCB assembly. +Search JLCPCB for ESP32-C3 modules. +Find Basic parts for: 10k resistor 0603, 100nF capacitor 0603, LED 0805. +For each component, show me the cheapest option with good stock availability. +Place these components on my board using the suggested footprints. +``` + +**Database Management:** + +```text +Download the JLCPCB parts database (first time setup). +Show me JLCPCB database statistics. +How many Basic parts are available? +``` + +## Architecture + +### MCP Protocol Layer + +- **JSON-RPC 2.0 Transport:** Bi-directional communication via STDIO +- **Protocol Version:** MCP 2025-06-18 +- **Capabilities:** Tools (122), Resources (8) +- **Tool Router:** Intelligent discovery system with 8 categories +- **Error Handling:** Standard JSON-RPC error codes + +### TypeScript Server (`src/`) + +- Implements MCP protocol specification +- Manages Python subprocess lifecycle +- Handles message routing and validation +- Provides logging and error recovery +- **Router System:** + - `src/tools/registry.ts` - Tool categorization and lookup + - `src/tools/router.ts` - Discovery and execution tools + - Reduces AI context usage by 70% while maintaining full functionality + +### Python Interface (`python/`) + +- **kicad_interface.py:** Main entry point, MCP message handler, command routing +- **kicad_api/:** Backend implementations + - `base.py` - Abstract base classes for backends + - `ipc_backend.py` - KiCAD 9.0 IPC API backend (real-time UI sync) + - `swig_backend.py` - pcbnew SWIG API backend (file-based operations) + - `factory.py` - Backend auto-detection and instantiation +- **schemas/tool_schemas.py:** JSON Schema definitions for all tools +- **resources/resource_definitions.py:** Resource handlers and URIs +- **commands/:** Modular command implementations + - `project.py` - Project operations + - `board.py` - Board manipulation + - `component.py` - Component placement + - `routing.py` - Trace routing and nets + - `design_rules.py` - DRC operations + - `export.py` - File generation + - `schematic.py` - Schematic design + - `library.py` - Footprint libraries + - `library_symbol.py` - Symbol library search (local JLCPCB libraries) + - `jlcpcb.py` - JLCPCB API client + - `jlcpcb_parts.py` - JLCPCB parts database manager + +### KiCAD Integration + +- **pcbnew API (SWIG):** Direct Python bindings to KiCAD for file operations +- **IPC API (kipy):** Real-time communication with running KiCAD instance (experimental) +- **Hybrid Backend:** Automatically uses IPC when available, falls back to SWIG +- **kicad-skip:** Schematic file manipulation +- **Platform Detection:** Cross-platform path handling +- **UI Management:** Automatic KiCAD UI launch/detection + +## Development + +### Building from Source + +```bash +# Install dependencies +npm install +pip3 install -r requirements.txt + +# Build TypeScript +npm run build + +# Watch mode for development +npm run dev +``` + +### Running Tests + +```bash +# TypeScript tests +npm run test:ts + +# Python tests +npm run test:py + +# All tests with coverage +npm run test:coverage +``` + +### Linting and Formatting + +```bash +# Lint TypeScript and Python +npm run lint + +# Format code +npm run format +``` + +## Troubleshooting + +### Server Not Appearing in Client + +**Symptoms:** MCP server doesn't show up in Claude Desktop or Cline + +**Solutions:** + +1. Verify build completed: `ls dist/index.js` +2. Check configuration paths are absolute +3. Restart MCP client completely +4. Check client logs for error messages + +### Python Module Import Errors + +**Symptoms:** `ModuleNotFoundError: No module named 'pcbnew'` + +**Solutions:** + +1. Verify KiCAD installation: `python3 -c "import pcbnew"` +2. Check PYTHONPATH in configuration matches your KiCAD installation +3. Ensure KiCAD was installed with Python support + +### Tool Execution Failures + +**Symptoms:** Tools fail with unclear errors + +**Solutions:** + +1. Check server logs: `~/.kicad-mcp/logs/kicad_interface.log` +2. Verify a project is loaded before running board operations +3. Ensure file paths are absolute, not relative +4. Check tool parameter types match schema requirements + +### Windows-Specific Issues + +**Symptoms:** Server fails to start on Windows + +**Solutions:** + +1. Run automated diagnostics: `.\setup-windows.ps1` +2. Verify Python path uses double backslashes: `C:\\Program Files\\KiCad\\9.0` +3. Check Windows Event Viewer for Node.js errors +4. See [Windows Troubleshooting Guide](docs/WINDOWS_TROUBLESHOOTING.md) + +### Getting Help + +1. Check the [GitHub Issues](https://github.com/mixelpixx/KiCAD-MCP-Server/issues) +2. Review server logs: `~/.kicad-mcp/logs/kicad_interface.log` +3. Open a new issue with: + - Operating system and version + - KiCAD version (`python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"`) + - Node.js version (`node --version`) + - Full error message and stack trace + - Relevant log excerpts + +## Project Status + +**Current Version:** 2.2.3 + +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):** + +- Project management with snapshot checkpointing +- Complete board design (outline, layers, zones, mounting holes, text, SVG logos) +- Component placement with arrays, alignment, and duplication +- Advanced routing (pad-to-pad with auto-via, differential pairs, pattern copying) +- Complete schematic workflow with dynamic symbol loading (~10,000 symbols) +- Intelligent wiring system with pin discovery and smart routing +- FFC/ribbon cable passthrough workflow +- Schematic-to-board synchronization +- Design rule checking (DRC and ERC) +- Export to Gerber, PDF, SVG, 3D, BOM, netlist, position file +- Custom footprint and symbol creation +- JLCPCB parts integration (2.5M+ parts catalog) +- Datasheet enrichment via LCSC +- Freerouting autorouter integration (Java, Docker, Podman) +- UI auto-launch and management +- Full MCP 2025-06-18 protocol compliance + +**IPC Backend (Experimental):** + +- Real-time UI synchronization via KiCAD 9.0 IPC API +- 21 IPC-enabled commands with automatic SWIG fallback +- Hybrid footprint loading (SWIG for library access, IPC for placement) + +**Developer Mode:** +Set `KICAD_MCP_DEV=1` to capture MCP session logs for debugging. See CHANGELOG v2.2.3 for details. + +See [ROADMAP.md](docs/ROADMAP.md) for planned features. + +## What Do You Want to See Next? + +We are actively developing new features. Your feedback directly shapes development priorities. + +**Share your ideas:** + +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) +3. Star the repo if you find it useful + +## Contributing + +Contributions are welcome! Please follow these guidelines: + +1. **Report Bugs:** Open an issue with reproduction steps +2. **Suggest Features:** Describe use case and expected behavior +3. **Submit Pull Requests:** + - Fork the repository + - Create a feature branch + - Follow existing code style + - Add tests for new functionality + - Update documentation + - Submit PR with clear description + +See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines. + +## License + +This project is licensed under the MIT License. See [LICENSE](LICENSE) for details. + +## Acknowledgments + +- Built on the [Model Context Protocol](https://modelcontextprotocol.io/) by Anthropic +- Powered by [KiCAD](https://www.kicad.org/) open-source PCB design software +- Uses [kicad-skip](https://github.com/kicad-skip) for schematic manipulation +- [JLCSearch API](https://jlcsearch.tscircuit.com/) by [@tscircuit](https://github.com/tscircuit/jlcsearch) - Public JLCPCB parts API +- [JLCParts Database](https://github.com/yaqwsx/jlcparts) by [@yaqwsx](https://github.com/yaqwsx) - JLCPCB parts data + +### Community Contributors + +- [@Kletternaut](https://github.com/Kletternaut) - Routing/component tools, footprint/symbol creators, passthrough workflow, template fixes (PRs #44, #48, #49, #51, #53, #57, #59) +- [@Mehanik](https://github.com/Mehanik) - Schematic inspection/editing tools, component field positions (PRs #60, #66, #67) +- [@jflaflamme](https://github.com/jflaflamme) - Freerouting autorouter integration with Docker/Podman support (PR #68) +- [@l3wi](https://github.com/l3wi) - Local symbol library search, JLCPCB third-party library support (PR #25) +- [@gwall-ceres](https://github.com/gwall-ceres) - MCP protocol compliance, Windows compatibility (PR #10) +- [@fariouche](https://github.com/fariouche) - Bug fixes (PR #17) +- [@shuofengzhang](https://github.com/shuofengzhang) - XDG relative path handling (PR #58) +- [@sid115](https://github.com/sid115) - Windows setup script improvements (PR #13) +- [@pasrom](https://github.com/pasrom) - MCP server bug fixes (PR #50) + +## Citation + +If you use this project in your research or publication, please cite: + +```bibtex +@software{kicad_mcp_server, + title = {KiCAD MCP Server: AI-Assisted PCB Design}, + author = {mixelpixx}, + year = {2025}, + url = {https://github.com/mixelpixx/KiCAD-MCP-Server}, + version = {2.2.3} +} +``` diff --git a/config/linux-config.example.json b/config/linux-config.example.json index 880cf81..7d2d92c 100644 --- a/config/linux-config.example.json +++ b/config/linux-config.example.json @@ -1,15 +1,15 @@ -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/home/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], - "env": { - "NODE_ENV": "production", - "PYTHONPATH": "/usr/share/kicad/scripting/plugins:/usr/lib/kicad/lib/python3/dist-packages", - "LOG_LEVEL": "info", - "KICAD_AUTO_LAUNCH": "false" - }, - "description": "KiCAD PCB Design Assistant - Note: PYTHONPATH auto-detected if venv exists" - } - } -} +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/home/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], + "env": { + "NODE_ENV": "production", + "PYTHONPATH": "/usr/share/kicad/scripting/plugins:/usr/lib/kicad/lib/python3/dist-packages", + "LOG_LEVEL": "info", + "KICAD_AUTO_LAUNCH": "false" + }, + "description": "KiCAD PCB Design Assistant - Note: PYTHONPATH auto-detected if venv exists" + } + } +} diff --git a/config/macos-config.example.json b/config/macos-config.example.json index a62e82a..5d2286c 100644 --- a/config/macos-config.example.json +++ b/config/macos-config.example.json @@ -1,15 +1,15 @@ -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/Users/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], - "env": { - "NODE_ENV": "production", - "PYTHONPATH": "/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/lib/python3.11/site-packages", - "LOG_LEVEL": "info", - "KICAD_AUTO_LAUNCH": "false" - }, - "description": "KiCAD PCB Design Assistant - Note: PYTHONPATH auto-detected if venv exists" - } - } -} +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/Users/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], + "env": { + "NODE_ENV": "production", + "PYTHONPATH": "/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/lib/python3.11/site-packages", + "LOG_LEVEL": "info", + "KICAD_AUTO_LAUNCH": "false" + }, + "description": "KiCAD PCB Design Assistant - Note: PYTHONPATH auto-detected if venv exists" + } + } +} diff --git a/config/windows-config.example.json b/config/windows-config.example.json index 7fdb060..796cfd2 100644 --- a/config/windows-config.example.json +++ b/config/windows-config.example.json @@ -1,16 +1,16 @@ -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["C:\\Users\\YOUR_USERNAME\\MCP\\KiCAD-MCP-Server\\dist\\index.js"], - "env": { - "NODE_ENV": "production", - "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\bin\\Lib\\site-packages", - "LOG_LEVEL": "info", - "KICAD_AUTO_LAUNCH": "false", - "KICAD_MCP_DEV": "0" - }, - "description": "KiCAD PCB Design Assistant - Note: PYTHONPATH auto-detected if venv exists" - } - } -} +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["C:\\Users\\YOUR_USERNAME\\MCP\\KiCAD-MCP-Server\\dist\\index.js"], + "env": { + "NODE_ENV": "production", + "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\bin\\Lib\\site-packages", + "LOG_LEVEL": "info", + "KICAD_AUTO_LAUNCH": "false", + "KICAD_MCP_DEV": "0" + }, + "description": "KiCAD PCB Design Assistant - Note: PYTHONPATH auto-detected if venv exists" + } + } +} diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index d29e15c..b99c420 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -118,10 +118,12 @@ KiCAD-MCP-Server/ ### Tool Registration Each tool file exports a `register*Tools(server, callKicadScript)` function that: + - Defines tool name, description, and Zod schema for parameters - Registers a handler that calls `callKicadScript(command, args)` Example from `src/tools/project.ts`: + ```typescript server.tool( "create_project", @@ -130,13 +132,14 @@ server.tool( async (args) => { const result = await callKicadScript("create_project", args); return { content: [{ type: "text", text: JSON.stringify(result) }] }; - } + }, ); ``` ### Tool Router (`src/tools/router.ts` and `src/tools/registry.ts`) The router pattern reduces AI context usage: + - `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` - 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 `callKicadScript(command, args)` in `server.ts`: + 1. Spawns `python3 python/kicad_interface.py` (if not already running) 2. Sends a JSON message: `{"command": "...", "params": {...}}` 3. Reads the JSON response @@ -164,6 +168,7 @@ The router pattern reduces AI context usage: ### Command Routing Commands are routed by name to handler methods. The mapping is defined in `kicad_interface.py`. Each handler: + 1. Receives a params dict 2. Calls the appropriate command class method 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: **SWIG Backend** (default): + - Direct Python bindings to KiCAD's C++ API via SWIG - Operates on files -- loads .kicad_pcb, modifies in memory, saves back - Works without KiCAD running - Requires manual UI reload to see changes **IPC Backend** (experimental): + - Communicates with running KiCAD via IPC API socket - Changes appear in the UI immediately - Requires KiCAD 9.0+ running with IPC enabled @@ -189,6 +196,7 @@ Two backends for interacting with KiCAD: ### Schematic System Schematic manipulation uses a different stack than PCB operations: + - **kicad-skip** library for reading/modifying schematic files - **S-expression parsing** for direct file manipulation (wires, symbols) - **DynamicSymbolLoader** for injecting any KiCad symbol into a schematic @@ -214,7 +222,7 @@ server.tool( async (args) => { const result = await callKicadScript("my_new_tool", args); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; - } + }, ); ``` @@ -271,11 +279,13 @@ npm run test:py # Run Python tests ### Python Tests Located in `python/tests/`. Run with: + ```bash pytest python/tests/ -v ``` Key test files: + - `test_schematic_tools.py` -- schematic tool tests - `test_freerouting.py` -- autorouter tests - `test_delete_schematic_component.py` -- component deletion tests @@ -302,13 +312,13 @@ Key test files: ## Source Files Reference -| File | Purpose | -|------|---------| -| `src/server.ts` | MCP server, subprocess management | -| `src/tools/registry.ts` | Tool categories and organization | -| `src/tools/router.ts` | Router meta-tools | -| `python/kicad_interface.py` | Python entry point, command routing | -| `python/kicad_api/factory.py` | Backend selection | -| `python/commands/dynamic_symbol_loader.py` | Symbol injection system | -| `python/commands/wire_manager.py` | Wire creation engine | -| `python/commands/pin_locator.py` | Pin position discovery | +| File | Purpose | +| ------------------------------------------ | ----------------------------------- | +| `src/server.ts` | MCP server, subprocess management | +| `src/tools/registry.ts` | Tool categories and organization | +| `src/tools/router.ts` | Router meta-tools | +| `python/kicad_interface.py` | Python entry point, command routing | +| `python/kicad_api/factory.py` | Backend selection | +| `python/commands/dynamic_symbol_loader.py` | Symbol injection system | +| `python/commands/wire_manager.py` | Wire creation engine | +| `python/commands/pin_locator.py` | Pin position discovery | diff --git a/docs/CLIENT_CONFIGURATION.md b/docs/CLIENT_CONFIGURATION.md index 5532a62..bcfd088 100644 --- a/docs/CLIENT_CONFIGURATION.md +++ b/docs/CLIENT_CONFIGURATION.md @@ -1,543 +1,538 @@ -# KiCAD MCP Server - Client Configuration Guide - -This guide shows how to configure the KiCAD MCP Server with various MCP-compatible clients. - ---- - -## Quick Reference - -| Client | Config File Location | -|--------|---------------------| -| **Claude Desktop** | Linux: `~/.config/Claude/claude_desktop_config.json`
macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
Windows: `%APPDATA%\Claude\claude_desktop_config.json` | -| **Cline (VSCode)** | VSCode Settings → Extensions → Cline → MCP Settings | -| **Claude Code** | `~/.config/claude-code/mcp_config.json` | - ---- - -## 1. Claude Desktop - -### Linux Configuration - -**File:** `~/.config/Claude/claude_desktop_config.json` - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/home/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages", - "NODE_ENV": "production" - } - } - } -} -``` - -**Important:** Replace `/home/YOUR_USERNAME` with your actual home directory path. - -### macOS Configuration - -**File:** `~/Library/Application Support/Claude/claude_desktop_config.json` - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/Users/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"] - } - } -} -``` - -**Note:** For standard KiCad installations in `/Applications/KiCad/`, the server auto-detects KiCad's bundled Python (versions 3.9-3.12). No `PYTHONPATH` configuration is required. - -If KiCad is installed in a non-standard location, you can override the Python path: - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/Users/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], - "env": { - "KICAD_PYTHON": "/custom/path/to/python3" - } - } - } -} -``` - -### Windows Configuration - -**File:** `%APPDATA%\Claude\claude_desktop_config.json` - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["C:\\Users\\YOUR_USERNAME\\MCP\\KiCAD-MCP-Server\\dist\\index.js"], - "env": { - "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\bin\\Lib\\site-packages", - "NODE_ENV": "production" - } - } - } -} -``` - -**Note:** Use double backslashes (`\\`) in Windows paths. - ---- - -## 2. Cline (VSCode Extension) - -### Configuration Steps - -1. Open VSCode -2. Install Cline extension from marketplace -3. Open Settings (Ctrl+,) -4. Search for "Cline MCP" -5. Click "Edit in settings.json" - -### settings.json Configuration - -```json -{ - "cline.mcpServers": { - "kicad": { - "command": "node", - "args": ["/home/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" - } - } - } -} -``` - -### Alternative: Workspace Configuration - -Create `.vscode/settings.json` in your project: - -```json -{ - "cline.mcpServers": { - "kicad": { - "command": "node", - "args": ["${workspaceFolder}/../KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" - } - } - } -} -``` - ---- - -## 3. Claude Code CLI - -### Configuration File - -**File:** `~/.config/claude-code/mcp_config.json` - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/home/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages", - "LOG_LEVEL": "info" - } - } - } -} -``` - -### Verify Configuration - -```bash -# List available MCP servers -claude-code mcp list - -# Test KiCAD server connection -claude-code mcp test kicad -``` - ---- - -## 4. Generic MCP Client - -For any MCP-compatible client that supports STDIO transport: - -### Basic Configuration - -```json -{ - "command": "node", - "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], - "transport": "stdio", - "env": { - "PYTHONPATH": "/path/to/kicad/python/packages" - } -} -``` - -### With Custom Config File - -```json -{ - "command": "node", - "args": [ - "/path/to/KiCAD-MCP-Server/dist/index.js", - "--config", - "/path/to/custom-config.json" - ], - "transport": "stdio" -} -``` - ---- - -## Environment Variables - -### Required - -| Variable | Description | Example | -|----------|-------------|---------| -| `PYTHONPATH` | Path to KiCAD Python modules | `/usr/lib/kicad/lib/python3/dist-packages` | - -### Optional - -| Variable | Description | Default | -|----------|-------------|---------| -| `LOG_LEVEL` | Logging verbosity | `info` | -| `NODE_ENV` | Node environment | `development` | -| `KICAD_BACKEND` | Force backend (`swig` or `ipc`) | Auto-detect | -| `KICAD_MCP_DEV` | Enable developer mode (auto-save logs to project) | `0` (disabled) | -| `FREEROUTING_JAR` | Path to FreeRouting JAR file for autorouting | Not set | - ---- - -## Finding KiCAD Python Path - -### Linux (Ubuntu/Debian) - -```bash -# Method 1: dpkg query -dpkg -L kicad | grep "site-packages" | head -1 - -# Method 2: Python auto-detect -python3 -c "from pathlib import Path; import sys; print([p for p in Path('/usr').rglob('pcbnew.py')])" - -# Method 3: Use platform helper -cd /path/to/KiCAD-MCP-Server -PYTHONPATH=python python3 -c "from utils.platform_helper import PlatformHelper; print(PlatformHelper.get_kicad_python_paths())" -``` - -### macOS - -```bash -# Typical location -/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/lib/python3.11/site-packages - -# Find dynamically -find /Applications/KiCad -name "pcbnew.py" -type f -``` - -### Windows - -```cmd -REM Typical location (KiCAD 9.0) -C:\Program Files\KiCad\9.0\bin\Lib\site-packages - -REM Search for pcbnew.py -where /r "C:\Program Files\KiCad" pcbnew.py -``` - ---- - -## Testing Your Configuration - -### 1. Verify Server Starts - -```bash -# Start server manually -node dist/index.js - -# Should see output like: -# [INFO] Using STDIO transport for local communication -# [INFO] Registering KiCAD tools, resources, and prompts... -# [INFO] Successfully connected to STDIO transport -``` - -Press Ctrl+C to stop. - -### 2. Test with Claude Desktop - -1. Restart Claude Desktop -2. Start a new conversation -3. Look for a "hammer" icon or "Tools" indicator -4. The KiCAD tools should be listed - -### 3. Test with Cline - -1. Open Cline panel in VSCode -2. Start a new chat -3. Type: "List available KiCAD tools" -4. Cline should show KiCAD MCP tools are available - -### 4. Test with Claude Code - -```bash -# Start Claude Code with MCP -claude-code - -# In the conversation, ask: -# "What KiCAD tools are available?" -``` - ---- - -## Troubleshooting - -### Server Not Starting - -**Error:** `Cannot find module 'pcbnew'` - -**Solution:** Verify `PYTHONPATH` is correct: -```bash -python3 -c "import sys; sys.path.append('/usr/lib/kicad/lib/python3/dist-packages'); import pcbnew; print(pcbnew.GetBuildVersion())" -``` - -**Error:** `ENOENT: no such file or directory` - -**Solution:** Check that `dist/index.js` exists: -```bash -cd /path/to/KiCAD-MCP-Server -npm run build -ls -lh dist/index.js -``` - -### Client Can't Connect - -**Issue:** Claude Desktop doesn't show KiCAD tools - -**Solutions:** -1. Restart Claude Desktop completely (quit, not just close window) -2. Check config file syntax with `jq`: - ```bash - jq . ~/.config/Claude/claude_desktop_config.json - ``` -3. Check Claude Desktop logs: - - Linux: `~/.config/Claude/logs/` - - macOS: `~/Library/Logs/Claude/` - - Windows: `%APPDATA%\Claude\logs\` - -### Python Module Errors - -**Error:** `ModuleNotFoundError: No module named 'kicad_api'` - -**Solution:** Server is looking for the wrong Python modules. This is an internal error. Check: -```bash -# 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" -``` - ---- - -## Advanced Configuration - -### Multiple KiCAD Versions - -If you have multiple KiCAD versions installed: - -```json -{ - "mcpServers": { - "kicad-9": { - "command": "node", - "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/lib/kicad-9/lib/python3/dist-packages" - } - }, - "kicad-8": { - "command": "node", - "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/lib/kicad-8/lib/python3/dist-packages" - } - } - } -} -``` - -### Custom Logging - -Create a custom config file `config/production.json`: - -```json -{ - "logLevel": "debug", - "python": { - "executable": "python3", - "timeout": 30000 - } -} -``` - -Then use it: - -```json -{ - "command": "node", - "args": [ - "/path/to/dist/index.js", - "--config", - "/path/to/config/production.json" - ] -} -``` - -### Development vs Production - -Development (verbose logging): -```json -{ - "env": { - "NODE_ENV": "development", - "LOG_LEVEL": "debug" - } -} -``` - -Production (minimal logging): -```json -{ - "env": { - "NODE_ENV": "production", - "LOG_LEVEL": "info" - } -} -``` - ---- - -## Platform-Specific Examples - -### Ubuntu 24.04 LTS - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/home/chris/MCP/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/share/kicad/scripting/plugins:/usr/lib/kicad/lib/python3/dist-packages" - } - } - } -} -``` - -### Arch Linux - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/home/user/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/lib/python3.12/site-packages" - } - } - } -} -``` - -### Windows 11 with WSL2 - -Running server in WSL2, client on Windows: - -```json -{ - "mcpServers": { - "kicad": { - "command": "wsl", - "args": [ - "node", - "/home/user/KiCAD-MCP-Server/dist/index.js" - ], - "env": { - "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" - } - } - } -} -``` - ---- - -## Security Considerations - -### File Permissions - -Ensure config files are only readable by your user: - -```bash -chmod 600 ~/.config/Claude/claude_desktop_config.json -``` - -### Network Isolation - -The KiCAD MCP Server uses STDIO transport (no network ports), providing isolation by default. - -### Code Execution - -The server executes Python scripts from the `python/` directory. Only run servers from trusted sources. - ---- - -## Next Steps - -After configuration: - -1. **Test Basic Functionality** - - Ask: "Create a new KiCAD project called 'test'" - - Ask: "What tools are available for PCB design?" - -2. **Explore Resources** - - Ask: "Show me board information" - - Ask: "What layers are in my PCB?" - -3. **Try Advanced Features** - - Ask: "Add a resistor to my schematic" - - Ask: "Route a trace between two points" - ---- - -## Support - -If you encounter issues: - -1. Check logs in `~/.kicad-mcp/logs/` (if logging is enabled) -2. Verify KiCAD installation: `kicad-cli version` -3. Test Python modules: `python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"` -4. Review server startup logs (manual start with `node dist/index.js`) -5. Check client-specific logs (see Troubleshooting section) - -For bugs or feature requests, open an issue on GitHub. - ---- - -**Last Updated:** March 21, 2026 -**Version:** 2.2.3+ +# KiCAD MCP Server - Client Configuration Guide + +This guide shows how to configure the KiCAD MCP Server with various MCP-compatible clients. + +--- + +## Quick Reference + +| Client | Config File Location | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Claude Desktop** | Linux: `~/.config/Claude/claude_desktop_config.json`
macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
Windows: `%APPDATA%\Claude\claude_desktop_config.json` | +| **Cline (VSCode)** | VSCode Settings → Extensions → Cline → MCP Settings | +| **Claude Code** | `~/.config/claude-code/mcp_config.json` | + +--- + +## 1. Claude Desktop + +### Linux Configuration + +**File:** `~/.config/Claude/claude_desktop_config.json` + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/home/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages", + "NODE_ENV": "production" + } + } + } +} +``` + +**Important:** Replace `/home/YOUR_USERNAME` with your actual home directory path. + +### macOS Configuration + +**File:** `~/Library/Application Support/Claude/claude_desktop_config.json` + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/Users/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"] + } + } +} +``` + +**Note:** For standard KiCad installations in `/Applications/KiCad/`, the server auto-detects KiCad's bundled Python (versions 3.9-3.12). No `PYTHONPATH` configuration is required. + +If KiCad is installed in a non-standard location, you can override the Python path: + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/Users/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], + "env": { + "KICAD_PYTHON": "/custom/path/to/python3" + } + } + } +} +``` + +### Windows Configuration + +**File:** `%APPDATA%\Claude\claude_desktop_config.json` + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["C:\\Users\\YOUR_USERNAME\\MCP\\KiCAD-MCP-Server\\dist\\index.js"], + "env": { + "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\bin\\Lib\\site-packages", + "NODE_ENV": "production" + } + } + } +} +``` + +**Note:** Use double backslashes (`\\`) in Windows paths. + +--- + +## 2. Cline (VSCode Extension) + +### Configuration Steps + +1. Open VSCode +2. Install Cline extension from marketplace +3. Open Settings (Ctrl+,) +4. Search for "Cline MCP" +5. Click "Edit in settings.json" + +### settings.json Configuration + +```json +{ + "cline.mcpServers": { + "kicad": { + "command": "node", + "args": ["/home/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" + } + } + } +} +``` + +### Alternative: Workspace Configuration + +Create `.vscode/settings.json` in your project: + +```json +{ + "cline.mcpServers": { + "kicad": { + "command": "node", + "args": ["${workspaceFolder}/../KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" + } + } + } +} +``` + +--- + +## 3. Claude Code CLI + +### Configuration File + +**File:** `~/.config/claude-code/mcp_config.json` + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/home/YOUR_USERNAME/MCP/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages", + "LOG_LEVEL": "info" + } + } + } +} +``` + +### Verify Configuration + +```bash +# List available MCP servers +claude-code mcp list + +# Test KiCAD server connection +claude-code mcp test kicad +``` + +--- + +## 4. Generic MCP Client + +For any MCP-compatible client that supports STDIO transport: + +### Basic Configuration + +```json +{ + "command": "node", + "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], + "transport": "stdio", + "env": { + "PYTHONPATH": "/path/to/kicad/python/packages" + } +} +``` + +### With Custom Config File + +```json +{ + "command": "node", + "args": ["/path/to/KiCAD-MCP-Server/dist/index.js", "--config", "/path/to/custom-config.json"], + "transport": "stdio" +} +``` + +--- + +## Environment Variables + +### Required + +| Variable | Description | Example | +| ------------ | ---------------------------- | ------------------------------------------ | +| `PYTHONPATH` | Path to KiCAD Python modules | `/usr/lib/kicad/lib/python3/dist-packages` | + +### Optional + +| Variable | Description | Default | +| ----------------- | ------------------------------------------------- | -------------- | +| `LOG_LEVEL` | Logging verbosity | `info` | +| `NODE_ENV` | Node environment | `development` | +| `KICAD_BACKEND` | Force backend (`swig` or `ipc`) | Auto-detect | +| `KICAD_MCP_DEV` | Enable developer mode (auto-save logs to project) | `0` (disabled) | +| `FREEROUTING_JAR` | Path to FreeRouting JAR file for autorouting | Not set | + +--- + +## Finding KiCAD Python Path + +### Linux (Ubuntu/Debian) + +```bash +# Method 1: dpkg query +dpkg -L kicad | grep "site-packages" | head -1 + +# Method 2: Python auto-detect +python3 -c "from pathlib import Path; import sys; print([p for p in Path('/usr').rglob('pcbnew.py')])" + +# Method 3: Use platform helper +cd /path/to/KiCAD-MCP-Server +PYTHONPATH=python python3 -c "from utils.platform_helper import PlatformHelper; print(PlatformHelper.get_kicad_python_paths())" +``` + +### macOS + +```bash +# Typical location +/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/lib/python3.11/site-packages + +# Find dynamically +find /Applications/KiCad -name "pcbnew.py" -type f +``` + +### Windows + +```cmd +REM Typical location (KiCAD 9.0) +C:\Program Files\KiCad\9.0\bin\Lib\site-packages + +REM Search for pcbnew.py +where /r "C:\Program Files\KiCad" pcbnew.py +``` + +--- + +## Testing Your Configuration + +### 1. Verify Server Starts + +```bash +# Start server manually +node dist/index.js + +# Should see output like: +# [INFO] Using STDIO transport for local communication +# [INFO] Registering KiCAD tools, resources, and prompts... +# [INFO] Successfully connected to STDIO transport +``` + +Press Ctrl+C to stop. + +### 2. Test with Claude Desktop + +1. Restart Claude Desktop +2. Start a new conversation +3. Look for a "hammer" icon or "Tools" indicator +4. The KiCAD tools should be listed + +### 3. Test with Cline + +1. Open Cline panel in VSCode +2. Start a new chat +3. Type: "List available KiCAD tools" +4. Cline should show KiCAD MCP tools are available + +### 4. Test with Claude Code + +```bash +# Start Claude Code with MCP +claude-code + +# In the conversation, ask: +# "What KiCAD tools are available?" +``` + +--- + +## Troubleshooting + +### Server Not Starting + +**Error:** `Cannot find module 'pcbnew'` + +**Solution:** Verify `PYTHONPATH` is correct: + +```bash +python3 -c "import sys; sys.path.append('/usr/lib/kicad/lib/python3/dist-packages'); import pcbnew; print(pcbnew.GetBuildVersion())" +``` + +**Error:** `ENOENT: no such file or directory` + +**Solution:** Check that `dist/index.js` exists: + +```bash +cd /path/to/KiCAD-MCP-Server +npm run build +ls -lh dist/index.js +``` + +### Client Can't Connect + +**Issue:** Claude Desktop doesn't show KiCAD tools + +**Solutions:** + +1. Restart Claude Desktop completely (quit, not just close window) +2. Check config file syntax with `jq`: + ```bash + jq . ~/.config/Claude/claude_desktop_config.json + ``` +3. Check Claude Desktop logs: + - Linux: `~/.config/Claude/logs/` + - macOS: `~/Library/Logs/Claude/` + - Windows: `%APPDATA%\Claude\logs\` + +### Python Module Errors + +**Error:** `ModuleNotFoundError: No module named 'kicad_api'` + +**Solution:** Server is looking for the wrong Python modules. This is an internal error. Check: + +```bash +# 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" +``` + +--- + +## Advanced Configuration + +### Multiple KiCAD Versions + +If you have multiple KiCAD versions installed: + +```json +{ + "mcpServers": { + "kicad-9": { + "command": "node", + "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/kicad-9/lib/python3/dist-packages" + } + }, + "kicad-8": { + "command": "node", + "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/kicad-8/lib/python3/dist-packages" + } + } + } +} +``` + +### Custom Logging + +Create a custom config file `config/production.json`: + +```json +{ + "logLevel": "debug", + "python": { + "executable": "python3", + "timeout": 30000 + } +} +``` + +Then use it: + +```json +{ + "command": "node", + "args": ["/path/to/dist/index.js", "--config", "/path/to/config/production.json"] +} +``` + +### Development vs Production + +Development (verbose logging): + +```json +{ + "env": { + "NODE_ENV": "development", + "LOG_LEVEL": "debug" + } +} +``` + +Production (minimal logging): + +```json +{ + "env": { + "NODE_ENV": "production", + "LOG_LEVEL": "info" + } +} +``` + +--- + +## Platform-Specific Examples + +### Ubuntu 24.04 LTS + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/home/chris/MCP/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/share/kicad/scripting/plugins:/usr/lib/kicad/lib/python3/dist-packages" + } + } + } +} +``` + +### Arch Linux + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/home/user/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/python3.12/site-packages" + } + } + } +} +``` + +### Windows 11 with WSL2 + +Running server in WSL2, client on Windows: + +```json +{ + "mcpServers": { + "kicad": { + "command": "wsl", + "args": ["node", "/home/user/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" + } + } + } +} +``` + +--- + +## Security Considerations + +### File Permissions + +Ensure config files are only readable by your user: + +```bash +chmod 600 ~/.config/Claude/claude_desktop_config.json +``` + +### Network Isolation + +The KiCAD MCP Server uses STDIO transport (no network ports), providing isolation by default. + +### Code Execution + +The server executes Python scripts from the `python/` directory. Only run servers from trusted sources. + +--- + +## Next Steps + +After configuration: + +1. **Test Basic Functionality** + - Ask: "Create a new KiCAD project called 'test'" + - Ask: "What tools are available for PCB design?" + +2. **Explore Resources** + - Ask: "Show me board information" + - Ask: "What layers are in my PCB?" + +3. **Try Advanced Features** + - Ask: "Add a resistor to my schematic" + - Ask: "Route a trace between two points" + +--- + +## Support + +If you encounter issues: + +1. Check logs in `~/.kicad-mcp/logs/` (if logging is enabled) +2. Verify KiCAD installation: `kicad-cli version` +3. Test Python modules: `python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"` +4. Review server startup logs (manual start with `node dist/index.js`) +5. Check client-specific logs (see Troubleshooting section) + +For bugs or feature requests, open an issue on GitHub. + +--- + +**Last Updated:** March 21, 2026 +**Version:** 2.2.3+ diff --git a/docs/DATASHEET_TOOLS_GUIDE.md b/docs/DATASHEET_TOOLS_GUIDE.md index c161d35..afdc5d1 100644 --- a/docs/DATASHEET_TOOLS_GUIDE.md +++ b/docs/DATASHEET_TOOLS_GUIDE.md @@ -15,6 +15,7 @@ Scans a KiCAD schematic and fills in missing Datasheet URLs for components that **How it works:** For every placed symbol that has: + - An LCSC property set (e.g., `(property "LCSC" "C123456")`) - An empty or missing Datasheet field @@ -24,23 +25,26 @@ The URL is then visible in KiCAD's footprint browser, symbol properties dialog, **Parameters:** -| Parameter | Type | Required | Default | Description | -|-----------|------|----------|---------|-------------| -| `schematic_path` | string | Yes | -- | Path to the .kicad_sch file to enrich | -| `dry_run` | boolean | No | false | Preview changes without writing to disk | +| Parameter | Type | Required | Default | Description | +| ---------------- | ------- | -------- | ------- | --------------------------------------- | +| `schematic_path` | string | Yes | -- | Path to the .kicad_sch file to enrich | +| `dry_run` | boolean | No | false | Preview changes without writing to disk | **Returns:** + - Number of components updated - Number already set (skipped) - Number without LCSC number - Details of each updated component (reference, LCSC number, URL) **Example:** + ``` Enrich datasheets for all components in ~/Projects/MyBoard/MyBoard.kicad_sch ``` Use `dry_run=true` to preview what would change: + ``` Preview datasheet enrichment for ~/Projects/MyBoard/MyBoard.kicad_sch with dry run enabled. ``` @@ -53,15 +57,17 @@ Get the LCSC datasheet URL for a single component by LCSC number. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `lcsc` | string | Yes | LCSC part number, with or without "C" prefix (e.g., "C179739" or "179739") | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | -------------------------------------------------------------------------- | +| `lcsc` | string | Yes | LCSC part number, with or without "C" prefix (e.g., "C179739" or "179739") | **Returns:** + - Datasheet PDF URL - Product page URL **Example:** + ``` Get the datasheet URL for LCSC part C179739. ``` diff --git a/docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md b/docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md index 2c0e285..e016c0f 100644 --- a/docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md +++ b/docs/FOOTPRINT_SYMBOL_CREATOR_GUIDE.md @@ -12,63 +12,63 @@ 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. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `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' | -| `description` | string | No | Human-readable description | -| `tags` | string | No | Space-separated tag string, e.g. 'resistor SMD 0603' | -| `pads` | array | No | List of pad objects (see Pad Schema below). Can be empty for outlines-only footprints | -| `courtyard` | object | No | Courtyard rectangle on F.CrtYd (recommended: 0.25 mm clearance around pads) | -| `silkscreen` | object | No | Silkscreen rectangle on F.SilkS | -| `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) | -| `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) | +| Parameter | Type | Required | Description | +| --------------- | ------- | -------- | ------------------------------------------------------------------------------------------ | +| `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' | +| `description` | string | No | Human-readable description | +| `tags` | string | No | Space-separated tag string, e.g. 'resistor SMD 0603' | +| `pads` | array | No | List of pad objects (see Pad Schema below). Can be empty for outlines-only footprints | +| `courtyard` | object | No | Courtyard rectangle on F.CrtYd (recommended: 0.25 mm clearance around pads) | +| `silkscreen` | object | No | Silkscreen rectangle on F.SilkS | +| `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) | +| `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) | #### Pad Schema Each pad object in the `pads` array supports: -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `number` | string | Yes | Pad number / name, e.g. '1', '2', 'A1' | -| `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) | -| `at` | object | Yes | Pad centre position: {x: number, y: number, angle?: number} in mm | -| `size` | object | Yes | Pad size: {w: number, h: number} in mm | -| `drill` | number or object | No | Round drill diameter (mm) or oval drill {w: number, h: number} (required for thru_hole pads) | -| `layers` | array | No | Override default layer list, e.g. ['F.Cu','F.Paste','F.Mask'] | -| `roundrect_ratio` | number | No | Corner radius ratio for roundrect shape (0.0-0.5, default 0.25) | +| Parameter | Type | Required | Description | +| ----------------- | ---------------- | -------- | -------------------------------------------------------------------------------------------- | +| `number` | string | Yes | Pad number / name, e.g. '1', '2', 'A1' | +| `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) | +| `at` | object | Yes | Pad centre position: {x: number, y: number, angle?: number} in mm | +| `size` | object | Yes | Pad size: {w: number, h: number} in mm | +| `drill` | number or object | No | Round drill diameter (mm) or oval drill {w: number, h: number} (required for thru_hole pads) | +| `layers` | array | No | Override default layer list, e.g. ['F.Cu','F.Paste','F.Mask'] | +| `roundrect_ratio` | number | No | Corner radius ratio for roundrect shape (0.0-0.5, default 0.25) | #### Rectangle Schema (courtyard, silkscreen, fabLayer) -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `x1` | number | Yes | Left X in mm | -| `y1` | number | Yes | Top Y in mm | -| `x2` | number | Yes | Right X in mm | -| `y2` | number | Yes | Bottom Y in mm | -| `width` | number | No | Line width in mm | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | ---------------- | +| `x1` | number | Yes | Left X in mm | +| `y1` | number | Yes | Top Y in mm | +| `x2` | number | Yes | Right X in mm | +| `y2` | number | Yes | Bottom Y in mm | +| `width` | number | No | Line width in mm | #### Pad Types - **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 -- **NPTH (np_thru_hole)**: Non-plated through-holes for mechanical mounting. Requires `drill` parameter. Default layers: *.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 ### edit_footprint_pad 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 | -|-----------|------|----------|-------------| -| `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 | -| `size` | object | No | New pad size: {w: number, h: number} in mm | -| `at` | object | No | New pad position: {x: number, y: number, angle?: number} in mm | -| `drill` | number or object | No | New drill size: number (round) or {w: number, h: number} (oval) for THT pads | -| `shape` | enum | No | New pad shape: `rect`, `circle`, `oval`, or `roundrect` | +| Parameter | Type | Required | Description | +| --------------- | ---------------- | -------- | ---------------------------------------------------------------------------- | +| `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 | +| `size` | object | No | New pad size: {w: number, h: number} in mm | +| `at` | object | No | New pad position: {x: number, y: number, angle?: number} in mm | +| `drill` | number or object | No | New drill size: number (round) or {w: number, h: number} (oval) for THT pads | +| `shape` | enum | No | New pad shape: `rect`, `circle`, `oval`, or `roundrect` | **When to use:** Use this tool when you need to adjust an existing footprint's pad dimensions or positions without recreating the entire footprint. Useful for fine-tuning after initial creation or adapting existing footprints. @@ -76,13 +76,13 @@ 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'. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `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) | -| `description` | string | No | Optional description | -| `scope` | enum | No | `project` = writes fp-lib-table next to the .kicad_pro file (default); `global` = writes to the user's global KiCAD config | -| `projectPath` | string | No | Path to the .kicad_pro file or its directory (required for scope=project when the library is not in the project folder) | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------- | +| `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) | +| `description` | string | No | Optional description | +| `scope` | enum | No | `project` = writes fp-lib-table next to the .kicad_pro file (default); `global` = writes to the user's global KiCAD config | +| `projectPath` | string | No | Path to the .kicad_pro file or its directory (required for scope=project when the library is not in the project folder) | **How fp-lib-table works:** KiCAD maintains a table mapping library nicknames to filesystem paths. Project-scope tables (fp-lib-table in the project directory) take precedence over global tables. This allows project-specific libraries without polluting the global configuration. @@ -90,9 +90,9 @@ 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. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `searchPaths` | array | No | Override default search paths. Each entry should be a directory that contains .pretty subdirs | +| Parameter | Type | Required | Description | +| ------------- | ----- | -------- | --------------------------------------------------------------------------------------------- | +| `searchPaths` | array | No | Override default search paths. Each entry should be a directory that contains .pretty subdirs | ### 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. **Coordinate tips:** + - 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 right side: at.x = body_right + length, angle=180 (wire goes left) @@ -179,36 +180,37 @@ Pin positions are where the wire connects; the symbol body is drawn between them - Pins on bottom: at.y = body_bottom - length, angle=90 (wire goes up) - Standard pin length: 2.54 mm, standard grid: 2.54 mm -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `libraryPath` | string | Yes | Path to the .kicad_sym file (created if missing) | -| `name` | string | Yes | Symbol name, e.g. 'TMC2209', 'MyOpAmp' | -| `referencePrefix` | string | No | Schematic reference prefix: 'U' (IC), 'R' (resistor), 'J' (connector), etc. Default: 'U' | -| `description` | string | No | Human-readable description | -| `keywords` | string | No | Space-separated search keywords | -| `datasheet` | string | No | Datasheet URL or '~' | -| `footprint` | string | No | Default footprint, e.g. 'Package_SO:SOIC-8_3.9x4.9mm_P1.27mm' | -| `inBom` | boolean | No | Include in BOM (default true) | -| `onBoard` | boolean | No | Include in netlist for PCB (default true) | -| `pins` | array | No | List of pin objects (see Pin Schema below). Can be empty for graphical-only symbols | -| `rectangles` | array | No | Body rectangle(s). Typically one rectangle defining the IC body | -| `polylines` | array | No | Polyline graphics for custom body shapes (op-amp triangles, etc.) | -| `overwrite` | boolean | No | Replace existing symbol with same name (default false) | +| Parameter | Type | Required | Description | +| ----------------- | ------- | -------- | ---------------------------------------------------------------------------------------- | +| `libraryPath` | string | Yes | Path to the .kicad_sym file (created if missing) | +| `name` | string | Yes | Symbol name, e.g. 'TMC2209', 'MyOpAmp' | +| `referencePrefix` | string | No | Schematic reference prefix: 'U' (IC), 'R' (resistor), 'J' (connector), etc. Default: 'U' | +| `description` | string | No | Human-readable description | +| `keywords` | string | No | Space-separated search keywords | +| `datasheet` | string | No | Datasheet URL or '~' | +| `footprint` | string | No | Default footprint, e.g. 'Package_SO:SOIC-8_3.9x4.9mm_P1.27mm' | +| `inBom` | boolean | No | Include in BOM (default true) | +| `onBoard` | boolean | No | Include in netlist for PCB (default true) | +| `pins` | array | No | List of pin objects (see Pin Schema below). Can be empty for graphical-only symbols | +| `rectangles` | array | No | Body rectangle(s). Typically one rectangle defining the IC body | +| `polylines` | array | No | Polyline graphics for custom body shapes (op-amp triangles, etc.) | +| `overwrite` | boolean | No | Replace existing symbol with same name (default false) | #### Pin Schema Each pin object in the `pins` array supports: -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `name` | string | Yes | Pin name, e.g. 'VCC', 'GND', 'IN+', '~' for unnamed | -| `number` | string or number | Yes | Pin number, e.g. '1', '2', 'A1' | -| `type` | enum | Yes | Electrical pin type (see Pin Types below) | -| `at` | object | Yes | Pin endpoint position: {x: number, y: number, angle: number} where angle is the direction the pin wire extends FROM the symbol body | -| `length` | number | No | Pin length in mm (default 2.54) | -| `shape` | enum | No | Pin graphic shape (default: line) | +| Parameter | Type | Required | Description | +| --------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `name` | string | Yes | Pin name, e.g. 'VCC', 'GND', 'IN+', '~' for unnamed | +| `number` | string or number | Yes | Pin number, e.g. '1', '2', 'A1' | +| `type` | enum | Yes | Electrical pin type (see Pin Types below) | +| `at` | object | Yes | Pin endpoint position: {x: number, y: number, angle: number} where angle is the direction the pin wire extends FROM the symbol body | +| `length` | number | No | Pin length in mm (default 2.54) | +| `shape` | enum | No | Pin graphic shape (default: line) | **Pin angle conventions:** + - 0 = right (wire extends to the right from the symbol body) - 90 = up (wire extends upward) - 180 = left (wire extends to the left) @@ -216,82 +218,82 @@ Each pin object in the `pins` array supports: #### Pin Types (Electrical) -| Type | Description | -|------|-------------| -| `input` | Input pin | -| `output` | Output pin | -| `bidirectional` | Bidirectional I/O | -| `tri_state` | Tri-state output | -| `passive` | Passive component (resistors, capacitors) | -| `free` | Free pin (no electrical rule checking) | -| `unspecified` | Unspecified type | -| `power_in` | Power input (VCC, VDD) | -| `power_out` | Power output (regulators) | -| `open_collector` | Open collector output | -| `open_emitter` | Open emitter output | -| `no_connect` | Not connected | +| Type | Description | +| ---------------- | ----------------------------------------- | +| `input` | Input pin | +| `output` | Output pin | +| `bidirectional` | Bidirectional I/O | +| `tri_state` | Tri-state output | +| `passive` | Passive component (resistors, capacitors) | +| `free` | Free pin (no electrical rule checking) | +| `unspecified` | Unspecified type | +| `power_in` | Power input (VCC, VDD) | +| `power_out` | Power output (regulators) | +| `open_collector` | Open collector output | +| `open_emitter` | Open emitter output | +| `no_connect` | Not connected | #### Pin Shapes (Graphical) -| Shape | Description | -|-------|-------------| -| `line` | Standard pin (default) | -| `inverted` | Pin with inversion bubble | -| `clock` | Clock input (triangle) | -| `inverted_clock` | Inverted clock with bubble | -| `input_low` | Active-low input | -| `clock_low` | Active-low clock | -| `output_low` | Active-low output | -| `falling_edge_clock` | Falling edge triggered | -| `non_logic` | Non-logic pin | +| Shape | Description | +| -------------------- | -------------------------- | +| `line` | Standard pin (default) | +| `inverted` | Pin with inversion bubble | +| `clock` | Clock input (triangle) | +| `inverted_clock` | Inverted clock with bubble | +| `input_low` | Active-low input | +| `clock_low` | Active-low clock | +| `output_low` | Active-low output | +| `falling_edge_clock` | Falling edge triggered | +| `non_logic` | Non-logic pin | #### Rectangle Schema -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `x1` | number | Yes | Left X in mm | -| `y1` | number | Yes | Top Y in mm | -| `x2` | number | Yes | Right X in mm | -| `y2` | number | Yes | Bottom Y in mm | -| `width` | number | No | Stroke width in mm (default 0.254) | -| `fill` | enum | No | Fill type: `none`, `outline`, or `background` (default: background) | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | ------------------------------------------------------------------- | +| `x1` | number | Yes | Left X in mm | +| `y1` | number | Yes | Top Y in mm | +| `x2` | number | Yes | Right X in mm | +| `y2` | number | Yes | Bottom Y in mm | +| `width` | number | No | Stroke width in mm (default 0.254) | +| `fill` | enum | No | Fill type: `none`, `outline`, or `background` (default: background) | #### Polyline Schema -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `points` | array | Yes | List of XY points: [{x: number, y: number}, ...] in mm | -| `width` | number | No | Stroke width in mm (default 0.254) | -| `fill` | enum | No | Fill type: `none`, `outline`, or `background` | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | ------------------------------------------------------ | +| `points` | array | Yes | List of XY points: [{x: number, y: number}, ...] in mm | +| `width` | number | No | Stroke width in mm (default 0.254) | +| `fill` | enum | No | Fill type: `none`, `outline`, or `background` | ### delete_symbol Remove a symbol from a .kicad_sym library file. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `libraryPath` | string | Yes | Path to the .kicad_sym file | -| `name` | string | Yes | Symbol name to delete | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | --------------------------- | +| `libraryPath` | string | Yes | Path to the .kicad_sym file | +| `name` | string | Yes | Symbol name to delete | ### list_symbols_in_library List all symbol names in a .kicad_sym library file. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `libraryPath` | string | Yes | Path to the .kicad_sym file | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | --------------------------- | +| `libraryPath` | string | Yes | Path to the .kicad_sym file | ### register_symbol_library 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 | -|-----------|------|----------|-------------| -| `libraryPath` | string | Yes | Full path to the .kicad_sym file | -| `libraryName` | string | No | Nickname (default: file name without extension) | -| `description` | string | No | Optional description | -| `scope` | enum | No | `project` = writes sym-lib-table next to .kicad_pro (default); `global` = user config | -| `projectPath` | string | No | Path to .kicad_pro or its directory (for scope=project) | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ------------------------------------------------------------------------------------- | +| `libraryPath` | string | Yes | Full path to the .kicad_sym file | +| `libraryName` | string | No | Nickname (default: file name without extension) | +| `description` | string | No | Optional description | +| `scope` | enum | No | `project` = writes sym-lib-table next to .kicad_pro (default); `global` = user config | +| `projectPath` | string | No | Path to .kicad_pro or its directory (for scope=project) | ### Example: Creating a Simple IC Symbol @@ -351,6 +353,7 @@ This example creates a 4-pin IC symbol (VCC, GND, IN, OUT): ``` **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 - 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 @@ -397,6 +400,7 @@ Footprints use a "Y-down" coordinate system (like screen coordinates), while sym ### Validation After creating custom parts: + - Open KiCAD schematic editor and verify the symbol appears in the "Add Symbol" dialog - Check pin numbers, names, and electrical types in symbol properties - Open KiCAD PCB editor and verify the footprint appears in the footprint browser diff --git a/docs/FREEROUTING_GUIDE.md b/docs/FREEROUTING_GUIDE.md index 18dc73c..9e8cec4 100644 --- a/docs/FREEROUTING_GUIDE.md +++ b/docs/FREEROUTING_GUIDE.md @@ -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 `freeroutingJar` parameter on any tool call - 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 **Example:** + ``` 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 | **Example:** + ``` 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: + - Use the Freerouting GUI for interactive routing - Use a different autorouter that supports DSN/SES - 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" Freerouting 2.x requires Java 21+. Either: + - Upgrade your Java installation - Install Docker as a fallback ### Timeout Errors For complex boards, increase the timeout: + ``` Autoroute with timeout 600 and max passes 30. ``` @@ -203,6 +209,7 @@ Autoroute with timeout 600 and max passes 30. ### Routing Quality If the autorouter does not route all connections: + - Increase `maxPasses` (default: 20) - Check that your design rules allow the autorouter enough clearance - Run DRC after autorouting to identify any violations @@ -211,6 +218,7 @@ If the autorouter does not route all connections: ### Docker Permission Errors If Docker reports permission errors: + ```bash # Add your user to the docker group sudo usermod -aG docker $USER diff --git a/docs/INDEX.md b/docs/INDEX.md index 9e16e64..dd4a2b5 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -8,79 +8,79 @@ KiCAD MCP Server -- AI-assisted PCB design via Model Context Protocol ## Getting Started -| Document | Description | -|----------|-------------| -| [README](../README.md) | Project overview, installation, configuration, quick start | -| [Client Configuration](CLIENT_CONFIGURATION.md) | MCP client setup (Claude Desktop, Cline, Claude Code) | -| [Platform Guide](PLATFORM_GUIDE.md) | Linux vs Windows vs macOS differences | -| [PCB Design Workflow](PCB_DESIGN_WORKFLOW.md) | End-to-end design guide from project creation to manufacturing | +| Document | Description | +| ----------------------------------------------- | -------------------------------------------------------------- | +| [README](../README.md) | Project overview, installation, configuration, quick start | +| [Client Configuration](CLIENT_CONFIGURATION.md) | MCP client setup (Claude Desktop, Cline, Claude Code) | +| [Platform Guide](PLATFORM_GUIDE.md) | Linux vs Windows vs macOS differences | +| [PCB Design Workflow](PCB_DESIGN_WORKFLOW.md) | End-to-end design guide from project creation to manufacturing | --- ## Tool References -| Document | Description | -|----------|-------------| -| [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 | -| [Routing Tools Reference](ROUTING_TOOLS_REFERENCE.md) | 13 routing tools -- traces, vias, differential pairs, zones | -| [Footprint and Symbol Creator Guide](FOOTPRINT_SYMBOL_CREATOR_GUIDE.md) | 8 tools for creating custom footprints and symbols | -| [Freerouting Guide](FREEROUTING_GUIDE.md) | 4 autorouter tools -- setup, usage, Docker support | -| [SVG Import Guide](SVG_IMPORT_GUIDE.md) | Import SVG logos onto PCB layers | -| [Datasheet Tools Guide](DATASHEET_TOOLS_GUIDE.md) | Datasheet enrichment via LCSC | +| Document | Description | +| ----------------------------------------------------------------------- | ----------------------------------------------------------- | +| [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 | +| [Routing Tools Reference](ROUTING_TOOLS_REFERENCE.md) | 13 routing tools -- traces, vias, differential pairs, zones | +| [Footprint and Symbol Creator Guide](FOOTPRINT_SYMBOL_CREATOR_GUIDE.md) | 8 tools for creating custom footprints and symbols | +| [Freerouting Guide](FREEROUTING_GUIDE.md) | 4 autorouter tools -- setup, usage, Docker support | +| [SVG Import Guide](SVG_IMPORT_GUIDE.md) | Import SVG logos onto PCB layers | +| [Datasheet Tools Guide](DATASHEET_TOOLS_GUIDE.md) | Datasheet enrichment via LCSC | --- ## Integration Guides -| Document | Description | -|----------|-------------| -| [JLCPCB Integration](JLCPCB_INTEGRATION.md) | JLCPCB parts catalog, pricing, component selection | -| [JLCPCB Usage Guide](JLCPCB_USAGE_GUIDE.md) | Detailed JLCPCB setup and usage | -| [Library Integration](LIBRARY_INTEGRATION.md) | Footprint and symbol library setup | -| [IPC Backend Status](IPC_BACKEND_STATUS.md) | Real-time KiCAD UI synchronization (experimental) | +| Document | Description | +| --------------------------------------------- | -------------------------------------------------- | +| [JLCPCB Integration](JLCPCB_INTEGRATION.md) | JLCPCB parts catalog, pricing, component selection | +| [JLCPCB Usage Guide](JLCPCB_USAGE_GUIDE.md) | Detailed JLCPCB setup and usage | +| [Library Integration](LIBRARY_INTEGRATION.md) | Footprint and symbol library setup | +| [IPC Backend Status](IPC_BACKEND_STATUS.md) | Real-time KiCAD UI synchronization (experimental) | --- ## Workflows -| Document | Description | -|----------|-------------| -| [Realtime Workflow](REALTIME_WORKFLOW.md) | Working with IPC backend for live updates | -| [Visual Feedback](VISUAL_FEEDBACK.md) | UI visual feedback guide | -| [UI Auto Launch](UI_AUTO_LAUNCH.md) | Automatic KiCAD UI launch feature | -| [Router Guide](mcp-router-guide.md) | Tool router pattern usage | -| [Router Architecture](ROUTER_ARCHITECTURE.md) | Router pattern design | -| [Router Quick Start](ROUTER_QUICK_START.md) | Quick start for the router pattern | +| Document | Description | +| --------------------------------------------- | ----------------------------------------- | +| [Realtime Workflow](REALTIME_WORKFLOW.md) | Working with IPC backend for live updates | +| [Visual Feedback](VISUAL_FEEDBACK.md) | UI visual feedback guide | +| [UI Auto Launch](UI_AUTO_LAUNCH.md) | Automatic KiCAD UI launch feature | +| [Router Guide](mcp-router-guide.md) | Tool router pattern usage | +| [Router Architecture](ROUTER_ARCHITECTURE.md) | Router pattern design | +| [Router Quick Start](ROUTER_QUICK_START.md) | Quick start for the router pattern | --- ## Troubleshooting -| Document | Description | -|----------|-------------| -| [Known Issues](KNOWN_ISSUES.md) | Current issues and workarounds | -| [Windows Troubleshooting](WINDOWS_TROUBLESHOOTING.md) | Windows-specific problems | -| [Linux Compatibility Audit](LINUX_COMPATIBILITY_AUDIT.md) | Linux platform details | +| Document | Description | +| --------------------------------------------------------- | ------------------------------ | +| [Known Issues](KNOWN_ISSUES.md) | Current issues and workarounds | +| [Windows Troubleshooting](WINDOWS_TROUBLESHOOTING.md) | Windows-specific problems | +| [Linux Compatibility Audit](LINUX_COMPATIBILITY_AUDIT.md) | Linux platform details | --- ## Project Information -| Document | Description | -|----------|-------------| +| Document | Description | +| ----------------------------------- | ----------------------------------------- | | [Status Summary](STATUS_SUMMARY.md) | Current project status and feature matrix | -| [Roadmap](ROADMAP.md) | Development roadmap and planned features | -| [Changelog](../CHANGELOG.md) | Detailed release notes for all versions | +| [Roadmap](ROADMAP.md) | Development roadmap and planned features | +| [Changelog](../CHANGELOG.md) | Detailed release notes for all versions | --- ## For Contributors -| Document | Description | -|----------|-------------| -| [Contributing](../CONTRIBUTING.md) | How to contribute to the project | -| [Architecture](ARCHITECTURE.md) | System architecture and adding new tools | +| Document | Description | +| ---------------------------------- | ---------------------------------------- | +| [Contributing](../CONTRIBUTING.md) | How to contribute to the project | +| [Architecture](ARCHITECTURE.md) | System architecture and adding new tools | --- diff --git a/docs/IPC_BACKEND_STATUS.md b/docs/IPC_BACKEND_STATUS.md index fd0ed1e..5f70387 100644 --- a/docs/IPC_BACKEND_STATUS.md +++ b/docs/IPC_BACKEND_STATUS.md @@ -1,212 +1,223 @@ -# KiCAD IPC Backend Implementation Status - -**Status:** Under Active Development and Testing -**Date:** 2026-03-21 -**KiCAD Version:** 9.0+ -**kicad-python Version:** 0.5.0+ - ---- - -## Overview - -The IPC backend provides real-time UI synchronization with KiCAD 9.0+ via the official IPC API. When KiCAD is running with IPC enabled, commands can update the KiCAD UI immediately without requiring manual reload. - -This feature is experimental and under active testing. The server uses a hybrid approach: IPC when available, automatic fallback to SWIG when IPC is not connected. - -## Key Differences - -| Feature | SWIG | IPC | -|---------|------|-----| -| UI Updates | Manual reload required | Immediate (when working) | -| Undo/Redo | Not supported | Transaction support | -| API Stability | Deprecated in KiCAD 9 | Official, versioned | -| Connection | File-based | Live socket connection | -| KiCAD Required | No (file operations) | Yes (must be running) | - -## Implemented IPC Commands - -The following MCP commands have IPC handlers: - -| Command | IPC Handler | Status | -|---------|-------------|--------| -| `route_trace` | `_ipc_route_trace` | Implemented | -| `add_via` | `_ipc_add_via` | Implemented | -| `add_net` | `_ipc_add_net` | Implemented | -| `delete_trace` | `_ipc_delete_trace` | Falls back to SWIG | -| `get_nets_list` | `_ipc_get_nets_list` | Implemented | -| `add_copper_pour` | `_ipc_add_copper_pour` | Implemented | -| `refill_zones` | `_ipc_refill_zones` | Implemented | -| `add_text` | `_ipc_add_text` | Implemented | -| `add_board_text` | `_ipc_add_text` | Implemented | -| `set_board_size` | `_ipc_set_board_size` | Implemented | -| `get_board_info` | `_ipc_get_board_info` | Implemented | -| `add_board_outline` | `_ipc_add_board_outline` | Implemented | -| `add_mounting_hole` | `_ipc_add_mounting_hole` | Implemented | -| `get_layer_list` | `_ipc_get_layer_list` | Implemented | -| `place_component` | `_ipc_place_component` | Implemented (hybrid) | -| `move_component` | `_ipc_move_component` | Implemented | -| `rotate_component` | `_ipc_rotate_component` | Implemented | -| `delete_component` | `_ipc_delete_component` | Implemented | -| `get_component_list` | `_ipc_get_component_list` | Implemented | -| `get_component_properties` | `_ipc_get_component_properties` | Implemented | -| `save_project` | `_ipc_save_project` | Implemented | - -### Implemented Backend Features - -**Core Connection:** -- Connect to running KiCAD instance -- Auto-detect socket path (`/tmp/kicad/api.sock`) -- Version checking and validation -- Auto-fallback to SWIG when IPC unavailable -- Change notification callbacks - -**Board Operations:** -- Get board reference -- Get/Set board size -- List enabled layers -- Save board -- Add board outline segments -- Add mounting holes - -**Component Operations:** -- List all components -- Place component (hybrid: SWIG for library loading, IPC for placement) -- Move component -- Rotate component -- Delete component -- Get component properties - -**Routing Operations:** -- Add track -- Add via -- Get all tracks -- Get all vias -- Get all nets - -**Zone Operations:** -- Add copper pour zones -- Get zones list -- Refill zones - -**UI Integration:** -- Add text to board -- Get current selection -- Clear selection - -**Transaction Support:** -- Begin transaction -- Commit transaction (with description for undo) -- Rollback transaction - -## Usage - -### Prerequisites - -1. **KiCAD 9.0+** must be running -2. **IPC API must be enabled**: `Preferences > Plugins > Enable IPC API Server` -3. A board must be open in the PCB editor - -### Installation - -```bash -pip install kicad-python -``` - -### Testing - -Run the test script to verify IPC functionality: - -```bash -# Make sure KiCAD is running with IPC enabled and a board open -./venv/bin/python python/test_ipc_backend.py -``` - -## Architecture - -``` -+-------------------------------------------------------------+ -| MCP Server (TypeScript/Node.js) | -+---------------------------+---------------------------------+ - | JSON commands -+---------------------------v---------------------------------+ -| Python Interface Layer | -| +--------------------------------------------------------+ | -| | kicad_interface.py | | -| | - Routes commands to IPC or SWIG handlers | | -| | - IPC_CAPABLE_COMMANDS dict defines routing | | -| +--------------------------------------------------------+ | -| +--------------------------------------------------------+ | -| | kicad_api/ipc_backend.py | | -| | - IPCBackend (connection management) | | -| | - IPCBoardAPI (board operations) | | -| +--------------------------------------------------------+ | -+---------------------------+---------------------------------+ - | kicad-python (kipy) library -+---------------------------v---------------------------------+ -| Protocol Buffers over UNIX Sockets | -+---------------------------+---------------------------------+ - | -+---------------------------v---------------------------------+ -| KiCAD 9.0+ (IPC Server) | -+-------------------------------------------------------------+ -``` - -## Known Limitations - -1. **KiCAD must be running**: Unlike SWIG, IPC requires KiCAD to be open -2. **Project creation**: Not supported via IPC, uses file system -3. **Footprint library access**: Uses hybrid approach (SWIG loads from library, IPC places) -4. **Delete trace**: Falls back to SWIG (IPC API doesn't support direct deletion) -5. **Some operations may not work as expected**: This is experimental code - -## Troubleshooting - -### "Connection failed" -- Ensure KiCAD is running -- Enable IPC API: `Preferences > Plugins > Enable IPC API Server` -- Check if a board is open - -### "kicad-python not found" -```bash -pip install kicad-python -``` - -### "Version mismatch" -- Update kicad-python: `pip install --upgrade kicad-python` -- Ensure KiCAD 9.0+ is installed - -### "No board open" -- Open a board in KiCAD's PCB editor before connecting - -## File Structure - -``` -python/kicad_api/ -├── __init__.py # Package exports -├── base.py # Abstract base classes -├── factory.py # Backend auto-detection -├── ipc_backend.py # IPC implementation -└── swig_backend.py # Legacy SWIG wrapper - -python/ -└── test_ipc_backend.py # IPC test script -``` - -## Future Work - -1. More comprehensive testing of all IPC commands -2. Footprint library integration via IPC (when kipy supports it) -3. Schematic IPC support (when available in kicad-python) -4. Event subscriptions to react to changes made in KiCAD UI -5. Multi-board support - -## Related Documentation - -- [ROADMAP.md](./ROADMAP.md) - Project roadmap -- [IPC_API_MIGRATION_PLAN.md](./IPC_API_MIGRATION_PLAN.md) - Migration details -- [REALTIME_WORKFLOW.md](./REALTIME_WORKFLOW.md) - Collaboration workflows -- [kicad-python docs](https://docs.kicad.org/kicad-python-main/) - Official API docs - ---- - -**Last Updated:** 2026-03-21 +# KiCAD IPC Backend Implementation Status + +**Status:** Under Active Development and Testing +**Date:** 2026-03-21 +**KiCAD Version:** 9.0+ +**kicad-python Version:** 0.5.0+ + +--- + +## Overview + +The IPC backend provides real-time UI synchronization with KiCAD 9.0+ via the official IPC API. When KiCAD is running with IPC enabled, commands can update the KiCAD UI immediately without requiring manual reload. + +This feature is experimental and under active testing. The server uses a hybrid approach: IPC when available, automatic fallback to SWIG when IPC is not connected. + +## Key Differences + +| Feature | SWIG | IPC | +| -------------- | ---------------------- | ------------------------ | +| UI Updates | Manual reload required | Immediate (when working) | +| Undo/Redo | Not supported | Transaction support | +| API Stability | Deprecated in KiCAD 9 | Official, versioned | +| Connection | File-based | Live socket connection | +| KiCAD Required | No (file operations) | Yes (must be running) | + +## Implemented IPC Commands + +The following MCP commands have IPC handlers: + +| Command | IPC Handler | Status | +| -------------------------- | ------------------------------- | -------------------- | +| `route_trace` | `_ipc_route_trace` | Implemented | +| `add_via` | `_ipc_add_via` | Implemented | +| `add_net` | `_ipc_add_net` | Implemented | +| `delete_trace` | `_ipc_delete_trace` | Falls back to SWIG | +| `get_nets_list` | `_ipc_get_nets_list` | Implemented | +| `add_copper_pour` | `_ipc_add_copper_pour` | Implemented | +| `refill_zones` | `_ipc_refill_zones` | Implemented | +| `add_text` | `_ipc_add_text` | Implemented | +| `add_board_text` | `_ipc_add_text` | Implemented | +| `set_board_size` | `_ipc_set_board_size` | Implemented | +| `get_board_info` | `_ipc_get_board_info` | Implemented | +| `add_board_outline` | `_ipc_add_board_outline` | Implemented | +| `add_mounting_hole` | `_ipc_add_mounting_hole` | Implemented | +| `get_layer_list` | `_ipc_get_layer_list` | Implemented | +| `place_component` | `_ipc_place_component` | Implemented (hybrid) | +| `move_component` | `_ipc_move_component` | Implemented | +| `rotate_component` | `_ipc_rotate_component` | Implemented | +| `delete_component` | `_ipc_delete_component` | Implemented | +| `get_component_list` | `_ipc_get_component_list` | Implemented | +| `get_component_properties` | `_ipc_get_component_properties` | Implemented | +| `save_project` | `_ipc_save_project` | Implemented | + +### Implemented Backend Features + +**Core Connection:** + +- Connect to running KiCAD instance +- Auto-detect socket path (`/tmp/kicad/api.sock`) +- Version checking and validation +- Auto-fallback to SWIG when IPC unavailable +- Change notification callbacks + +**Board Operations:** + +- Get board reference +- Get/Set board size +- List enabled layers +- Save board +- Add board outline segments +- Add mounting holes + +**Component Operations:** + +- List all components +- Place component (hybrid: SWIG for library loading, IPC for placement) +- Move component +- Rotate component +- Delete component +- Get component properties + +**Routing Operations:** + +- Add track +- Add via +- Get all tracks +- Get all vias +- Get all nets + +**Zone Operations:** + +- Add copper pour zones +- Get zones list +- Refill zones + +**UI Integration:** + +- Add text to board +- Get current selection +- Clear selection + +**Transaction Support:** + +- Begin transaction +- Commit transaction (with description for undo) +- Rollback transaction + +## Usage + +### Prerequisites + +1. **KiCAD 9.0+** must be running +2. **IPC API must be enabled**: `Preferences > Plugins > Enable IPC API Server` +3. A board must be open in the PCB editor + +### Installation + +```bash +pip install kicad-python +``` + +### Testing + +Run the test script to verify IPC functionality: + +```bash +# Make sure KiCAD is running with IPC enabled and a board open +./venv/bin/python python/test_ipc_backend.py +``` + +## Architecture + +``` ++-------------------------------------------------------------+ +| MCP Server (TypeScript/Node.js) | ++---------------------------+---------------------------------+ + | JSON commands ++---------------------------v---------------------------------+ +| Python Interface Layer | +| +--------------------------------------------------------+ | +| | kicad_interface.py | | +| | - Routes commands to IPC or SWIG handlers | | +| | - IPC_CAPABLE_COMMANDS dict defines routing | | +| +--------------------------------------------------------+ | +| +--------------------------------------------------------+ | +| | kicad_api/ipc_backend.py | | +| | - IPCBackend (connection management) | | +| | - IPCBoardAPI (board operations) | | +| +--------------------------------------------------------+ | ++---------------------------+---------------------------------+ + | kicad-python (kipy) library ++---------------------------v---------------------------------+ +| Protocol Buffers over UNIX Sockets | ++---------------------------+---------------------------------+ + | ++---------------------------v---------------------------------+ +| KiCAD 9.0+ (IPC Server) | ++-------------------------------------------------------------+ +``` + +## Known Limitations + +1. **KiCAD must be running**: Unlike SWIG, IPC requires KiCAD to be open +2. **Project creation**: Not supported via IPC, uses file system +3. **Footprint library access**: Uses hybrid approach (SWIG loads from library, IPC places) +4. **Delete trace**: Falls back to SWIG (IPC API doesn't support direct deletion) +5. **Some operations may not work as expected**: This is experimental code + +## Troubleshooting + +### "Connection failed" + +- Ensure KiCAD is running +- Enable IPC API: `Preferences > Plugins > Enable IPC API Server` +- Check if a board is open + +### "kicad-python not found" + +```bash +pip install kicad-python +``` + +### "Version mismatch" + +- Update kicad-python: `pip install --upgrade kicad-python` +- Ensure KiCAD 9.0+ is installed + +### "No board open" + +- Open a board in KiCAD's PCB editor before connecting + +## File Structure + +``` +python/kicad_api/ +├── __init__.py # Package exports +├── base.py # Abstract base classes +├── factory.py # Backend auto-detection +├── ipc_backend.py # IPC implementation +└── swig_backend.py # Legacy SWIG wrapper + +python/ +└── test_ipc_backend.py # IPC test script +``` + +## Future Work + +1. More comprehensive testing of all IPC commands +2. Footprint library integration via IPC (when kipy supports it) +3. Schematic IPC support (when available in kicad-python) +4. Event subscriptions to react to changes made in KiCAD UI +5. Multi-board support + +## Related Documentation + +- [ROADMAP.md](./ROADMAP.md) - Project roadmap +- [IPC_API_MIGRATION_PLAN.md](./IPC_API_MIGRATION_PLAN.md) - Migration details +- [REALTIME_WORKFLOW.md](./REALTIME_WORKFLOW.md) - Collaboration workflows +- [kicad-python docs](https://docs.kicad.org/kicad-python-main/) - Official API docs + +--- + +**Last Updated:** 2026-03-21 diff --git a/docs/JLCPCB_INTEGRATION.md b/docs/JLCPCB_INTEGRATION.md index 18b8631..ce46967 100644 --- a/docs/JLCPCB_INTEGRATION.md +++ b/docs/JLCPCB_INTEGRATION.md @@ -1,344 +1,374 @@ -# JLCPCB Parts Integration - Complete Guide - -## Overview - -The KiCAD MCP Server integrates with JLCPCB's parts library to provide intelligent component selection, cost optimization, and automated part sourcing for PCB assembly. - -**Current Implementation**: Uses the **JLCSearch public API** (by tscircuit) for free, unauthenticated access to JLCPCB's ~100k parts catalog. - -## Features - -✅ **Parametric Search** - Find components by specifications (resistance, capacitance, package, etc.) -✅ **Price Comparison** - Compare Basic vs Extended library pricing -✅ **Alternative Suggestions** - Find cheaper or higher-stock alternatives -✅ **Footprint Mapping** - Automatic JLCPCB package to KiCad footprint mapping -✅ **Stock Availability** - Real-time stock levels from JLCPCB -✅ **No Authentication Required** - Public API, no API keys needed - -## Quick Start - -### 1. Search for Components - -```python -from commands.jlcsearch import JLCSearchClient - -client = JLCSearchClient() - -# Search for resistors -resistors = client.search_resistors( - resistance=10000, # 10kΩ - package="0603", - limit=20 -) - -# Search for capacitors -capacitors = client.search_capacitors( - capacitance=1e-7, # 100nF - package="0603", - limit=20 -) - -# General component search -components = client.search_components( - "components", - package="0603", - limit=100 -) -``` - -### 2. Get Part Details - -```python -# Get specific part by LCSC number -part = client.get_part_by_lcsc(25804) # C25804 -print(f"Part: {part['mfr']}") -print(f"Stock: {part['stock']}") -print(f"Price: ${part['price1']}") -print(f"Basic Library: {part['is_basic']}") -``` - -### 3. Database Integration - -```python -from commands.jlcpcb_parts import JLCPCBPartsManager - -# Initialize database -db = JLCPCBPartsManager() # Uses data/jlcpcb_parts.db - -# Download and import parts (one-time setup) -client = JLCSearchClient() -parts = client.download_all_components() -db.import_jlcsearch_parts(parts) - -# Search imported database -results = db.search_parts( - query="resistor", - package="0603", - library_type="Basic", - in_stock=True, - limit=20 -) -``` - -### 4. Footprint Mapping - -```python -# Map JLCPCB package to KiCad footprints -footprints = db.map_package_to_footprint("0603") -# Returns: -# [ -# "Resistor_SMD:R_0603_1608Metric", -# "Capacitor_SMD:C_0603_1608Metric", -# "LED_SMD:LED_0603_1608Metric" -# ] -``` - -## API Reference - -### JLCSearchClient - -#### `search_resistors(resistance, package, limit)` -Search for resistors by value and package. - -**Parameters:** -- `resistance` (int, optional): Resistance in ohms -- `package` (str, optional): Package size ("0402", "0603", "0805", etc.) -- `limit` (int): Maximum results (default: 100) - -**Returns:** List of resistor dicts with fields: -- `lcsc`: LCSC number (integer) -- `mfr`: Manufacturer part number -- `package`: Package size -- `is_basic`: True if Basic library part (no assembly fee) -- `resistance`: Resistance in ohms -- `tolerance_fraction`: Tolerance (0.01 = 1%) -- `power_watts`: Power rating in mW -- `stock`: Available stock -- `price1`: Unit price in USD - -#### `search_capacitors(capacitance, package, limit)` -Search for capacitors by value and package. - -**Parameters:** -- `capacitance` (float, optional): Capacitance in farads (e.g., 1e-7 for 100nF) -- `package` (str, optional): Package size -- `limit` (int): Maximum results - -**Returns:** List of capacitor dicts - -#### `search_components(category, limit, offset, **filters)` -General component search. - -**Parameters:** -- `category` (str): "resistors", "capacitors", "components", etc. -- `limit` (int): Maximum results -- `offset` (int): Pagination offset -- `**filters`: Additional filters (package="0603", lcsc=25804, etc.) - -**Returns:** List of component dicts - -#### `download_all_components(callback, batch_size)` -Download entire JLCPCB parts catalog. - -**Parameters:** -- `callback` (callable, optional): Progress callback(parts_count, status_msg) -- `batch_size` (int): Parts per batch (default: 1000) - -**Returns:** List of all parts (~100k components) - -**Note:** This may take 5-10 minutes to complete. - -### JLCPCBPartsManager - -#### `import_jlcsearch_parts(parts, progress_callback)` -Import parts from JLCSearch into local SQLite database. - -**Parameters:** -- `parts` (list): List of part dicts from JLCSearchClient -- `progress_callback` (callable, optional): Progress updates - -#### `search_parts(query, category, package, library_type, manufacturer, in_stock, limit)` -Search local database with filters. - -**Parameters:** -- `query` (str, optional): Free-text search -- `category` (str, optional): Category filter -- `package` (str, optional): Package filter -- `library_type` (str, optional): "Basic", "Extended", or "Preferred" -- `manufacturer` (str, optional): Manufacturer filter -- `in_stock` (bool): Only in-stock parts (default: True) -- `limit` (int): Maximum results - -**Returns:** List of matching parts - -#### `get_part_info(lcsc_number)` -Get detailed part information. - -**Parameters:** -- `lcsc_number` (str): LCSC part number (e.g., "C25804") - -**Returns:** Part dict or None - -#### `get_database_stats()` -Get database statistics. - -**Returns:** Dict with: -- `total_parts`: Total parts count -- `basic_parts`: Basic library count -- `extended_parts`: Extended library count -- `in_stock`: Parts with stock > 0 -- `db_path`: Database file path - -#### `map_package_to_footprint(package)` -Map JLCPCB package to KiCad footprints. - -**Parameters:** -- `package` (str): JLCPCB package name - -**Returns:** List of KiCad footprint library references - -## Data Format - -### JLCSearch Part Object - -```json -{ - "lcsc": 25804, - "mfr": "0603WAF1002T5E", - "package": "0603", - "is_basic": true, - "is_preferred": false, - "resistance": 10000, - "tolerance_fraction": 0.01, - "power_watts": 100, - "stock": 37165617, - "price1": 0.000842857 -} -``` - -### Database Schema - -```sql -CREATE TABLE components ( - lcsc TEXT PRIMARY KEY, -- "C25804" - category TEXT, -- "Resistors" - subcategory TEXT, -- "Chip Resistor" - mfr_part TEXT, -- "0603WAF1002T5E" - package TEXT, -- "0603" - solder_joints INTEGER, - manufacturer TEXT, - library_type TEXT, -- "Basic" or "Extended" - description TEXT, -- "10kΩ ±1% 100mW" - datasheet TEXT, - stock INTEGER, - price_json TEXT, -- JSON array of price breaks - last_updated INTEGER -- Unix timestamp -); -``` - -## Package to Footprint Mappings - -| JLCPCB Package | KiCad Footprints | -|----------------|------------------| -| 0402 | Resistor_SMD:R_0402_1005Metric
Capacitor_SMD:C_0402_1005Metric
LED_SMD:LED_0402_1005Metric | -| 0603 | Resistor_SMD:R_0603_1608Metric
Capacitor_SMD:C_0603_1608Metric
LED_SMD:LED_0603_1608Metric | -| 0805 | Resistor_SMD:R_0805_2012Metric
Capacitor_SMD:C_0805_2012Metric | -| 1206 | Resistor_SMD:R_1206_3216Metric
Capacitor_SMD:C_1206_3216Metric | -| SOT-23 | Package_TO_SOT_SMD:SOT-23
Package_TO_SOT_SMD:SOT-23-3 | -| SOT-23-5 | Package_TO_SOT_SMD:SOT-23-5 | -| SOT-23-6 | Package_TO_SOT_SMD:SOT-23-6 | -| SOT-223 | Package_TO_SOT_SMD:SOT-223 | -| SOIC-8 | Package_SO:SOIC-8_3.9x4.9mm_P1.27mm | -| QFN-20 | Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.5x2.5mm | - -## Best Practices - -### 1. Always Use Basic Library Parts First -Basic library parts have **no assembly fee** ($0/part), while Extended parts cost **$3/part**. - -```python -# Filter for Basic parts only -basic_parts = [p for p in results if p['is_basic']] -``` - -### 2. Check Stock Availability -Ensure sufficient stock before committing to a design. - -```python -# Only use parts with >1000 stock -high_stock = [p for p in results if p['stock'] > 1000] -``` - -### 3. Compare Prices -Even within Basic library, prices vary significantly. - -```python -# Find cheapest option -cheapest = min(results, key=lambda x: x.get('price1', 999)) -``` - -### 4. Use Standardized Packages -Stick to common packages (0402, 0603, 0805) for better availability and pricing. - -### 5. Cache Database Locally -Download the full parts database once and search locally for faster results. - -```python -# Initial download (one-time, ~5-10 minutes) -if not os.path.exists("data/jlcpcb_parts.db"): - parts = client.download_all_components() - db.import_jlcsearch_parts(parts) - -# Subsequent searches use local database (instant) -results = db.search_parts(...) -``` - -## Troubleshooting - -### API Rate Limiting -JLCSearch is a community service. If you hit rate limits: -- Add delays between requests (`time.sleep(0.1)`) -- Use the local database instead of repeated API calls -- Download the full database once and work offline - -### Missing Data -JLCSearch may not have all fields that official JLCPCB API provides: -- No datasheets (use manufacturer website) -- Limited category information -- No solder joint count - -### Stock Discrepancies -Stock levels are updated periodically but may lag real-time JLCPCB data by a few hours. - -## Official JLCPCB API (Alternative) - -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) -2. APP_ID, ACCESS_KEY, and SECRET_KEY credentials -3. Previous order history with JLCPCB - -To use the official API instead of JLCSearch: - -```python -from commands.jlcpcb import JLCPCBClient - -# Set credentials in .env file: -# JLCPCB_APP_ID= -# JLCPCB_API_KEY= -# JLCPCB_API_SECRET= - -client = JLCPCBClient(app_id, access_key, secret_key) -data = client.fetch_parts_page() -``` - -**Note:** Most users should use JLCSearch public API instead, as it's freely available and requires no authentication. - -## Credits - -- **JLCSearch API**: https://jlcsearch.tscircuit.com/ (by [@tscircuit](https://github.com/tscircuit/jlcsearch)) -- **JLCParts Database**: https://github.com/yaqwsx/jlcparts (by [@yaqwsx](https://github.com/yaqwsx)) -- **JLCPCB**: https://jlcpcb.com/ (official parts library provider) - -## License - -This integration uses publicly available JLCPCB parts data via the JLCSearch community service. Users must comply with JLCPCB's terms of service when using this data for production PCB orders. +# JLCPCB Parts Integration - Complete Guide + +## Overview + +The KiCAD MCP Server integrates with JLCPCB's parts library to provide intelligent component selection, cost optimization, and automated part sourcing for PCB assembly. + +**Current Implementation**: Uses the **JLCSearch public API** (by tscircuit) for free, unauthenticated access to JLCPCB's ~100k parts catalog. + +## Features + +✅ **Parametric Search** - Find components by specifications (resistance, capacitance, package, etc.) +✅ **Price Comparison** - Compare Basic vs Extended library pricing +✅ **Alternative Suggestions** - Find cheaper or higher-stock alternatives +✅ **Footprint Mapping** - Automatic JLCPCB package to KiCad footprint mapping +✅ **Stock Availability** - Real-time stock levels from JLCPCB +✅ **No Authentication Required** - Public API, no API keys needed + +## Quick Start + +### 1. Search for Components + +```python +from commands.jlcsearch import JLCSearchClient + +client = JLCSearchClient() + +# Search for resistors +resistors = client.search_resistors( + resistance=10000, # 10kΩ + package="0603", + limit=20 +) + +# Search for capacitors +capacitors = client.search_capacitors( + capacitance=1e-7, # 100nF + package="0603", + limit=20 +) + +# General component search +components = client.search_components( + "components", + package="0603", + limit=100 +) +``` + +### 2. Get Part Details + +```python +# Get specific part by LCSC number +part = client.get_part_by_lcsc(25804) # C25804 +print(f"Part: {part['mfr']}") +print(f"Stock: {part['stock']}") +print(f"Price: ${part['price1']}") +print(f"Basic Library: {part['is_basic']}") +``` + +### 3. Database Integration + +```python +from commands.jlcpcb_parts import JLCPCBPartsManager + +# Initialize database +db = JLCPCBPartsManager() # Uses data/jlcpcb_parts.db + +# Download and import parts (one-time setup) +client = JLCSearchClient() +parts = client.download_all_components() +db.import_jlcsearch_parts(parts) + +# Search imported database +results = db.search_parts( + query="resistor", + package="0603", + library_type="Basic", + in_stock=True, + limit=20 +) +``` + +### 4. Footprint Mapping + +```python +# Map JLCPCB package to KiCad footprints +footprints = db.map_package_to_footprint("0603") +# Returns: +# [ +# "Resistor_SMD:R_0603_1608Metric", +# "Capacitor_SMD:C_0603_1608Metric", +# "LED_SMD:LED_0603_1608Metric" +# ] +``` + +## API Reference + +### JLCSearchClient + +#### `search_resistors(resistance, package, limit)` + +Search for resistors by value and package. + +**Parameters:** + +- `resistance` (int, optional): Resistance in ohms +- `package` (str, optional): Package size ("0402", "0603", "0805", etc.) +- `limit` (int): Maximum results (default: 100) + +**Returns:** List of resistor dicts with fields: + +- `lcsc`: LCSC number (integer) +- `mfr`: Manufacturer part number +- `package`: Package size +- `is_basic`: True if Basic library part (no assembly fee) +- `resistance`: Resistance in ohms +- `tolerance_fraction`: Tolerance (0.01 = 1%) +- `power_watts`: Power rating in mW +- `stock`: Available stock +- `price1`: Unit price in USD + +#### `search_capacitors(capacitance, package, limit)` + +Search for capacitors by value and package. + +**Parameters:** + +- `capacitance` (float, optional): Capacitance in farads (e.g., 1e-7 for 100nF) +- `package` (str, optional): Package size +- `limit` (int): Maximum results + +**Returns:** List of capacitor dicts + +#### `search_components(category, limit, offset, **filters)` + +General component search. + +**Parameters:** + +- `category` (str): "resistors", "capacitors", "components", etc. +- `limit` (int): Maximum results +- `offset` (int): Pagination offset +- `**filters`: Additional filters (package="0603", lcsc=25804, etc.) + +**Returns:** List of component dicts + +#### `download_all_components(callback, batch_size)` + +Download entire JLCPCB parts catalog. + +**Parameters:** + +- `callback` (callable, optional): Progress callback(parts_count, status_msg) +- `batch_size` (int): Parts per batch (default: 1000) + +**Returns:** List of all parts (~100k components) + +**Note:** This may take 5-10 minutes to complete. + +### JLCPCBPartsManager + +#### `import_jlcsearch_parts(parts, progress_callback)` + +Import parts from JLCSearch into local SQLite database. + +**Parameters:** + +- `parts` (list): List of part dicts from JLCSearchClient +- `progress_callback` (callable, optional): Progress updates + +#### `search_parts(query, category, package, library_type, manufacturer, in_stock, limit)` + +Search local database with filters. + +**Parameters:** + +- `query` (str, optional): Free-text search +- `category` (str, optional): Category filter +- `package` (str, optional): Package filter +- `library_type` (str, optional): "Basic", "Extended", or "Preferred" +- `manufacturer` (str, optional): Manufacturer filter +- `in_stock` (bool): Only in-stock parts (default: True) +- `limit` (int): Maximum results + +**Returns:** List of matching parts + +#### `get_part_info(lcsc_number)` + +Get detailed part information. + +**Parameters:** + +- `lcsc_number` (str): LCSC part number (e.g., "C25804") + +**Returns:** Part dict or None + +#### `get_database_stats()` + +Get database statistics. + +**Returns:** Dict with: + +- `total_parts`: Total parts count +- `basic_parts`: Basic library count +- `extended_parts`: Extended library count +- `in_stock`: Parts with stock > 0 +- `db_path`: Database file path + +#### `map_package_to_footprint(package)` + +Map JLCPCB package to KiCad footprints. + +**Parameters:** + +- `package` (str): JLCPCB package name + +**Returns:** List of KiCad footprint library references + +## Data Format + +### JLCSearch Part Object + +```json +{ + "lcsc": 25804, + "mfr": "0603WAF1002T5E", + "package": "0603", + "is_basic": true, + "is_preferred": false, + "resistance": 10000, + "tolerance_fraction": 0.01, + "power_watts": 100, + "stock": 37165617, + "price1": 0.000842857 +} +``` + +### Database Schema + +```sql +CREATE TABLE components ( + lcsc TEXT PRIMARY KEY, -- "C25804" + category TEXT, -- "Resistors" + subcategory TEXT, -- "Chip Resistor" + mfr_part TEXT, -- "0603WAF1002T5E" + package TEXT, -- "0603" + solder_joints INTEGER, + manufacturer TEXT, + library_type TEXT, -- "Basic" or "Extended" + description TEXT, -- "10kΩ ±1% 100mW" + datasheet TEXT, + stock INTEGER, + price_json TEXT, -- JSON array of price breaks + last_updated INTEGER -- Unix timestamp +); +``` + +## Package to Footprint Mappings + +| JLCPCB Package | KiCad Footprints | +| -------------- | ------------------------------------------------------------------------------------------------ | +| 0402 | Resistor_SMD:R_0402_1005Metric
Capacitor_SMD:C_0402_1005Metric
LED_SMD:LED_0402_1005Metric | +| 0603 | Resistor_SMD:R_0603_1608Metric
Capacitor_SMD:C_0603_1608Metric
LED_SMD:LED_0603_1608Metric | +| 0805 | Resistor_SMD:R_0805_2012Metric
Capacitor_SMD:C_0805_2012Metric | +| 1206 | Resistor_SMD:R_1206_3216Metric
Capacitor_SMD:C_1206_3216Metric | +| SOT-23 | Package_TO_SOT_SMD:SOT-23
Package_TO_SOT_SMD:SOT-23-3 | +| SOT-23-5 | Package_TO_SOT_SMD:SOT-23-5 | +| SOT-23-6 | Package_TO_SOT_SMD:SOT-23-6 | +| SOT-223 | Package_TO_SOT_SMD:SOT-223 | +| SOIC-8 | Package_SO:SOIC-8_3.9x4.9mm_P1.27mm | +| QFN-20 | Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.5x2.5mm | + +## Best Practices + +### 1. Always Use Basic Library Parts First + +Basic library parts have **no assembly fee** ($0/part), while Extended parts cost **$3/part**. + +```python +# Filter for Basic parts only +basic_parts = [p for p in results if p['is_basic']] +``` + +### 2. Check Stock Availability + +Ensure sufficient stock before committing to a design. + +```python +# Only use parts with >1000 stock +high_stock = [p for p in results if p['stock'] > 1000] +``` + +### 3. Compare Prices + +Even within Basic library, prices vary significantly. + +```python +# Find cheapest option +cheapest = min(results, key=lambda x: x.get('price1', 999)) +``` + +### 4. Use Standardized Packages + +Stick to common packages (0402, 0603, 0805) for better availability and pricing. + +### 5. Cache Database Locally + +Download the full parts database once and search locally for faster results. + +```python +# Initial download (one-time, ~5-10 minutes) +if not os.path.exists("data/jlcpcb_parts.db"): + parts = client.download_all_components() + db.import_jlcsearch_parts(parts) + +# Subsequent searches use local database (instant) +results = db.search_parts(...) +``` + +## Troubleshooting + +### API Rate Limiting + +JLCSearch is a community service. If you hit rate limits: + +- Add delays between requests (`time.sleep(0.1)`) +- Use the local database instead of repeated API calls +- Download the full database once and work offline + +### Missing Data + +JLCSearch may not have all fields that official JLCPCB API provides: + +- No datasheets (use manufacturer website) +- Limited category information +- No solder joint count + +### Stock Discrepancies + +Stock levels are updated periodically but may lag real-time JLCPCB data by a few hours. + +## Official JLCPCB API (Alternative) + +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) +2. APP_ID, ACCESS_KEY, and SECRET_KEY credentials +3. Previous order history with JLCPCB + +To use the official API instead of JLCSearch: + +```python +from commands.jlcpcb import JLCPCBClient + +# Set credentials in .env file: +# JLCPCB_APP_ID= +# JLCPCB_API_KEY= +# JLCPCB_API_SECRET= + +client = JLCPCBClient(app_id, access_key, secret_key) +data = client.fetch_parts_page() +``` + +**Note:** Most users should use JLCSearch public API instead, as it's freely available and requires no authentication. + +## Credits + +- **JLCSearch API**: https://jlcsearch.tscircuit.com/ (by [@tscircuit](https://github.com/tscircuit/jlcsearch)) +- **JLCParts Database**: https://github.com/yaqwsx/jlcparts (by [@yaqwsx](https://github.com/yaqwsx)) +- **JLCPCB**: https://jlcpcb.com/ (official parts library provider) + +## License + +This integration uses publicly available JLCPCB parts data via the JLCSearch community service. Users must comply with JLCPCB's terms of service when using this data for production PCB orders. diff --git a/docs/JLCPCB_USAGE_GUIDE.md b/docs/JLCPCB_USAGE_GUIDE.md index db4118d..69b4e87 100644 --- a/docs/JLCPCB_USAGE_GUIDE.md +++ b/docs/JLCPCB_USAGE_GUIDE.md @@ -1,519 +1,548 @@ -# JLCPCB Integration Guide - -> **Note:** This document provides usage examples and workflow guidance. For complete API reference and setup instructions, see [JLCPCB_INTEGRATION.md](JLCPCB_INTEGRATION.md). - -The KiCAD MCP Server provides **three complementary approaches** for working with JLCPCB parts: - -1. **JLCSearch Public API** - No authentication required, 2.5M+ parts with pricing (Recommended) -2. **Local Symbol Libraries** - Search JLCPCB libraries installed via KiCad PCM _(contributed by [@l3wi](https://github.com/l3wi) in [PR #25](https://github.com/mixelpixx/KiCAD-MCP-Server/pull/25))_ -3. **Official JLCPCB API** - Requires enterprise account (Advanced) - -All approaches can be used together to give you maximum flexibility. - -## Credits - -- **Local Symbol Library Search**: Implementation by [@l3wi](https://github.com/l3wi) - [PR #25](https://github.com/mixelpixx/KiCAD-MCP-Server/pull/25) -- **JLCPCB API Integration**: Built on top of the local library foundation - ---- - -## Approach 1: JLCSearch Public API (Recommended) - -### What It Does -- Access to 2.5M+ JLCPCB parts with pricing and stock data -- **No authentication required** - works immediately -- **No JLCPCB account needed** -- Real-time pricing with quantity breaks -- Basic vs Extended library type identification -- Local SQLite database for fast offline searching -- Note: Download takes 40-60 minutes due to API pagination (100 parts per request) - -### Setup - -No setup required! Just download the database: - -``` -download_jlcpcb_database({ force: false }) -``` - -This downloads ~2.5M parts from JLCSearch API and creates a local SQLite database (`data/jlcpcb_parts.db`). - -**Expected Output:** -``` -Downloading JLCPCB parts database... -Downloaded 100 parts... -Downloaded 200 parts... -... (continues for 40-60 minutes) -Downloaded 2,500,000 parts... - -Total parts: 2,500,000+ -Database size: 3-5 GB (full catalog) -``` - -### Usage Examples - -See "Approach 2" usage examples below - the API is the same. - ---- - -## Approach 2: Local Symbol Libraries (Good for Offline Use) - -### What It Does -- Searches symbol libraries you've installed via KiCad's Plugin and Content Manager (PCM) -- Works with community JLCPCB libraries like `JLCPCB-KiCad-Library` -- No API credentials needed -- Works offline -- Symbols already have LCSC IDs and footprints configured - -### Setup - -1. **Install JLCPCB Libraries via KiCad PCM:** - - Open KiCad → Tools → Plugin and Content Manager - - Search for "JLCPCB" or "JLC" - - Install libraries like: - - `JLCPCB-KiCad-Library` (community maintained) - - `EDA_MCP` (contains common JLCPCB parts) - - Any other JLCPCB-compatible libraries - -2. **Verify Installation:** - The libraries should appear in KiCad's symbol library table. - -### Usage Examples - -#### Search for Components -``` -search_symbols({ - query: "ESP32", - library: "JLCPCB" // Filter to JLCPCB libraries only -}) -``` - -Returns: -``` -Found 12 symbols matching "ESP32": - -PCM_JLCPCB-MCUs:ESP32-C3 | LCSC: C2934196 | ESP32-C3 RISC-V WiFi/BLE SoC -PCM_JLCPCB-MCUs:ESP32-S2 | LCSC: C701342 | ESP32-S2 WiFi SoC -... -``` - -#### Search by LCSC ID -``` -search_symbols({ - query: "C2934196" // Direct LCSC ID search -}) -``` - -#### Get Symbol Details -``` -get_symbol_info({ - symbol: "PCM_JLCPCB-MCUs:ESP32-C3" -}) -``` - -Returns: -``` -Symbol: PCM_JLCPCB-MCUs:ESP32-C3 -Description: ESP32-C3 RISC-V WiFi/BLE SoC -LCSC: C2934196 -Manufacturer: Espressif -MPN: ESP32-C3-WROOM-02 -Footprint: Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm -Class: Extended -``` - -### Advantages -- ✅ No API credentials required -- ✅ Works offline after library installation -- ✅ Symbols pre-configured with correct footprints -- ✅ Community-maintained and curated -- ✅ Instant availability - -### Limitations -- ❌ Only parts in installed libraries (typically 1k-10k parts) -- ❌ No real-time pricing or stock information -- ❌ Requires manual library updates via PCM - ---- - -## Approach 3: Official JLCPCB API (Advanced - Enterprise Accounts Only) - -### What It Does -- Downloads from the **official JLCPCB API** (requires enterprise account) -- Provides **real-time pricing and stock information** -- Automatic **Basic vs Extended** library type identification (Basic = free assembly) -- Smart suggestions for cheaper/in-stock alternatives -- Package-to-footprint mapping for KiCad - -### Setup - -#### 1. Get JLCPCB API Credentials - -Visit [JLCPCB](https://jlcpcb.com/) and get your API credentials: -1. Log in to your JLCPCB account -2. Go to: **Account → API Management** -3. Click "Create API Key" -4. Save your `appKey` and `appSecret` - -#### 2. Configure Environment Variables - -Add to your shell profile (`~/.bashrc`, `~/.zshrc`, or `~/.profile`): - -```bash -export JLCPCB_API_KEY="your_app_key_here" -export JLCPCB_API_SECRET="your_app_secret_here" -``` - -Or create a `.env` file in the project root: - -``` -JLCPCB_API_KEY=your_app_key_here -JLCPCB_API_SECRET=your_app_secret_here -``` - -#### 3. Download the Parts Database - -**One-time setup** (takes 5-10 minutes): - -``` -download_jlcpcb_database({ force: false }) -``` - -This downloads ~100k parts from JLCPCB and creates a local SQLite database (`data/jlcpcb_parts.db`). - -**Output:** -``` -✓ Successfully downloaded JLCPCB parts database - -Total parts: 108,523 -Basic parts: 2,856 (free assembly) -Extended parts: 105,667 ($3 setup fee each) -Database size: 42.3 MB -Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db -``` - -### Usage Examples - -#### Search for Parts with Specifications - -``` -search_jlcpcb_parts({ - query: "10k resistor", - package: "0603", - library_type: "Basic" // Only free-assembly parts -}) -``` - -**Returns:** -``` -Found 15 JLCPCB parts: - -C25804: RC0603FR-0710KL - 10kΩ ±1% 0.1W [Basic] - $0.002/ea (15000 in stock) -C58972: 0603WAF1002T5E - 10kΩ ±1% 0.1W [Basic] - $0.001/ea (50000 in stock) -C25744: RC0603FR-0710KP - 10kΩ ±1% 0.1W [Basic] - $0.002/ea (12000 in stock) -... - -💡 Basic parts have free assembly. Extended parts charge $3 setup fee per unique part. -``` - -#### Get Part Details with Pricing - -``` -get_jlcpcb_part({ - lcsc_number: "C58972" -}) -``` - -**Returns:** -``` -LCSC: C58972 -MFR Part: 0603WAF1002T5E -Manufacturer: UNI-ROYAL -Category: Resistors / Chip Resistor - Surface Mount -Package: 0603 -Description: 10kΩ ±1% 0.1W Thick Film Resistors -Library Type: Basic (Free assembly!) -Stock: 50000 - -Price Breaks: - 1+: $0.0010/ea - 10+: $0.0009/ea - 100+: $0.0008/ea - 1000+: $0.0007/ea - -Suggested KiCAD Footprints: - - Resistor_SMD:R_0603_1608Metric - - Capacitor_SMD:C_0603_1608Metric - - LED_SMD:LED_0603_1608Metric -``` - -#### Find Cheaper Alternatives - -``` -suggest_jlcpcb_alternatives({ - lcsc_number: "C25804", - limit: 5 -}) -``` - -**Returns:** -``` -Alternative parts for C25804: - -1. C58972: 0603WAF1002T5E [Basic] - $0.001/ea (50% cheaper) - 10kΩ ±1% 0.1W Thick Film Resistors - Stock: 50000 - -2. C22790: 0603WAF1002T - [Basic] - $0.0011/ea (45% cheaper) - 10kΩ ±1% 0.1W Thick Film Resistors - Stock: 35000 -... -``` - -#### Search by Category and Package - -``` -search_jlcpcb_parts({ - category: "Microcontrollers", - package: "QFN-32", - manufacturer: "STM", - in_stock: true, - limit: 10 -}) -``` - -#### Get Database Statistics - -``` -get_jlcpcb_database_stats({}) -``` - -**Returns:** -``` -JLCPCB Database Statistics: - -Total parts: 108,523 -Basic parts: 2,856 (free assembly) -Extended parts: 105,667 ($3 setup fee each) -In stock: 95,432 -Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db -``` - -### Advantages -- ✅ Complete JLCPCB catalog (100k+ parts) -- ✅ Real-time pricing and stock data -- ✅ Automatic Basic/Extended identification -- ✅ Cost optimization suggestions -- ✅ Works offline after initial download -- ✅ Fast parametric search - -### Limitations -- ❌ Requires API credentials -- ❌ Initial download takes 5-10 minutes -- ❌ Database needs periodic updates for latest parts -- ❌ Footprint mapping may need manual verification - ---- - -## Best Practices: Using Both Approaches Together - -### Workflow 1: Design with Known Components - -**Use Local Libraries:** -``` -1. search_symbols({ query: "STM32F103", library: "JLCPCB" }) -2. Select component from installed library -3. Component already has correct symbol + footprint + LCSC ID -``` - -**Why:** Faster, symbols are pre-configured and tested. - -### Workflow 2: Find Optimal Part for Cost - -**Use JLCPCB API:** -``` -1. search_jlcpcb_parts({ - query: "10k resistor", - package: "0603", - library_type: "Basic" - }) -2. Select cheapest Basic part -3. Use suggested footprint from API -``` - -**Why:** Ensures lowest cost and maximum stock availability. - -### Workflow 3: Explore Unknown Parts - -**Start with API, verify with Libraries:** -``` -1. search_jlcpcb_parts({ query: "ESP32", limit: 20 }) -2. Find interesting part (e.g., C2934196) -3. search_symbols({ query: "C2934196" }) -4. If found in library → use library symbol -5. If not found → use API footprint suggestion -``` - -**Why:** Combines discovery power of API with quality of curated libraries. - ---- - -## Cost Optimization Tips - -### 1. Prefer Basic Parts - -``` -search_jlcpcb_parts({ - query: "resistor 10k", - library_type: "Basic" // Free assembly! -}) -``` - -**Why:** Basic parts have **$0 assembly fee**. Extended parts charge **$3 per unique part**. - -### 2. Use Alternatives Tool - -``` -suggest_jlcpcb_alternatives({ lcsc_number: "C12345" }) -``` - -**Why:** Find cheaper, more available, or Basic alternatives automatically. - -### 3. Check Stock Levels - -Always filter `in_stock: true` to avoid ordering parts that are out of stock: - -``` -search_jlcpcb_parts({ - query: "capacitor", - in_stock: true // Only show available parts -}) -``` - -### 4. Calculate BOM Cost - -For each part in your design: -1. Use `get_jlcpcb_part()` to get price breaks -2. Sum up total cost based on order quantity -3. Check library_type count (each unique Extended part = $3 fee) - ---- - -## Updating the Database - -The JLCPCB parts database should be updated periodically to get latest parts and pricing. - -### Manual Update - -``` -download_jlcpcb_database({ force: true }) -``` - -This re-downloads the entire catalog and replaces the existing database. - -### Automatic Updates (Future) - -Future versions will support incremental updates that only fetch new/changed parts. - ---- - -## Troubleshooting - -### "JLCPCB API credentials not configured" - -**Solution:** Set environment variables: -```bash -export JLCPCB_API_KEY="your_key" -export JLCPCB_API_SECRET="your_secret" -``` - -### "Database not found or empty" - -**Solution:** Run: -``` -download_jlcpcb_database({ force: false }) -``` - -### "No symbols found" (Local Libraries) - -**Solution:** -1. Install JLCPCB libraries via KiCad PCM -2. Verify library is enabled in KiCad symbol library table -3. Restart KiCad MCP server - -### "Authentication failed" - -**Solution:** -1. Verify your API credentials are correct -2. Check JLCPCB account has API access enabled -3. Try regenerating API key/secret in JLCPCB dashboard - ---- - -## API vs Libraries: Quick Reference - -| Feature | Local Libraries | JLCPCB API | -|---------|----------------|------------| -| **Parts Count** | 1k-10k (installed) | 100k+ (complete catalog) | -| **Setup** | Install via PCM | API credentials + download | -| **Offline Use** | ✅ Yes | ✅ Yes (after download) | -| **Pricing** | ❌ No | ✅ Real-time | -| **Stock Info** | ❌ No | ✅ Real-time | -| **Footprints** | ✅ Pre-configured | ⚠️ Auto-suggested | -| **Updates** | Manual via PCM | Re-download database | -| **Speed** | ⚡ Instant | ⚡ Fast (local DB) | -| **Cost Optimization** | ❌ Manual | ✅ Automatic | - ---- - -## Example Workflows - -### Complete Design Flow - -``` -# 1. Find main MCU from local library (curated) -search_symbols({ query: "ESP32", library: "JLCPCB" }) -→ Use: PCM_JLCPCB-MCUs:ESP32-C3 - -# 2. Find passives optimized for cost (API) -search_jlcpcb_parts({ - query: "capacitor 10uF", - package: "0805", - library_type: "Basic" -}) -→ Use: C15850 ($0.004, Basic, 80k stock) - -# 3. Verify connector in library -search_symbols({ query: "USB-C" }) -→ Use library symbol if available - -# 4. Export BOM with LCSC numbers -# All components now have LCSC IDs for JLCPCB assembly! -``` - ---- - -## Resources - -- [JLCPCB API Documentation](https://jlcpcb.com/help/article/JLCPCB-API) -- [JLCPCB Parts Library](https://jlcpcb.com/parts) -- [KiCad Plugin and Content Manager](https://www.kicad.org/help/pcm/) -- [JLCPCB-KiCad-Library (GitHub)](https://github.com/pejot/JLC2KiCad_lib) - ---- - -## Summary - -**Use Local Libraries when:** -- Starting a new design with common components -- You want pre-configured, tested symbols -- Working offline -- Components are in installed libraries - -**Use JLCPCB API when:** -- Optimizing cost (find cheapest Basic parts) -- Checking real-time stock availability -- Exploring parts outside installed libraries -- Need complete catalog access - -**Best approach:** Use both! Start with local libraries for known components, then use API for cost optimization and finding alternatives. +# JLCPCB Integration Guide + +> **Note:** This document provides usage examples and workflow guidance. For complete API reference and setup instructions, see [JLCPCB_INTEGRATION.md](JLCPCB_INTEGRATION.md). + +The KiCAD MCP Server provides **three complementary approaches** for working with JLCPCB parts: + +1. **JLCSearch Public API** - No authentication required, 2.5M+ parts with pricing (Recommended) +2. **Local Symbol Libraries** - Search JLCPCB libraries installed via KiCad PCM _(contributed by [@l3wi](https://github.com/l3wi) in [PR #25](https://github.com/mixelpixx/KiCAD-MCP-Server/pull/25))_ +3. **Official JLCPCB API** - Requires enterprise account (Advanced) + +All approaches can be used together to give you maximum flexibility. + +## Credits + +- **Local Symbol Library Search**: Implementation by [@l3wi](https://github.com/l3wi) - [PR #25](https://github.com/mixelpixx/KiCAD-MCP-Server/pull/25) +- **JLCPCB API Integration**: Built on top of the local library foundation + +--- + +## Approach 1: JLCSearch Public API (Recommended) + +### What It Does + +- Access to 2.5M+ JLCPCB parts with pricing and stock data +- **No authentication required** - works immediately +- **No JLCPCB account needed** +- Real-time pricing with quantity breaks +- Basic vs Extended library type identification +- Local SQLite database for fast offline searching +- Note: Download takes 40-60 minutes due to API pagination (100 parts per request) + +### Setup + +No setup required! Just download the database: + +``` +download_jlcpcb_database({ force: false }) +``` + +This downloads ~2.5M parts from JLCSearch API and creates a local SQLite database (`data/jlcpcb_parts.db`). + +**Expected Output:** + +``` +Downloading JLCPCB parts database... +Downloaded 100 parts... +Downloaded 200 parts... +... (continues for 40-60 minutes) +Downloaded 2,500,000 parts... + +Total parts: 2,500,000+ +Database size: 3-5 GB (full catalog) +``` + +### Usage Examples + +See "Approach 2" usage examples below - the API is the same. + +--- + +## Approach 2: Local Symbol Libraries (Good for Offline Use) + +### What It Does + +- Searches symbol libraries you've installed via KiCad's Plugin and Content Manager (PCM) +- Works with community JLCPCB libraries like `JLCPCB-KiCad-Library` +- No API credentials needed +- Works offline +- Symbols already have LCSC IDs and footprints configured + +### Setup + +1. **Install JLCPCB Libraries via KiCad PCM:** + - Open KiCad → Tools → Plugin and Content Manager + - Search for "JLCPCB" or "JLC" + - Install libraries like: + - `JLCPCB-KiCad-Library` (community maintained) + - `EDA_MCP` (contains common JLCPCB parts) + - Any other JLCPCB-compatible libraries + +2. **Verify Installation:** + The libraries should appear in KiCad's symbol library table. + +### Usage Examples + +#### Search for Components + +``` +search_symbols({ + query: "ESP32", + library: "JLCPCB" // Filter to JLCPCB libraries only +}) +``` + +Returns: + +``` +Found 12 symbols matching "ESP32": + +PCM_JLCPCB-MCUs:ESP32-C3 | LCSC: C2934196 | ESP32-C3 RISC-V WiFi/BLE SoC +PCM_JLCPCB-MCUs:ESP32-S2 | LCSC: C701342 | ESP32-S2 WiFi SoC +... +``` + +#### Search by LCSC ID + +``` +search_symbols({ + query: "C2934196" // Direct LCSC ID search +}) +``` + +#### Get Symbol Details + +``` +get_symbol_info({ + symbol: "PCM_JLCPCB-MCUs:ESP32-C3" +}) +``` + +Returns: + +``` +Symbol: PCM_JLCPCB-MCUs:ESP32-C3 +Description: ESP32-C3 RISC-V WiFi/BLE SoC +LCSC: C2934196 +Manufacturer: Espressif +MPN: ESP32-C3-WROOM-02 +Footprint: Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm +Class: Extended +``` + +### Advantages + +- ✅ No API credentials required +- ✅ Works offline after library installation +- ✅ Symbols pre-configured with correct footprints +- ✅ Community-maintained and curated +- ✅ Instant availability + +### Limitations + +- ❌ Only parts in installed libraries (typically 1k-10k parts) +- ❌ No real-time pricing or stock information +- ❌ Requires manual library updates via PCM + +--- + +## Approach 3: Official JLCPCB API (Advanced - Enterprise Accounts Only) + +### What It Does + +- Downloads from the **official JLCPCB API** (requires enterprise account) +- Provides **real-time pricing and stock information** +- Automatic **Basic vs Extended** library type identification (Basic = free assembly) +- Smart suggestions for cheaper/in-stock alternatives +- Package-to-footprint mapping for KiCad + +### Setup + +#### 1. Get JLCPCB API Credentials + +Visit [JLCPCB](https://jlcpcb.com/) and get your API credentials: + +1. Log in to your JLCPCB account +2. Go to: **Account → API Management** +3. Click "Create API Key" +4. Save your `appKey` and `appSecret` + +#### 2. Configure Environment Variables + +Add to your shell profile (`~/.bashrc`, `~/.zshrc`, or `~/.profile`): + +```bash +export JLCPCB_API_KEY="your_app_key_here" +export JLCPCB_API_SECRET="your_app_secret_here" +``` + +Or create a `.env` file in the project root: + +``` +JLCPCB_API_KEY=your_app_key_here +JLCPCB_API_SECRET=your_app_secret_here +``` + +#### 3. Download the Parts Database + +**One-time setup** (takes 5-10 minutes): + +``` +download_jlcpcb_database({ force: false }) +``` + +This downloads ~100k parts from JLCPCB and creates a local SQLite database (`data/jlcpcb_parts.db`). + +**Output:** + +``` +✓ Successfully downloaded JLCPCB parts database + +Total parts: 108,523 +Basic parts: 2,856 (free assembly) +Extended parts: 105,667 ($3 setup fee each) +Database size: 42.3 MB +Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db +``` + +### Usage Examples + +#### Search for Parts with Specifications + +``` +search_jlcpcb_parts({ + query: "10k resistor", + package: "0603", + library_type: "Basic" // Only free-assembly parts +}) +``` + +**Returns:** + +``` +Found 15 JLCPCB parts: + +C25804: RC0603FR-0710KL - 10kΩ ±1% 0.1W [Basic] - $0.002/ea (15000 in stock) +C58972: 0603WAF1002T5E - 10kΩ ±1% 0.1W [Basic] - $0.001/ea (50000 in stock) +C25744: RC0603FR-0710KP - 10kΩ ±1% 0.1W [Basic] - $0.002/ea (12000 in stock) +... + +💡 Basic parts have free assembly. Extended parts charge $3 setup fee per unique part. +``` + +#### Get Part Details with Pricing + +``` +get_jlcpcb_part({ + lcsc_number: "C58972" +}) +``` + +**Returns:** + +``` +LCSC: C58972 +MFR Part: 0603WAF1002T5E +Manufacturer: UNI-ROYAL +Category: Resistors / Chip Resistor - Surface Mount +Package: 0603 +Description: 10kΩ ±1% 0.1W Thick Film Resistors +Library Type: Basic (Free assembly!) +Stock: 50000 + +Price Breaks: + 1+: $0.0010/ea + 10+: $0.0009/ea + 100+: $0.0008/ea + 1000+: $0.0007/ea + +Suggested KiCAD Footprints: + - Resistor_SMD:R_0603_1608Metric + - Capacitor_SMD:C_0603_1608Metric + - LED_SMD:LED_0603_1608Metric +``` + +#### Find Cheaper Alternatives + +``` +suggest_jlcpcb_alternatives({ + lcsc_number: "C25804", + limit: 5 +}) +``` + +**Returns:** + +``` +Alternative parts for C25804: + +1. C58972: 0603WAF1002T5E [Basic] - $0.001/ea (50% cheaper) + 10kΩ ±1% 0.1W Thick Film Resistors + Stock: 50000 + +2. C22790: 0603WAF1002T - [Basic] - $0.0011/ea (45% cheaper) + 10kΩ ±1% 0.1W Thick Film Resistors + Stock: 35000 +... +``` + +#### Search by Category and Package + +``` +search_jlcpcb_parts({ + category: "Microcontrollers", + package: "QFN-32", + manufacturer: "STM", + in_stock: true, + limit: 10 +}) +``` + +#### Get Database Statistics + +``` +get_jlcpcb_database_stats({}) +``` + +**Returns:** + +``` +JLCPCB Database Statistics: + +Total parts: 108,523 +Basic parts: 2,856 (free assembly) +Extended parts: 105,667 ($3 setup fee each) +In stock: 95,432 +Database path: /home/user/KiCAD-MCP-Server/data/jlcpcb_parts.db +``` + +### Advantages + +- ✅ Complete JLCPCB catalog (100k+ parts) +- ✅ Real-time pricing and stock data +- ✅ Automatic Basic/Extended identification +- ✅ Cost optimization suggestions +- ✅ Works offline after initial download +- ✅ Fast parametric search + +### Limitations + +- ❌ Requires API credentials +- ❌ Initial download takes 5-10 minutes +- ❌ Database needs periodic updates for latest parts +- ❌ Footprint mapping may need manual verification + +--- + +## Best Practices: Using Both Approaches Together + +### Workflow 1: Design with Known Components + +**Use Local Libraries:** + +``` +1. search_symbols({ query: "STM32F103", library: "JLCPCB" }) +2. Select component from installed library +3. Component already has correct symbol + footprint + LCSC ID +``` + +**Why:** Faster, symbols are pre-configured and tested. + +### Workflow 2: Find Optimal Part for Cost + +**Use JLCPCB API:** + +``` +1. search_jlcpcb_parts({ + query: "10k resistor", + package: "0603", + library_type: "Basic" + }) +2. Select cheapest Basic part +3. Use suggested footprint from API +``` + +**Why:** Ensures lowest cost and maximum stock availability. + +### Workflow 3: Explore Unknown Parts + +**Start with API, verify with Libraries:** + +``` +1. search_jlcpcb_parts({ query: "ESP32", limit: 20 }) +2. Find interesting part (e.g., C2934196) +3. search_symbols({ query: "C2934196" }) +4. If found in library → use library symbol +5. If not found → use API footprint suggestion +``` + +**Why:** Combines discovery power of API with quality of curated libraries. + +--- + +## Cost Optimization Tips + +### 1. Prefer Basic Parts + +``` +search_jlcpcb_parts({ + query: "resistor 10k", + library_type: "Basic" // Free assembly! +}) +``` + +**Why:** Basic parts have **$0 assembly fee**. Extended parts charge **$3 per unique part**. + +### 2. Use Alternatives Tool + +``` +suggest_jlcpcb_alternatives({ lcsc_number: "C12345" }) +``` + +**Why:** Find cheaper, more available, or Basic alternatives automatically. + +### 3. Check Stock Levels + +Always filter `in_stock: true` to avoid ordering parts that are out of stock: + +``` +search_jlcpcb_parts({ + query: "capacitor", + in_stock: true // Only show available parts +}) +``` + +### 4. Calculate BOM Cost + +For each part in your design: + +1. Use `get_jlcpcb_part()` to get price breaks +2. Sum up total cost based on order quantity +3. Check library_type count (each unique Extended part = $3 fee) + +--- + +## Updating the Database + +The JLCPCB parts database should be updated periodically to get latest parts and pricing. + +### Manual Update + +``` +download_jlcpcb_database({ force: true }) +``` + +This re-downloads the entire catalog and replaces the existing database. + +### Automatic Updates (Future) + +Future versions will support incremental updates that only fetch new/changed parts. + +--- + +## Troubleshooting + +### "JLCPCB API credentials not configured" + +**Solution:** Set environment variables: + +```bash +export JLCPCB_API_KEY="your_key" +export JLCPCB_API_SECRET="your_secret" +``` + +### "Database not found or empty" + +**Solution:** Run: + +``` +download_jlcpcb_database({ force: false }) +``` + +### "No symbols found" (Local Libraries) + +**Solution:** + +1. Install JLCPCB libraries via KiCad PCM +2. Verify library is enabled in KiCad symbol library table +3. Restart KiCad MCP server + +### "Authentication failed" + +**Solution:** + +1. Verify your API credentials are correct +2. Check JLCPCB account has API access enabled +3. Try regenerating API key/secret in JLCPCB dashboard + +--- + +## API vs Libraries: Quick Reference + +| Feature | Local Libraries | JLCPCB API | +| --------------------- | ------------------ | -------------------------- | +| **Parts Count** | 1k-10k (installed) | 100k+ (complete catalog) | +| **Setup** | Install via PCM | API credentials + download | +| **Offline Use** | ✅ Yes | ✅ Yes (after download) | +| **Pricing** | ❌ No | ✅ Real-time | +| **Stock Info** | ❌ No | ✅ Real-time | +| **Footprints** | ✅ Pre-configured | ⚠️ Auto-suggested | +| **Updates** | Manual via PCM | Re-download database | +| **Speed** | ⚡ Instant | ⚡ Fast (local DB) | +| **Cost Optimization** | ❌ Manual | ✅ Automatic | + +--- + +## Example Workflows + +### Complete Design Flow + +``` +# 1. Find main MCU from local library (curated) +search_symbols({ query: "ESP32", library: "JLCPCB" }) +→ Use: PCM_JLCPCB-MCUs:ESP32-C3 + +# 2. Find passives optimized for cost (API) +search_jlcpcb_parts({ + query: "capacitor 10uF", + package: "0805", + library_type: "Basic" +}) +→ Use: C15850 ($0.004, Basic, 80k stock) + +# 3. Verify connector in library +search_symbols({ query: "USB-C" }) +→ Use library symbol if available + +# 4. Export BOM with LCSC numbers +# All components now have LCSC IDs for JLCPCB assembly! +``` + +--- + +## Resources + +- [JLCPCB API Documentation](https://jlcpcb.com/help/article/JLCPCB-API) +- [JLCPCB Parts Library](https://jlcpcb.com/parts) +- [KiCad Plugin and Content Manager](https://www.kicad.org/help/pcm/) +- [JLCPCB-KiCad-Library (GitHub)](https://github.com/pejot/JLC2KiCad_lib) + +--- + +## Summary + +**Use Local Libraries when:** + +- Starting a new design with common components +- You want pre-configured, tested symbols +- Working offline +- Components are in installed libraries + +**Use JLCPCB API when:** + +- Optimizing cost (find cheapest Basic parts) +- Checking real-time stock availability +- Exploring parts outside installed libraries +- Need complete catalog access + +**Best approach:** Use both! Start with local libraries for known components, then use API for cost optimization and finding alternatives. diff --git a/docs/KNOWN_ISSUES.md b/docs/KNOWN_ISSUES.md index 615920f..b1740e9 100644 --- a/docs/KNOWN_ISSUES.md +++ b/docs/KNOWN_ISSUES.md @@ -14,6 +14,7 @@ This document tracks known issues and provides workarounds where available. **Status:** KNOWN - Non-critical **Symptoms:** + ``` AttributeError: 'BOARD' object has no attribute 'LT_USER' ``` @@ -31,10 +32,12 @@ AttributeError: 'BOARD' object has no attribute 'LT_USER' **Status:** KNOWN - Workaround available **Symptoms:** + - Copper pours created but not filled automatically when using SWIG backend - Calling `ZONE_FILLER` via SWIG causes segfault **Workaround Options:** + 1. Use IPC backend (zones fill correctly via IPC) 2. Open the board in KiCAD UI -- zones fill automatically when opened 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 **Symptoms:** + - MCP makes changes via SWIG backend - KiCAD does not show changes until file is reloaded @@ -64,6 +68,7 @@ AttributeError: 'BOARD' object has no attribute 'LT_USER' **Status:** EXPERIMENTAL **Known Limitations:** + - KiCAD must be running with IPC enabled (Preferences > Plugins > Enable IPC API Server) - Some commands fall back to SWIG (e.g., delete_trace) - 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) ### B.Cu Footprint Routing (Fixed v2.2.3) + - `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()` ### B.Cu Placement Hang (Fixed v2.2.3) + - Placing footprints on B.Cu no longer causes ~30s freeze - Fix: call `board.Add()` before `Flip()` ### Board Outline Rounded Corners (Fixed v2.2.3) + - `add_board_outline` now correctly applies cornerRadius for rounded_rectangle shape ### 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 - Previously only global KiCAD library paths were searched ### Template File Corruption (Fixed v2.2.2) + - Removed invalid `;;` comment lines from template schematics - Restored KiCAD 9 format version (20250114) in templates ### copy_routing_pattern Empty Results (Fixed v2.2.2) + - Added geometric fallback when pads have no net assignments ### Schematic Component Corruption (Fixed v2.2.1) + - `add_schematic_component` no longer corrupts .kicad_sch files - Rewritten to use text manipulation instead of sexpdata formatting ### SWIG/UUID Comparison Bugs (Fixed v2.2.0) + - Fixed SwigPyObject UUID comparison - Fixed SWIG iterator invalidation after board.Remove() - Added board.SetModified() to prevent dangling pointer crashes @@ -136,6 +149,7 @@ If you encounter an issue not listed here: ## General Workarounds ### Server Will Not Start + ```bash # Check Python can import pcbnew python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" @@ -145,12 +159,14 @@ python3 python/utils/platform_helper.py ``` ### Commands Fail After Server Restart + ``` # Board reference is lost on restart # Always run open_project after server restart ``` ### KiCAD UI Does Not Show Changes (SWIG Mode) + ``` # File > Revert (or click reload prompt) # Or: Close and reopen file in KiCAD @@ -158,6 +174,7 @@ python3 python/utils/platform_helper.py ``` ### IPC Not Connecting + ``` # Ensure KiCAD is running # Enable IPC: Preferences > Plugins > Enable IPC API Server @@ -168,6 +185,7 @@ python3 python/utils/platform_helper.py --- **Need Help?** + - Check [IPC_BACKEND_STATUS.md](IPC_BACKEND_STATUS.md) for IPC details - Check logs: `~/.kicad-mcp/logs/kicad_interface.log` - Open an issue on GitHub diff --git a/docs/LIBRARY_INTEGRATION.md b/docs/LIBRARY_INTEGRATION.md index c23b8b5..f45d36a 100644 --- a/docs/LIBRARY_INTEGRATION.md +++ b/docs/LIBRARY_INTEGRATION.md @@ -1,364 +1,390 @@ -# KiCAD Library Integration - -**Status:** ✅ COMPLETE -**Date:** 2026-03-21 -**Version:** 2.2.3+ - -## Overview - -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 KiCAD symbol libraries (including project-local) -- ✅ Search and browse footprints/symbols across all libraries -- ✅ Component placement using library footprints -- ✅ Symbol creation and editing with project-local library support (v2.2.2+) -- ✅ Support for both `Library:Footprint` and `Footprint` formats - -## How It Works - -### Library Discovery - -The library system automatically discovers both footprint and symbol libraries: - -**Footprint Libraries** - `LibraryManager` class: - -1. **Parsing fp-lib-table files:** - - Global: `~/.config/kicad/9.0/fp-lib-table` - - Project-specific: `project-dir/fp-lib-table` - -**Symbol Libraries** - `DynamicSymbolLoader` class (v2.2.2+): - -1. **Parsing sym-lib-table files:** - - Global: `~/.config/kicad/9.0/sym-lib-table` - - Project-local: `project-dir/sym-lib-table` (added v2.2.2) - -2. **Resolving environment variables:** - - `${KICAD9_FOOTPRINT_DIR}` → `/usr/share/kicad/footprints` - - `${K IPRJMOD}` → project directory - - Supports custom paths - -3. **Indexing footprints:** - - Scans `.kicad_mod` files in each library - - Caches results for performance - - Provides fast search capabilities - -### Supported Formats - -**Library:Footprint format (recommended):** -```json -{ - "componentId": "Resistor_SMD:R_0603_1608Metric" -} -``` - -**Footprint-only format (searches all libraries):** -```json -{ - "componentId": "R_0603_1608Metric" -} -``` - -## New MCP Tools - -### 1. `list_libraries` - -List all available footprint libraries. - -**Parameters:** None - -**Returns:** -```json -{ - "success": true, - "libraries": ["Resistor_SMD", "Capacitor_SMD", "LED_SMD", ...], - "count": 153 -} -``` - -### 2. `search_footprints` - -Search for footprints matching a pattern. - -**Parameters:** -```json -{ - "pattern": "*0603*", // Supports wildcards - "limit": 20 // Optional, default: 20 -} -``` - -**Returns:** -```json -{ - "success": true, - "footprints": [ - { - "library": "Resistor_SMD", - "footprint": "R_0603_1608Metric", - "full_name": "Resistor_SMD:R_0603_1608Metric" - }, - ... - ] -} -``` - -### 3. `list_library_footprints` - -List all footprints in a specific library. - -**Parameters:** -```json -{ - "library": "Resistor_SMD" -} -``` - -**Returns:** -```json -{ - "success": true, - "library": "Resistor_SMD", - "footprints": ["R_0402_1005Metric", "R_0603_1608Metric", ...], - "count": 120 -} -``` - -### 4. `get_footprint_info` - -Get detailed information about a specific footprint. - -**Parameters:** -```json -{ - "footprint": "Resistor_SMD:R_0603_1608Metric" -} -``` - -**Returns:** -```json -{ - "success": true, - "footprint_info": { - "library": "Resistor_SMD", - "footprint": "R_0603_1608Metric", - "full_name": "Resistor_SMD:R_0603_1608Metric", - "library_path": "/usr/share/kicad/footprints/Resistor_SMD.pretty" - } -} -``` - -## Updated Component Placement - -The `place_component` tool now uses the library system: - -```json -{ - "componentId": "Resistor_SMD:R_0603_1608Metric", // Library:Footprint format - "position": {"x": 50, "y": 40, "unit": "mm"}, - "reference": "R1", - "value": "10k", - "rotation": 0, - "layer": "F.Cu" -} -``` - -**Features:** -- ✅ Automatic footprint discovery across all libraries -- ✅ Helpful error messages with suggestions -- ✅ Supports KiCAD 9.0 API (EDA_ANGLE, GetFPIDAsString) - -## Example Usage (Claude Code) - -**Search for a resistor footprint:** -``` -User: "Find me a 0603 resistor footprint" - -Claude: [uses search_footprints tool with pattern "*R_0603*"] - Found: Resistor_SMD:R_0603_1608Metric -``` - -**Place a component:** -``` -User: "Place a 10k 0603 resistor at 50,40mm" - -Claude: [uses place_component with "Resistor_SMD:R_0603_1608Metric"] - ✅ Placed R1: 10k at (50, 40) mm -``` - -**List available capacitors:** -``` -User: "What capacitor footprints are available?" - -Claude: [uses list_library_footprints with "Capacitor_SMD"] - Found 103 capacitor footprints including: - - C_0402_1005Metric - - C_0603_1608Metric - - C_0805_2012Metric - ... -``` - -## Configuration - -### Custom Library Paths - -The system automatically detects KiCAD installations, but you can add custom libraries: - -1. **Via KiCAD Preferences:** - - Open KiCAD → Preferences → Manage Footprint Libraries - - Add your custom library paths - - The MCP server will automatically discover them - -2. **Via Project fp-lib-table:** - - Create `fp-lib-table` in your project directory - - Follow the KiCAD S-expression format - -### Supported Platforms - -- ✅ **Linux:** `/usr/share/kicad/footprints`, `~/.config/kicad/9.0/` -- ✅ **Windows:** `C:/Program Files/KiCAD/*/share/kicad/footprints` -- ✅ **macOS:** `/Applications/KiCad/KiCad.app/Contents/SharedSupport/footprints` - -## KiCAD 9.0 API Compatibility - -The library integration includes full KiCAD 9.0 API support: - -### Fixed API Changes: -1. ✅ `SetOrientation()` → now uses `EDA_ANGLE(degrees, DEGREES_T)` -2. ✅ `GetOrientation()` → returns `EDA_ANGLE`, call `.AsDegrees()` -3. ✅ `GetFootprintName()` → now `GetFPIDAsString()` - -### Example Fixes: -**Old (KiCAD 8.0):** -```python -module.SetOrientation(90 * 10) # Decidegrees -rotation = module.GetOrientation() / 10 -``` - -**New (KiCAD 9.0):** -```python -angle = pcbnew.EDA_ANGLE(90, pcbnew.DEGREES_T) -module.SetOrientation(angle) -rotation = module.GetOrientation().AsDegrees() -``` - -## Implementation Details - -### LibraryManager Class - -**Location:** `python/commands/library.py` - -**Key Methods:** -- `_load_libraries()` - Parse fp-lib-table files -- `_parse_fp_lib_table()` - S-expression parser -- `_resolve_uri()` - Handle environment variables -- `find_footprint()` - Locate footprint in libraries -- `search_footprints()` - Pattern-based search -- `list_footprints()` - List library contents - -**Performance:** -- Libraries loaded once at startup -- Footprint lists cached on first access -- Fast search using Python regex -- Minimal memory footprint - -### Integration Points - -1. **KiCADInterface (`kicad_interface.py`):** - - Creates `FootprintLibraryManager` on init - - Passes to `ComponentCommands` - - Routes library commands - -2. **ComponentCommands (`component.py`):** - - Uses `LibraryManager.find_footprint()` - - Provides suggestions on errors - - Supports both lookup formats - -3. **MCP Tools (`src/tools/index.ts`):** - - Exposes 4 new library tools - - Fully typed TypeScript interfaces - - Documented parameters - -## Testing - -**Test Coverage:** -- ✅ Library path discovery (Linux/Windows/macOS) -- ✅ fp-lib-table parsing -- ✅ Environment variable resolution -- ✅ Footprint search and lookup -- ✅ Component placement integration -- ✅ Error handling and suggestions - -**Verified With:** -- KiCAD 9.0.5 on Ubuntu 24.04 -- 153 standard libraries (8,000+ footprints) -- pcbnew Python API - -## Known Limitations - -1. **Library Updates:** Changes to fp-lib-table require server restart -2. **Custom Libraries:** Must be added via KiCAD preferences first -3. **Network Libraries:** GitHub-based libraries not yet supported -4. **Search Performance:** Linear search across all libraries (fast for <200 libs) - -## Future Enhancements - -- [ ] Watch fp-lib-table for changes (auto-reload) -- [ ] Support for GitHub library URLs -- [ ] Fuzzy search for typo tolerance -- [ ] Library metadata (descriptions, categories) -- [ ] Footprint previews (SVG/PNG generation) -- [ ] Most-used footprints caching - -## Troubleshooting - -### "No footprint libraries found" - -**Cause:** fp-lib-table not found or empty - -**Solution:** -1. Verify KiCAD is installed -2. Open KiCAD and ensure libraries are configured -3. Check `~/.config/kicad/9.0/fp-lib-table` exists - -### "Footprint not found" - -**Cause:** Footprint doesn't exist or library not loaded - -**Solution:** -1. Use `search_footprints` to find similar footprints -2. Check library name is correct -3. Verify library is in fp-lib-table - -### "Failed to load footprint" - -**Cause:** Corrupt .kicad_mod file or permissions issue - -**Solution:** -1. Check file permissions on library directories -2. Reinstall KiCAD libraries if corrupt -3. Check logs for detailed error - -## Related Documentation - -- [ROADMAP.md](./ROADMAP.md) - Week 2 planning -- [STATUS_SUMMARY.md](./STATUS_SUMMARY.md) - Current implementation status -- [API.md](./API.md) - Full MCP API reference -- [KiCAD Documentation](https://docs.kicad.org/9.0/en/pcbnew/pcbnew.html) - Official KiCAD docs - -## Changelog - -**2026-03-21 - v2.2.3+** -- ✅ Project-local symbol library support (v2.2.2) -- ✅ Project-local footprint library support (v2.2.2) -- ✅ Implemented LibraryManager class -- ✅ Added 4 new MCP library tools -- ✅ Updated component placement to use libraries -- ✅ Fixed all KiCAD 9.0 API compatibility issues -- ✅ Tested end-to-end with real components -- ✅ Created comprehensive documentation - ---- - -**Status: PRODUCTION READY** 🎉 - -The library integration is complete and fully functional. Component placement now works seamlessly with KiCAD's footprint libraries, enabling AI-driven PCB design with real, validated components. +# KiCAD Library Integration + +**Status:** ✅ COMPLETE +**Date:** 2026-03-21 +**Version:** 2.2.3+ + +## Overview + +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 KiCAD symbol libraries (including project-local) +- ✅ Search and browse footprints/symbols across all libraries +- ✅ Component placement using library footprints +- ✅ Symbol creation and editing with project-local library support (v2.2.2+) +- ✅ Support for both `Library:Footprint` and `Footprint` formats + +## How It Works + +### Library Discovery + +The library system automatically discovers both footprint and symbol libraries: + +**Footprint Libraries** - `LibraryManager` class: + +1. **Parsing fp-lib-table files:** + - Global: `~/.config/kicad/9.0/fp-lib-table` + - Project-specific: `project-dir/fp-lib-table` + +**Symbol Libraries** - `DynamicSymbolLoader` class (v2.2.2+): + +1. **Parsing sym-lib-table files:** + - Global: `~/.config/kicad/9.0/sym-lib-table` + - Project-local: `project-dir/sym-lib-table` (added v2.2.2) + +2. **Resolving environment variables:** + - `${KICAD9_FOOTPRINT_DIR}` → `/usr/share/kicad/footprints` + - `${K IPRJMOD}` → project directory + - Supports custom paths + +3. **Indexing footprints:** + - Scans `.kicad_mod` files in each library + - Caches results for performance + - Provides fast search capabilities + +### Supported Formats + +**Library:Footprint format (recommended):** + +```json +{ + "componentId": "Resistor_SMD:R_0603_1608Metric" +} +``` + +**Footprint-only format (searches all libraries):** + +```json +{ + "componentId": "R_0603_1608Metric" +} +``` + +## New MCP Tools + +### 1. `list_libraries` + +List all available footprint libraries. + +**Parameters:** None + +**Returns:** + +```json +{ + "success": true, + "libraries": ["Resistor_SMD", "Capacitor_SMD", "LED_SMD", ...], + "count": 153 +} +``` + +### 2. `search_footprints` + +Search for footprints matching a pattern. + +**Parameters:** + +```json +{ + "pattern": "*0603*", // Supports wildcards + "limit": 20 // Optional, default: 20 +} +``` + +**Returns:** + +```json +{ + "success": true, + "footprints": [ + { + "library": "Resistor_SMD", + "footprint": "R_0603_1608Metric", + "full_name": "Resistor_SMD:R_0603_1608Metric" + }, + ... + ] +} +``` + +### 3. `list_library_footprints` + +List all footprints in a specific library. + +**Parameters:** + +```json +{ + "library": "Resistor_SMD" +} +``` + +**Returns:** + +```json +{ + "success": true, + "library": "Resistor_SMD", + "footprints": ["R_0402_1005Metric", "R_0603_1608Metric", ...], + "count": 120 +} +``` + +### 4. `get_footprint_info` + +Get detailed information about a specific footprint. + +**Parameters:** + +```json +{ + "footprint": "Resistor_SMD:R_0603_1608Metric" +} +``` + +**Returns:** + +```json +{ + "success": true, + "footprint_info": { + "library": "Resistor_SMD", + "footprint": "R_0603_1608Metric", + "full_name": "Resistor_SMD:R_0603_1608Metric", + "library_path": "/usr/share/kicad/footprints/Resistor_SMD.pretty" + } +} +``` + +## Updated Component Placement + +The `place_component` tool now uses the library system: + +```json +{ + "componentId": "Resistor_SMD:R_0603_1608Metric", // Library:Footprint format + "position": { "x": 50, "y": 40, "unit": "mm" }, + "reference": "R1", + "value": "10k", + "rotation": 0, + "layer": "F.Cu" +} +``` + +**Features:** + +- ✅ Automatic footprint discovery across all libraries +- ✅ Helpful error messages with suggestions +- ✅ Supports KiCAD 9.0 API (EDA_ANGLE, GetFPIDAsString) + +## Example Usage (Claude Code) + +**Search for a resistor footprint:** + +``` +User: "Find me a 0603 resistor footprint" + +Claude: [uses search_footprints tool with pattern "*R_0603*"] + Found: Resistor_SMD:R_0603_1608Metric +``` + +**Place a component:** + +``` +User: "Place a 10k 0603 resistor at 50,40mm" + +Claude: [uses place_component with "Resistor_SMD:R_0603_1608Metric"] + ✅ Placed R1: 10k at (50, 40) mm +``` + +**List available capacitors:** + +``` +User: "What capacitor footprints are available?" + +Claude: [uses list_library_footprints with "Capacitor_SMD"] + Found 103 capacitor footprints including: + - C_0402_1005Metric + - C_0603_1608Metric + - C_0805_2012Metric + ... +``` + +## Configuration + +### Custom Library Paths + +The system automatically detects KiCAD installations, but you can add custom libraries: + +1. **Via KiCAD Preferences:** + - Open KiCAD → Preferences → Manage Footprint Libraries + - Add your custom library paths + - The MCP server will automatically discover them + +2. **Via Project fp-lib-table:** + - Create `fp-lib-table` in your project directory + - Follow the KiCAD S-expression format + +### Supported Platforms + +- ✅ **Linux:** `/usr/share/kicad/footprints`, `~/.config/kicad/9.0/` +- ✅ **Windows:** `C:/Program Files/KiCAD/*/share/kicad/footprints` +- ✅ **macOS:** `/Applications/KiCad/KiCad.app/Contents/SharedSupport/footprints` + +## KiCAD 9.0 API Compatibility + +The library integration includes full KiCAD 9.0 API support: + +### Fixed API Changes: + +1. ✅ `SetOrientation()` → now uses `EDA_ANGLE(degrees, DEGREES_T)` +2. ✅ `GetOrientation()` → returns `EDA_ANGLE`, call `.AsDegrees()` +3. ✅ `GetFootprintName()` → now `GetFPIDAsString()` + +### Example Fixes: + +**Old (KiCAD 8.0):** + +```python +module.SetOrientation(90 * 10) # Decidegrees +rotation = module.GetOrientation() / 10 +``` + +**New (KiCAD 9.0):** + +```python +angle = pcbnew.EDA_ANGLE(90, pcbnew.DEGREES_T) +module.SetOrientation(angle) +rotation = module.GetOrientation().AsDegrees() +``` + +## Implementation Details + +### LibraryManager Class + +**Location:** `python/commands/library.py` + +**Key Methods:** + +- `_load_libraries()` - Parse fp-lib-table files +- `_parse_fp_lib_table()` - S-expression parser +- `_resolve_uri()` - Handle environment variables +- `find_footprint()` - Locate footprint in libraries +- `search_footprints()` - Pattern-based search +- `list_footprints()` - List library contents + +**Performance:** + +- Libraries loaded once at startup +- Footprint lists cached on first access +- Fast search using Python regex +- Minimal memory footprint + +### Integration Points + +1. **KiCADInterface (`kicad_interface.py`):** + - Creates `FootprintLibraryManager` on init + - Passes to `ComponentCommands` + - Routes library commands + +2. **ComponentCommands (`component.py`):** + - Uses `LibraryManager.find_footprint()` + - Provides suggestions on errors + - Supports both lookup formats + +3. **MCP Tools (`src/tools/index.ts`):** + - Exposes 4 new library tools + - Fully typed TypeScript interfaces + - Documented parameters + +## Testing + +**Test Coverage:** + +- ✅ Library path discovery (Linux/Windows/macOS) +- ✅ fp-lib-table parsing +- ✅ Environment variable resolution +- ✅ Footprint search and lookup +- ✅ Component placement integration +- ✅ Error handling and suggestions + +**Verified With:** + +- KiCAD 9.0.5 on Ubuntu 24.04 +- 153 standard libraries (8,000+ footprints) +- pcbnew Python API + +## Known Limitations + +1. **Library Updates:** Changes to fp-lib-table require server restart +2. **Custom Libraries:** Must be added via KiCAD preferences first +3. **Network Libraries:** GitHub-based libraries not yet supported +4. **Search Performance:** Linear search across all libraries (fast for <200 libs) + +## Future Enhancements + +- [ ] Watch fp-lib-table for changes (auto-reload) +- [ ] Support for GitHub library URLs +- [ ] Fuzzy search for typo tolerance +- [ ] Library metadata (descriptions, categories) +- [ ] Footprint previews (SVG/PNG generation) +- [ ] Most-used footprints caching + +## Troubleshooting + +### "No footprint libraries found" + +**Cause:** fp-lib-table not found or empty + +**Solution:** + +1. Verify KiCAD is installed +2. Open KiCAD and ensure libraries are configured +3. Check `~/.config/kicad/9.0/fp-lib-table` exists + +### "Footprint not found" + +**Cause:** Footprint doesn't exist or library not loaded + +**Solution:** + +1. Use `search_footprints` to find similar footprints +2. Check library name is correct +3. Verify library is in fp-lib-table + +### "Failed to load footprint" + +**Cause:** Corrupt .kicad_mod file or permissions issue + +**Solution:** + +1. Check file permissions on library directories +2. Reinstall KiCAD libraries if corrupt +3. Check logs for detailed error + +## Related Documentation + +- [ROADMAP.md](./ROADMAP.md) - Week 2 planning +- [STATUS_SUMMARY.md](./STATUS_SUMMARY.md) - Current implementation status +- [API.md](./API.md) - Full MCP API reference +- [KiCAD Documentation](https://docs.kicad.org/9.0/en/pcbnew/pcbnew.html) - Official KiCAD docs + +## Changelog + +**2026-03-21 - v2.2.3+** + +- ✅ Project-local symbol library support (v2.2.2) +- ✅ Project-local footprint library support (v2.2.2) +- ✅ Implemented LibraryManager class +- ✅ Added 4 new MCP library tools +- ✅ Updated component placement to use libraries +- ✅ Fixed all KiCAD 9.0 API compatibility issues +- ✅ Tested end-to-end with real components +- ✅ Created comprehensive documentation + +--- + +**Status: PRODUCTION READY** 🎉 + +The library integration is complete and fully functional. Component placement now works seamlessly with KiCAD's footprint libraries, enabling AI-driven PCB design with real, validated components. diff --git a/docs/LINUX_COMPATIBILITY_AUDIT.md b/docs/LINUX_COMPATIBILITY_AUDIT.md index e965f87..a78f07c 100644 --- a/docs/LINUX_COMPATIBILITY_AUDIT.md +++ b/docs/LINUX_COMPATIBILITY_AUDIT.md @@ -1,313 +1,336 @@ -# Linux Compatibility Audit Report -**Date:** 2025-10-25 -**Target Platform:** Ubuntu 24.04 LTS (primary), Fedora, Arch (secondary) -**Current Status:** Windows-optimized, partial Linux support - ---- - -## Executive Summary - -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** -- ✅ TypeScript server: Good cross-platform support -- 🟡 Python interface: Mixed (some hardcoded paths) -- ❌ Configuration: Windows-specific examples -- ❌ Documentation: Windows-only instructions - ---- - -## Critical Issues (P0 - Must Fix) - -### 1. Hardcoded Windows Paths in Config Examples -**File:** `config/claude-desktop-config.json` -```json -"cwd": "c:/repo/KiCAD-MCP", -"PYTHONPATH": "C:/Program Files/KiCad/9.0/lib/python3/dist-packages" -``` - -**Impact:** Config file won't work on Linux without manual editing -**Fix:** Create platform-specific config templates -**Priority:** P0 - ---- - -### 2. Library Search Paths (Mixed Approach) -**File:** `python/commands/library_schematic.py:16` -```python -search_paths = [ - "C:/Program Files/KiCad/*/share/kicad/symbols/*.kicad_sym", # Windows - "/usr/share/kicad/symbols/*.kicad_sym", # Linux - "/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/*.kicad_sym", # macOS -] -``` - -**Impact:** Works but inefficient (checks all platforms) -**Fix:** Auto-detect platform and use appropriate paths -**Priority:** P0 - ---- - -### 3. Python Path Detection -**File:** `python/kicad_interface.py:38-45` -```python -kicad_paths = [ - os.path.join(os.path.dirname(sys.executable), 'Lib', 'site-packages'), - os.path.dirname(sys.executable) -] -``` - -**Impact:** Paths use Windows convention ('Lib' is 'lib' on Linux) -**Fix:** Platform-specific path detection -**Priority:** P0 - ---- - -## High Priority Issues (P1) - -### 4. Documentation is Windows-Only -**Files:** `README.md`, installation instructions - -**Issues:** -- Installation paths reference `C:\Program Files` -- VSCode settings path is Windows format -- No Linux-specific troubleshooting - -**Fix:** Add Linux installation section -**Priority:** P1 - ---- - -### 5. Missing Python Dependencies Documentation -**File:** None (no requirements.txt) - -**Impact:** Users don't know what Python packages to install -**Fix:** Create `requirements.txt` and `requirements-dev.txt` -**Priority:** P1 - ---- - -### 6. Path Handling Uses os.path Instead of pathlib -**Files:** All Python files (11 files) - -**Impact:** Code is less readable and more error-prone -**Fix:** Migrate to `pathlib.Path` throughout -**Priority:** P1 - ---- - -## Medium Priority Issues (P2) - -### 7. No Linux-Specific Testing -**Impact:** Can't verify Linux compatibility -**Fix:** Add GitHub Actions with Ubuntu runner -**Priority:** P2 - ---- - -### 8. Log File Paths May Differ -**File:** `src/logger.ts:13` -```typescript -const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs'); -``` - -**Impact:** `.kicad-mcp` is okay for Linux, but best practice is `~/.config/kicad-mcp` -**Fix:** Use XDG Base Directory spec on Linux -**Priority:** P2 - ---- - -### 9. No Bash/Shell Scripts for Linux -**Impact:** Manual setup is harder on Linux -**Fix:** Create `install.sh` and `run.sh` scripts -**Priority:** P2 - ---- - -## Low Priority Issues (P3) - -### 10. TypeScript Build Uses Windows Conventions -**File:** `package.json` - -**Impact:** Works but could be more Linux-friendly -**Fix:** Add platform-specific build scripts -**Priority:** P3 - ---- - -## Positive Findings ✅ - -### What's Already Good: - -1. **TypeScript Path Handling** - Uses `path.join()` and `os.homedir()` correctly -2. **Node.js Dependencies** - All cross-platform -3. **JSON Communication** - Platform-agnostic -4. **Python Base** - Python 3 works identically on all platforms - ---- - -## Recommended Fixes - Priority Order - -### **Week 1 - Critical Fixes (P0)** - -1. **Create Platform-Specific Config Templates** - ```bash - config/ - ├── linux-config.example.json - ├── windows-config.example.json - └── macos-config.example.json - ``` - -2. **Fix Python Path Detection** - ```python - # Detect platform and set appropriate paths - import platform - import sys - from pathlib import Path - - if platform.system() == "Windows": - kicad_paths = [Path(sys.executable).parent / "Lib" / "site-packages"] - else: # Linux/Mac - kicad_paths = [Path(sys.executable).parent / "lib" / "python3.X" / "site-packages"] - ``` - -3. **Update Library Search Path Logic** - ```python - def get_kicad_library_paths(): - """Auto-detect KiCAD library paths based on platform""" - system = platform.system() - if system == "Windows": - return ["C:/Program Files/KiCad/*/share/kicad/symbols/*.kicad_sym"] - elif system == "Linux": - return ["/usr/share/kicad/symbols/*.kicad_sym"] - elif system == "Darwin": # macOS - return ["/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/*.kicad_sym"] - ``` - -### **Week 1 - High Priority (P1)** - -4. **Create requirements.txt** - ```txt - # requirements.txt - kicad-skip>=0.1.0 - Pillow>=9.0.0 - cairosvg>=2.7.0 - colorlog>=6.7.0 - ``` - -5. **Add Linux Installation Documentation** - - Ubuntu/Debian instructions - - Fedora/RHEL instructions - - Arch Linux instructions - -6. **Migrate to pathlib** - - Convert all `os.path` calls to `Path` - - More Pythonic and readable - ---- - -## Testing Checklist - -### Ubuntu 24.04 LTS Testing -- [ ] Install KiCAD 9.0 from official PPA -- [ ] Install Node.js 18+ from NodeSource -- [ ] Clone repository -- [ ] Run `npm install` -- [ ] Run `npm run build` -- [ ] Configure MCP settings (Cline) -- [ ] Test: Create project -- [ ] Test: Place components -- [ ] Test: Export Gerbers - -### Fedora Testing -- [ ] Install KiCAD from Fedora repos -- [ ] Test same workflow - -### Arch Testing -- [ ] Install KiCAD from AUR -- [ ] Test same workflow - ---- - -## Platform Detection Helper - -Create `python/utils/platform_helper.py`: - -```python -"""Platform detection and path utilities""" -import platform -import sys -from pathlib import Path -from typing import List - -class PlatformHelper: - @staticmethod - def is_windows() -> bool: - return platform.system() == "Windows" - - @staticmethod - def is_linux() -> bool: - return platform.system() == "Linux" - - @staticmethod - def is_macos() -> bool: - return platform.system() == "Darwin" - - @staticmethod - def get_kicad_python_path() -> Path: - """Get KiCAD Python dist-packages path""" - if PlatformHelper.is_windows(): - return Path("C:/Program Files/KiCad/9.0/lib/python3/dist-packages") - elif PlatformHelper.is_linux(): - # Common Linux paths - candidates = [ - Path("/usr/lib/kicad/lib/python3/dist-packages"), - Path("/usr/share/kicad/scripting/plugins"), - ] - for path in candidates: - if path.exists(): - return path - elif PlatformHelper.is_macos(): - return Path("/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/3.X/lib/python3.X/site-packages") - - raise RuntimeError(f"Could not find KiCAD Python path for {platform.system()}") - - @staticmethod - def get_config_dir() -> Path: - """Get appropriate config directory""" - if PlatformHelper.is_windows(): - return Path.home() / ".kicad-mcp" - elif PlatformHelper.is_linux(): - # Use XDG Base Directory specification - xdg_config = os.environ.get("XDG_CONFIG_HOME") - if xdg_config: - return Path(xdg_config) / "kicad-mcp" - return Path.home() / ".config" / "kicad-mcp" - elif PlatformHelper.is_macos(): - return Path.home() / "Library" / "Application Support" / "kicad-mcp" -``` - ---- - -## Success Criteria - -✅ Server starts on Ubuntu 24.04 LTS without errors -✅ Can create and manipulate KiCAD projects -✅ CI/CD pipeline tests on Linux -✅ Documentation includes Linux setup -✅ All tests pass on Linux - ---- - -## Next Steps - -1. Implement P0 fixes (this week) -2. Set up GitHub Actions CI/CD -3. Test on Ubuntu 24.04 LTS -4. Document Linux-specific issues -5. Create installation scripts - ---- - -**Audited by:** Claude Code -**Review Status:** ✅ Complete +# Linux Compatibility Audit Report + +**Date:** 2025-10-25 +**Target Platform:** Ubuntu 24.04 LTS (primary), Fedora, Arch (secondary) +**Current Status:** Windows-optimized, partial Linux support + +--- + +## Executive Summary + +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** + +- ✅ TypeScript server: Good cross-platform support +- 🟡 Python interface: Mixed (some hardcoded paths) +- ❌ Configuration: Windows-specific examples +- ❌ Documentation: Windows-only instructions + +--- + +## Critical Issues (P0 - Must Fix) + +### 1. Hardcoded Windows Paths in Config Examples + +**File:** `config/claude-desktop-config.json` + +```json +"cwd": "c:/repo/KiCAD-MCP", +"PYTHONPATH": "C:/Program Files/KiCad/9.0/lib/python3/dist-packages" +``` + +**Impact:** Config file won't work on Linux without manual editing +**Fix:** Create platform-specific config templates +**Priority:** P0 + +--- + +### 2. Library Search Paths (Mixed Approach) + +**File:** `python/commands/library_schematic.py:16` + +```python +search_paths = [ + "C:/Program Files/KiCad/*/share/kicad/symbols/*.kicad_sym", # Windows + "/usr/share/kicad/symbols/*.kicad_sym", # Linux + "/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/*.kicad_sym", # macOS +] +``` + +**Impact:** Works but inefficient (checks all platforms) +**Fix:** Auto-detect platform and use appropriate paths +**Priority:** P0 + +--- + +### 3. Python Path Detection + +**File:** `python/kicad_interface.py:38-45` + +```python +kicad_paths = [ + os.path.join(os.path.dirname(sys.executable), 'Lib', 'site-packages'), + os.path.dirname(sys.executable) +] +``` + +**Impact:** Paths use Windows convention ('Lib' is 'lib' on Linux) +**Fix:** Platform-specific path detection +**Priority:** P0 + +--- + +## High Priority Issues (P1) + +### 4. Documentation is Windows-Only + +**Files:** `README.md`, installation instructions + +**Issues:** + +- Installation paths reference `C:\Program Files` +- VSCode settings path is Windows format +- No Linux-specific troubleshooting + +**Fix:** Add Linux installation section +**Priority:** P1 + +--- + +### 5. Missing Python Dependencies Documentation + +**File:** None (no requirements.txt) + +**Impact:** Users don't know what Python packages to install +**Fix:** Create `requirements.txt` and `requirements-dev.txt` +**Priority:** P1 + +--- + +### 6. Path Handling Uses os.path Instead of pathlib + +**Files:** All Python files (11 files) + +**Impact:** Code is less readable and more error-prone +**Fix:** Migrate to `pathlib.Path` throughout +**Priority:** P1 + +--- + +## Medium Priority Issues (P2) + +### 7. No Linux-Specific Testing + +**Impact:** Can't verify Linux compatibility +**Fix:** Add GitHub Actions with Ubuntu runner +**Priority:** P2 + +--- + +### 8. Log File Paths May Differ + +**File:** `src/logger.ts:13` + +```typescript +const DEFAULT_LOG_DIR = join(os.homedir(), ".kicad-mcp", "logs"); +``` + +**Impact:** `.kicad-mcp` is okay for Linux, but best practice is `~/.config/kicad-mcp` +**Fix:** Use XDG Base Directory spec on Linux +**Priority:** P2 + +--- + +### 9. No Bash/Shell Scripts for Linux + +**Impact:** Manual setup is harder on Linux +**Fix:** Create `install.sh` and `run.sh` scripts +**Priority:** P2 + +--- + +## Low Priority Issues (P3) + +### 10. TypeScript Build Uses Windows Conventions + +**File:** `package.json` + +**Impact:** Works but could be more Linux-friendly +**Fix:** Add platform-specific build scripts +**Priority:** P3 + +--- + +## Positive Findings ✅ + +### What's Already Good: + +1. **TypeScript Path Handling** - Uses `path.join()` and `os.homedir()` correctly +2. **Node.js Dependencies** - All cross-platform +3. **JSON Communication** - Platform-agnostic +4. **Python Base** - Python 3 works identically on all platforms + +--- + +## Recommended Fixes - Priority Order + +### **Week 1 - Critical Fixes (P0)** + +1. **Create Platform-Specific Config Templates** + + ```bash + config/ + ├── linux-config.example.json + ├── windows-config.example.json + └── macos-config.example.json + ``` + +2. **Fix Python Path Detection** + + ```python + # Detect platform and set appropriate paths + import platform + import sys + from pathlib import Path + + if platform.system() == "Windows": + kicad_paths = [Path(sys.executable).parent / "Lib" / "site-packages"] + else: # Linux/Mac + kicad_paths = [Path(sys.executable).parent / "lib" / "python3.X" / "site-packages"] + ``` + +3. **Update Library Search Path Logic** + ```python + def get_kicad_library_paths(): + """Auto-detect KiCAD library paths based on platform""" + system = platform.system() + if system == "Windows": + return ["C:/Program Files/KiCad/*/share/kicad/symbols/*.kicad_sym"] + elif system == "Linux": + return ["/usr/share/kicad/symbols/*.kicad_sym"] + elif system == "Darwin": # macOS + return ["/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/*.kicad_sym"] + ``` + +### **Week 1 - High Priority (P1)** + +4. **Create requirements.txt** + + ```txt + # requirements.txt + kicad-skip>=0.1.0 + Pillow>=9.0.0 + cairosvg>=2.7.0 + colorlog>=6.7.0 + ``` + +5. **Add Linux Installation Documentation** + - Ubuntu/Debian instructions + - Fedora/RHEL instructions + - Arch Linux instructions + +6. **Migrate to pathlib** + - Convert all `os.path` calls to `Path` + - More Pythonic and readable + +--- + +## Testing Checklist + +### Ubuntu 24.04 LTS Testing + +- [ ] Install KiCAD 9.0 from official PPA +- [ ] Install Node.js 18+ from NodeSource +- [ ] Clone repository +- [ ] Run `npm install` +- [ ] Run `npm run build` +- [ ] Configure MCP settings (Cline) +- [ ] Test: Create project +- [ ] Test: Place components +- [ ] Test: Export Gerbers + +### Fedora Testing + +- [ ] Install KiCAD from Fedora repos +- [ ] Test same workflow + +### Arch Testing + +- [ ] Install KiCAD from AUR +- [ ] Test same workflow + +--- + +## Platform Detection Helper + +Create `python/utils/platform_helper.py`: + +```python +"""Platform detection and path utilities""" +import platform +import sys +from pathlib import Path +from typing import List + +class PlatformHelper: + @staticmethod + def is_windows() -> bool: + return platform.system() == "Windows" + + @staticmethod + def is_linux() -> bool: + return platform.system() == "Linux" + + @staticmethod + def is_macos() -> bool: + return platform.system() == "Darwin" + + @staticmethod + def get_kicad_python_path() -> Path: + """Get KiCAD Python dist-packages path""" + if PlatformHelper.is_windows(): + return Path("C:/Program Files/KiCad/9.0/lib/python3/dist-packages") + elif PlatformHelper.is_linux(): + # Common Linux paths + candidates = [ + Path("/usr/lib/kicad/lib/python3/dist-packages"), + Path("/usr/share/kicad/scripting/plugins"), + ] + for path in candidates: + if path.exists(): + return path + elif PlatformHelper.is_macos(): + return Path("/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/3.X/lib/python3.X/site-packages") + + raise RuntimeError(f"Could not find KiCAD Python path for {platform.system()}") + + @staticmethod + def get_config_dir() -> Path: + """Get appropriate config directory""" + if PlatformHelper.is_windows(): + return Path.home() / ".kicad-mcp" + elif PlatformHelper.is_linux(): + # Use XDG Base Directory specification + xdg_config = os.environ.get("XDG_CONFIG_HOME") + if xdg_config: + return Path(xdg_config) / "kicad-mcp" + return Path.home() / ".config" / "kicad-mcp" + elif PlatformHelper.is_macos(): + return Path.home() / "Library" / "Application Support" / "kicad-mcp" +``` + +--- + +## Success Criteria + +✅ Server starts on Ubuntu 24.04 LTS without errors +✅ Can create and manipulate KiCAD projects +✅ CI/CD pipeline tests on Linux +✅ Documentation includes Linux setup +✅ All tests pass on Linux + +--- + +## Next Steps + +1. Implement P0 fixes (this week) +2. Set up GitHub Actions CI/CD +3. Test on Ubuntu 24.04 LTS +4. Document Linux-specific issues +5. Create installation scripts + +--- + +**Audited by:** Claude Code +**Review Status:** ✅ Complete diff --git a/docs/PCB_DESIGN_WORKFLOW.md b/docs/PCB_DESIGN_WORKFLOW.md index 05424b3..8cf8bda 100644 --- a/docs/PCB_DESIGN_WORKFLOW.md +++ b/docs/PCB_DESIGN_WORKFLOW.md @@ -25,6 +25,7 @@ Create a new KiCAD project named "LEDBoard" in ~/Projects/ ``` This uses `create_project` to generate: + - `.kicad_pro` -- project file - `.kicad_pcb` -- PCB layout file - `.kicad_sch` -- schematic file (with template symbols pre-loaded) @@ -119,6 +120,7 @@ Align all resistors horizontally. ### Route Traces **Preferred approach -- pad-to-pad routing:** + ``` 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 **Manual approach:** + ``` 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 **Differential pairs:** + ``` Route a differential pair for USB_P and USB_N with 0.2mm width and 0.15mm gap. ``` **Copper zones:** + ``` 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 For boards with many connections: + ``` Check if Freerouting is available. Autoroute the board using Freerouting. @@ -246,6 +252,7 @@ Suggest alternatives to part C25804. ``` After selecting parts, enrich datasheets: + ``` Enrich datasheets for all components in the schematic. ``` diff --git a/docs/PLATFORM_GUIDE.md b/docs/PLATFORM_GUIDE.md index adfcc8c..11e8dd3 100644 --- a/docs/PLATFORM_GUIDE.md +++ b/docs/PLATFORM_GUIDE.md @@ -1,512 +1,561 @@ -# Platform Guide: Linux vs Windows - -This guide explains the differences between using KiCAD MCP Server on Linux and Windows platforms. - -**Last Updated:** 2025-11-05 - ---- - -## Quick Comparison - -| Feature | Linux | Windows | -|---------|-------|---------| -| **Primary Support** | Full (tested extensively) | Community tested | -| **Setup Complexity** | Moderate | Easy (automated script) | -| **Prerequisites** | Manual package management | Automated detection | -| **KiCAD Python Access** | System paths | Bundled with KiCAD | -| **Path Separators** | Forward slash (/) | Backslash (\\) or forward slash | -| **Virtual Environments** | Recommended | Optional | -| **Troubleshooting** | Standard Linux tools | PowerShell diagnostics | - ---- - -## Installation Differences - -### Linux Installation - -**Advantages:** -- Native package manager integration -- Better tested and documented -- More predictable Python environments -- Standard Unix paths - -**Process:** -1. Install KiCAD 9.0 via package manager (apt, dnf, pacman) -2. Install Node.js via package manager or nvm -3. Clone repository -4. Install dependencies manually -5. Build project -6. Configure MCP client -7. Set PYTHONPATH environment variable - -**Typical paths:** -```bash -KiCAD Python: /usr/lib/kicad/lib/python3/dist-packages -Node.js: /usr/bin/node -Python: /usr/bin/python3 -``` - -**Configuration example:** -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/home/username/KiCAD-MCP-Server/dist/index.js"], - "env": { - "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" - } - } - } -} -``` - -### Windows Installation - -**Advantages:** -- Automated setup script handles everything -- KiCAD includes bundled Python (no system Python needed) -- Better error diagnostics -- Comprehensive troubleshooting guide - -**Process:** -1. Install KiCAD 9.0 from official installer -2. Install Node.js from official installer -3. Clone repository -4. Run `setup-windows.ps1` script - - Auto-detects KiCAD installation - - Auto-detects Python paths - - Installs all dependencies - - Builds project - - Generates configuration - - Validates setup - -**Typical paths:** -```powershell -KiCAD Python: C:\Program Files\KiCad\9.0\bin\python.exe -KiCAD Libraries: C:\Program Files\KiCad\9.0\lib\python3\dist-packages -Node.js: C:\Program Files\nodejs\node.exe -``` - -**Configuration example:** -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["C:\\Users\\username\\KiCAD-MCP-Server\\dist\\index.js"], - "env": { - "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" - } - } - } -} -``` - ---- - -## Path Handling - -### Linux Paths -- Use forward slashes: `/home/user/project` -- Case-sensitive filesystem -- No drive letters -- Symbolic links commonly used - -**Example commands:** -```bash -cd /home/username/KiCAD-MCP-Server -export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages -python3 -c "import pcbnew" -``` - -### Windows Paths -- Use backslashes in native commands: `C:\Users\username` -- Use double backslashes in JSON: `C:\\Users\\username` -- OR use forward slashes in JSON: `C:/Users/username` -- Case-insensitive filesystem (but preserve case) -- Drive letters required (C:, D:, etc.) - -**Example commands:** -```powershell -cd C:\Users\username\KiCAD-MCP-Server -$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" -& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew" -``` - -**JSON configuration notes:** -```json -// Wrong - single backslash will cause errors -"args": ["C:\Users\name\project"] - -// Correct - double backslashes -"args": ["C:\\Users\\name\\project"] - -// Also correct - forward slashes work in JSON -"args": ["C:/Users/name/project"] -``` - ---- - -## Python Environment - -### Linux - -**System Python:** -- Usually Python 3.10+ available system-wide -- KiCAD uses system Python with additional modules -- Virtual environments recommended for isolation - -**Setup:** -```bash -# Check Python version -python3 --version - -# Verify pcbnew module -python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" - -# Install project dependencies -pip3 install -r requirements.txt - -# Or use virtual environment (recommended) -python3 -m venv venv -source venv/bin/activate -pip install -r requirements.txt -``` - -**PYTHONPATH:** -```bash -# Temporary (current session) -export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages - -# Permanent (add to ~/.bashrc or ~/.profile) -echo 'export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages' >> ~/.bashrc -``` - -### Windows - -**KiCAD Bundled Python:** -- KiCAD 9.0 includes Python 3.11 -- No system Python installation needed -- Use KiCAD's Python for all MCP operations - -**Setup:** -```powershell -# Check KiCAD Python -& "C:\Program Files\KiCad\9.0\bin\python.exe" --version - -# Verify pcbnew module -& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew; print(pcbnew.GetBuildVersion())" - -# Install project dependencies using KiCAD Python -& "C:\Program Files\KiCad\9.0\bin\python.exe" -m pip install -r requirements.txt -``` - -**PYTHONPATH:** -```powershell -# Temporary (current session) -$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" - -# In MCP configuration (permanent) -{ - "env": { - "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" - } -} -``` - ---- - -## Testing and Debugging - -### Linux - -**Check KiCAD installation:** -```bash -which kicad -kicad --version -``` - -**Check Python module:** -```bash -python3 -c "import sys; print(sys.path)" -python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" -``` - -**Run tests:** -```bash -cd /home/username/KiCAD-MCP-Server -npm test -pytest tests/ -``` - -**View logs:** -```bash -tail -f ~/.kicad-mcp/logs/kicad_interface.log -``` - -**Start server manually:** -```bash -export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages -node dist/index.js -``` - -### Windows - -**Check KiCAD installation:** -```powershell -Test-Path "C:\Program Files\KiCad\9.0" -& "C:\Program Files\KiCad\9.0\bin\kicad.exe" --version -``` - -**Check Python module:** -```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 pcbnew; print(pcbnew.GetBuildVersion())" -``` - -**Run automated diagnostics:** -```powershell -.\setup-windows.ps1 -``` - -**View logs:** -```powershell -Get-Content "$env:USERPROFILE\.kicad-mcp\logs\kicad_interface.log" -Tail 50 -Wait -``` - -**Start server manually:** -```powershell -$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" -node dist\index.js -``` - ---- - -## Common Issues - -### Linux-Specific Issues - -**1. Permission Errors** -```bash -# Fix file permissions -chmod +x python/kicad_interface.py - -# Fix directory permissions -chmod -R 755 ~/KiCAD-MCP-Server -``` - -**2. PYTHONPATH Not Set** -```bash -# Check current PYTHONPATH -echo $PYTHONPATH - -# Find KiCAD Python path -find /usr -name "pcbnew.py" 2>/dev/null -``` - -**3. KiCAD Not in PATH** -```bash -# Add to PATH temporarily -export PATH=$PATH:/usr/bin - -# Or use full path to KiCAD -/usr/bin/kicad -``` - -**4. Library Dependencies** -```bash -# Install missing system libraries -sudo apt-get install python3-wxgtk4.0 python3-cairo - -# Check library linkage -ldd /usr/lib/kicad/lib/python3/dist-packages/pcbnew.so -``` - -### Windows-Specific Issues - -**1. Server Exits Immediately** -- Most common issue -- Usually means pcbnew import failed -- Solution: Run `setup-windows.ps1` for diagnostics - -**2. Path Issues in Configuration** -```powershell -# Test path accessibility -Test-Path "C:\Users\name\KiCAD-MCP-Server\dist\index.js" - -# Use Tab completion in PowerShell to get correct paths -cd C:\Users\[TAB] -``` - -**3. PowerShell Execution Policy** -```powershell -# Check current policy -Get-ExecutionPolicy - -# Set policy to allow scripts (if needed) -Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -``` - -**4. Antivirus Blocking** -``` -Windows Defender may block Node.js or Python processes -Solution: Add exclusion for project directory in Windows Security -``` - ---- - -## Performance Considerations - -### Linux -- Generally faster file I/O operations -- Better process management -- Lower memory overhead -- Native Unix socket support (future IPC backend) - -### Windows -- Slightly slower file operations -- More memory overhead -- Extra startup validation checks (for diagnostics) -- Named pipes for IPC (future backend) - -**Both platforms perform equivalently for normal PCB design operations.** - ---- - -## Development Workflow - -### Linux Development Environment - -**Typical workflow:** -```bash -# Start development -cd ~/KiCAD-MCP-Server -code . # Open in VSCode - -# Watch mode for TypeScript -npm run watch - -# Run tests in another terminal -npm test - -# Test Python changes -python3 python/kicad_interface.py -``` - -**Recommended tools:** -- Terminal: GNOME Terminal, Konsole, or Alacritty -- Editor: VSCode with Python and TypeScript extensions -- Process monitoring: `htop` or `top` -- Log viewing: `tail -f` or `less +F` - -### Windows Development Environment - -**Typical workflow:** -```powershell -# Start development -cd C:\Users\username\KiCAD-MCP-Server -code . # Open in VSCode - -# Watch mode for TypeScript -npm run watch - -# Run tests in another PowerShell window -npm test - -# Test Python changes -& "C:\Program Files\KiCad\9.0\bin\python.exe" python\kicad_interface.py -``` - -**Recommended tools:** -- Terminal: Windows Terminal or PowerShell 7 -- Editor: VSCode with Python and TypeScript extensions -- Process monitoring: Task Manager or Process Explorer -- Log viewing: `Get-Content -Wait` or Notepad++ - ---- - -## Best Practices - -### Linux - -1. **Use virtual environments** for Python dependencies -2. **Set PYTHONPATH** in your shell profile for persistence -3. **Use absolute paths** in MCP configuration -4. **Check file permissions** if encountering access errors -5. **Monitor system logs** with `journalctl` if needed - -### Windows - -1. **Run setup-windows.ps1 first** - saves time troubleshooting -2. **Use KiCAD's bundled Python** - don't install system Python -3. **Use forward slashes** in JSON configs to avoid escaping -4. **Check log file** when debugging - it has detailed errors -5. **Keep paths short** - avoid deeply nested directories - ---- - -## Migration Between Platforms - -### Moving from Linux to Windows - -1. Clone repository on Windows machine -2. Run `setup-windows.ps1` -3. Update config file path separators (/ to \\) -4. Update PYTHONPATH to Windows format -5. No project file changes needed (KiCAD files are cross-platform) - -### Moving from Windows to Linux - -1. Clone repository on Linux machine -2. Follow Linux installation steps -3. Update config file path separators (\\ to /) -4. Update PYTHONPATH to Linux format -5. Set file permissions: `chmod +x python/kicad_interface.py` - -**KiCAD project files (.kicad_pro, .kicad_pcb) are identical across platforms.** - ---- - -## Getting Help - -### Linux Support -- Check: [README.md](../README.md) Linux installation section -- Read: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md) -- Search: GitHub Issues filtered by `linux` label -- Community: Linux users in Discussions - -### Windows Support -- Check: [README.md](../README.md) Windows installation section -- Read: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md) -- Run: `setup-windows.ps1` for automated diagnostics -- Search: GitHub Issues filtered by `windows` label -- Community: Windows users in Discussions - ---- - -## Summary - -**Choose Linux if:** -- You're comfortable with command-line tools -- You want the most stable, tested environment -- You're developing or contributing to the project -- You need maximum performance - -**Choose Windows if:** -- You want automated setup and diagnostics -- You're less comfortable with terminal commands -- You need detailed troubleshooting guidance -- You're a KiCAD user new to development tools - -**Both platforms work well for PCB design with KiCAD MCP. Choose based on your comfort level and existing development environment.** - ---- - -**For platform-specific installation instructions, see:** -- Linux: [README.md - Linux Installation](../README.md#linux-ubuntudebian) -- Windows: [README.md - Windows Installation](../README.md#windows-1011) - -**For troubleshooting:** -- Linux: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md) -- Windows: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md) +# Platform Guide: Linux vs Windows + +This guide explains the differences between using KiCAD MCP Server on Linux and Windows platforms. + +**Last Updated:** 2025-11-05 + +--- + +## Quick Comparison + +| Feature | Linux | Windows | +| ------------------------ | ------------------------- | ------------------------------- | +| **Primary Support** | Full (tested extensively) | Community tested | +| **Setup Complexity** | Moderate | Easy (automated script) | +| **Prerequisites** | Manual package management | Automated detection | +| **KiCAD Python Access** | System paths | Bundled with KiCAD | +| **Path Separators** | Forward slash (/) | Backslash (\\) or forward slash | +| **Virtual Environments** | Recommended | Optional | +| **Troubleshooting** | Standard Linux tools | PowerShell diagnostics | + +--- + +## Installation Differences + +### Linux Installation + +**Advantages:** + +- Native package manager integration +- Better tested and documented +- More predictable Python environments +- Standard Unix paths + +**Process:** + +1. Install KiCAD 9.0 via package manager (apt, dnf, pacman) +2. Install Node.js via package manager or nvm +3. Clone repository +4. Install dependencies manually +5. Build project +6. Configure MCP client +7. Set PYTHONPATH environment variable + +**Typical paths:** + +```bash +KiCAD Python: /usr/lib/kicad/lib/python3/dist-packages +Node.js: /usr/bin/node +Python: /usr/bin/python3 +``` + +**Configuration example:** + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/home/username/KiCAD-MCP-Server/dist/index.js"], + "env": { + "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages" + } + } + } +} +``` + +### Windows Installation + +**Advantages:** + +- Automated setup script handles everything +- KiCAD includes bundled Python (no system Python needed) +- Better error diagnostics +- Comprehensive troubleshooting guide + +**Process:** + +1. Install KiCAD 9.0 from official installer +2. Install Node.js from official installer +3. Clone repository +4. Run `setup-windows.ps1` script + - Auto-detects KiCAD installation + - Auto-detects Python paths + - Installs all dependencies + - Builds project + - Generates configuration + - Validates setup + +**Typical paths:** + +```powershell +KiCAD Python: C:\Program Files\KiCad\9.0\bin\python.exe +KiCAD Libraries: C:\Program Files\KiCad\9.0\lib\python3\dist-packages +Node.js: C:\Program Files\nodejs\node.exe +``` + +**Configuration example:** + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["C:\\Users\\username\\KiCAD-MCP-Server\\dist\\index.js"], + "env": { + "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" + } + } + } +} +``` + +--- + +## Path Handling + +### Linux Paths + +- Use forward slashes: `/home/user/project` +- Case-sensitive filesystem +- No drive letters +- Symbolic links commonly used + +**Example commands:** + +```bash +cd /home/username/KiCAD-MCP-Server +export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages +python3 -c "import pcbnew" +``` + +### Windows Paths + +- Use backslashes in native commands: `C:\Users\username` +- Use double backslashes in JSON: `C:\\Users\\username` +- OR use forward slashes in JSON: `C:/Users/username` +- Case-insensitive filesystem (but preserve case) +- Drive letters required (C:, D:, etc.) + +**Example commands:** + +```powershell +cd C:\Users\username\KiCAD-MCP-Server +$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" +& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew" +``` + +**JSON configuration notes:** + +```json +// Wrong - single backslash will cause errors +"args": ["C:\Users\name\project"] + +// Correct - double backslashes +"args": ["C:\\Users\\name\\project"] + +// Also correct - forward slashes work in JSON +"args": ["C:/Users/name/project"] +``` + +--- + +## Python Environment + +### Linux + +**System Python:** + +- Usually Python 3.10+ available system-wide +- KiCAD uses system Python with additional modules +- Virtual environments recommended for isolation + +**Setup:** + +```bash +# Check Python version +python3 --version + +# Verify pcbnew module +python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" + +# Install project dependencies +pip3 install -r requirements.txt + +# Or use virtual environment (recommended) +python3 -m venv venv +source venv/bin/activate +pip install -r requirements.txt +``` + +**PYTHONPATH:** + +```bash +# Temporary (current session) +export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages + +# Permanent (add to ~/.bashrc or ~/.profile) +echo 'export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages' >> ~/.bashrc +``` + +### Windows + +**KiCAD Bundled Python:** + +- KiCAD 9.0 includes Python 3.11 +- No system Python installation needed +- Use KiCAD's Python for all MCP operations + +**Setup:** + +```powershell +# Check KiCAD Python +& "C:\Program Files\KiCad\9.0\bin\python.exe" --version + +# Verify pcbnew module +& "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew; print(pcbnew.GetBuildVersion())" + +# Install project dependencies using KiCAD Python +& "C:\Program Files\KiCad\9.0\bin\python.exe" -m pip install -r requirements.txt +``` + +**PYTHONPATH:** + +```powershell +# Temporary (current session) +$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" + +# In MCP configuration (permanent) +{ + "env": { + "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" + } +} +``` + +--- + +## Testing and Debugging + +### Linux + +**Check KiCAD installation:** + +```bash +which kicad +kicad --version +``` + +**Check Python module:** + +```bash +python3 -c "import sys; print(sys.path)" +python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" +``` + +**Run tests:** + +```bash +cd /home/username/KiCAD-MCP-Server +npm test +pytest tests/ +``` + +**View logs:** + +```bash +tail -f ~/.kicad-mcp/logs/kicad_interface.log +``` + +**Start server manually:** + +```bash +export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages +node dist/index.js +``` + +### Windows + +**Check KiCAD installation:** + +```powershell +Test-Path "C:\Program Files\KiCad\9.0" +& "C:\Program Files\KiCad\9.0\bin\kicad.exe" --version +``` + +**Check Python module:** + +```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 pcbnew; print(pcbnew.GetBuildVersion())" +``` + +**Run automated diagnostics:** + +```powershell +.\setup-windows.ps1 +``` + +**View logs:** + +```powershell +Get-Content "$env:USERPROFILE\.kicad-mcp\logs\kicad_interface.log" -Tail 50 -Wait +``` + +**Start server manually:** + +```powershell +$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" +node dist\index.js +``` + +--- + +## Common Issues + +### Linux-Specific Issues + +**1. Permission Errors** + +```bash +# Fix file permissions +chmod +x python/kicad_interface.py + +# Fix directory permissions +chmod -R 755 ~/KiCAD-MCP-Server +``` + +**2. PYTHONPATH Not Set** + +```bash +# Check current PYTHONPATH +echo $PYTHONPATH + +# Find KiCAD Python path +find /usr -name "pcbnew.py" 2>/dev/null +``` + +**3. KiCAD Not in PATH** + +```bash +# Add to PATH temporarily +export PATH=$PATH:/usr/bin + +# Or use full path to KiCAD +/usr/bin/kicad +``` + +**4. Library Dependencies** + +```bash +# Install missing system libraries +sudo apt-get install python3-wxgtk4.0 python3-cairo + +# Check library linkage +ldd /usr/lib/kicad/lib/python3/dist-packages/pcbnew.so +``` + +### Windows-Specific Issues + +**1. Server Exits Immediately** + +- Most common issue +- Usually means pcbnew import failed +- Solution: Run `setup-windows.ps1` for diagnostics + +**2. Path Issues in Configuration** + +```powershell +# Test path accessibility +Test-Path "C:\Users\name\KiCAD-MCP-Server\dist\index.js" + +# Use Tab completion in PowerShell to get correct paths +cd C:\Users\[TAB] +``` + +**3. PowerShell Execution Policy** + +```powershell +# Check current policy +Get-ExecutionPolicy + +# Set policy to allow scripts (if needed) +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +``` + +**4. Antivirus Blocking** + +``` +Windows Defender may block Node.js or Python processes +Solution: Add exclusion for project directory in Windows Security +``` + +--- + +## Performance Considerations + +### Linux + +- Generally faster file I/O operations +- Better process management +- Lower memory overhead +- Native Unix socket support (future IPC backend) + +### Windows + +- Slightly slower file operations +- More memory overhead +- Extra startup validation checks (for diagnostics) +- Named pipes for IPC (future backend) + +**Both platforms perform equivalently for normal PCB design operations.** + +--- + +## Development Workflow + +### Linux Development Environment + +**Typical workflow:** + +```bash +# Start development +cd ~/KiCAD-MCP-Server +code . # Open in VSCode + +# Watch mode for TypeScript +npm run watch + +# Run tests in another terminal +npm test + +# Test Python changes +python3 python/kicad_interface.py +``` + +**Recommended tools:** + +- Terminal: GNOME Terminal, Konsole, or Alacritty +- Editor: VSCode with Python and TypeScript extensions +- Process monitoring: `htop` or `top` +- Log viewing: `tail -f` or `less +F` + +### Windows Development Environment + +**Typical workflow:** + +```powershell +# Start development +cd C:\Users\username\KiCAD-MCP-Server +code . # Open in VSCode + +# Watch mode for TypeScript +npm run watch + +# Run tests in another PowerShell window +npm test + +# Test Python changes +& "C:\Program Files\KiCad\9.0\bin\python.exe" python\kicad_interface.py +``` + +**Recommended tools:** + +- Terminal: Windows Terminal or PowerShell 7 +- Editor: VSCode with Python and TypeScript extensions +- Process monitoring: Task Manager or Process Explorer +- Log viewing: `Get-Content -Wait` or Notepad++ + +--- + +## Best Practices + +### Linux + +1. **Use virtual environments** for Python dependencies +2. **Set PYTHONPATH** in your shell profile for persistence +3. **Use absolute paths** in MCP configuration +4. **Check file permissions** if encountering access errors +5. **Monitor system logs** with `journalctl` if needed + +### Windows + +1. **Run setup-windows.ps1 first** - saves time troubleshooting +2. **Use KiCAD's bundled Python** - don't install system Python +3. **Use forward slashes** in JSON configs to avoid escaping +4. **Check log file** when debugging - it has detailed errors +5. **Keep paths short** - avoid deeply nested directories + +--- + +## Migration Between Platforms + +### Moving from Linux to Windows + +1. Clone repository on Windows machine +2. Run `setup-windows.ps1` +3. Update config file path separators (/ to \\) +4. Update PYTHONPATH to Windows format +5. No project file changes needed (KiCAD files are cross-platform) + +### Moving from Windows to Linux + +1. Clone repository on Linux machine +2. Follow Linux installation steps +3. Update config file path separators (\\ to /) +4. Update PYTHONPATH to Linux format +5. Set file permissions: `chmod +x python/kicad_interface.py` + +**KiCAD project files (.kicad_pro, .kicad_pcb) are identical across platforms.** + +--- + +## Getting Help + +### Linux Support + +- Check: [README.md](../README.md) Linux installation section +- Read: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md) +- Search: GitHub Issues filtered by `linux` label +- Community: Linux users in Discussions + +### Windows Support + +- Check: [README.md](../README.md) Windows installation section +- Read: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md) +- Run: `setup-windows.ps1` for automated diagnostics +- Search: GitHub Issues filtered by `windows` label +- Community: Windows users in Discussions + +--- + +## Summary + +**Choose Linux if:** + +- You're comfortable with command-line tools +- You want the most stable, tested environment +- You're developing or contributing to the project +- You need maximum performance + +**Choose Windows if:** + +- You want automated setup and diagnostics +- You're less comfortable with terminal commands +- You need detailed troubleshooting guidance +- You're a KiCAD user new to development tools + +**Both platforms work well for PCB design with KiCAD MCP. Choose based on your comfort level and existing development environment.** + +--- + +**For platform-specific installation instructions, see:** + +- Linux: [README.md - Linux Installation](../README.md#linux-ubuntudebian) +- Windows: [README.md - Windows Installation](../README.md#windows-1011) + +**For troubleshooting:** + +- Linux: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md) +- Windows: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md) diff --git a/docs/REALTIME_WORKFLOW.md b/docs/REALTIME_WORKFLOW.md index 6c103a5..3b7d8f6 100644 --- a/docs/REALTIME_WORKFLOW.md +++ b/docs/REALTIME_WORKFLOW.md @@ -1,416 +1,441 @@ -# Real-Time Collaboration Workflow - -**Status:** ✅ TESTED AND WORKING -**Date:** 2025-11-01 -**Version:** 2.1.0-alpha - -## Overview - -The KiCAD MCP Server enables **real-time paired circuit board design** between Claude Code (via MCP) and a human designer using the KiCAD UI. Both workflows have been tested and confirmed working: - -- ✅ **MCP→UI**: AI places components, human sees them in KiCAD -- ✅ **UI→MCP**: Human edits board, AI reads changes back - -## How It Works - -### Architecture - -The MCP server uses KiCAD's Python API (`pcbnew` module) to read and write `.kicad_pcb` files. The KiCAD UI and MCP both operate on the same file, enabling collaboration through the file system. - -``` -┌─────────────────┐ ┌──────────────────┐ -│ Claude Code │ │ Human Designer │ -│ (via MCP) │ │ (KiCAD UI) │ -└────────┬────────┘ └────────┬─────────┘ - │ │ - │ pcbnew Python API │ KiCAD UI - │ │ - ▼ ▼ - ┌─────────────────────────────────────┐ - │ project.kicad_pcb (file system) │ - └─────────────────────────────────────┘ -``` - -### MCP→UI Workflow (AI to Human) - -**Use case:** Claude places components via MCP, human sees them in KiCAD UI - -1. **Claude places components** via MCP tools: - ```python - # MCP internally uses: - board = pcbnew.LoadBoard('project.kicad_pcb') - module = pcbnew.FootprintLoad(library_path, 'R_0603_1608Metric') - module.SetPosition(pcbnew.VECTOR2I(x_nm, y_nm)) - board.Add(module) - pcbnew.SaveBoard('project.kicad_pcb', board) - ``` - -2. **Human opens/reloads in KiCAD UI:** - - **Option A (first time):** Open the project in KiCAD - - **Option B (already open):** File → Revert or close and reopen the PCB editor - - Components appear instantly ✅ - -**Example:** -``` -User: "Place a 10k resistor at position 30, 30mm" -Claude: [uses place_component MCP tool] - ✅ Placed R1: 10k at (30.0, 30.0) mm -User: [opens KiCAD UI] - [sees R1 at the specified position] -``` - -### UI→MCP Workflow (Human to AI) - -**Use case:** Human edits board in KiCAD UI, Claude reads changes via MCP - -1. **Human makes changes in KiCAD UI:** - - Move components - - Add new components - - Route traces - - Edit properties - -2. **Human saves the file:** - - Ctrl+S or File → Save - - KiCAD writes changes to `.kicad_pcb` file - -3. **Claude reads changes** via MCP tools: - ```python - # MCP internally uses: - board = pcbnew.LoadBoard('project.kicad_pcb') - footprints = board.GetFootprints() - # Reads all current component positions, values, etc. - ``` - -4. **Claude can see the updates:** - - New component positions - - Added/removed components - - Updated values and references - - New traces and nets - -**Example:** -``` -User: "I moved R1 to a new position, can you see it?" -Claude: [uses get_board_info MCP tool] - Yes! I can see R1 is now at (59.175, 49.0) mm - (previously it was at 30.0, 30.0 mm) -``` - -## Tested Workflows - -### Test 1: MCP→UI (Verified ✅) - -**Setup:** -- Created new board via MCP (100x80mm) -- Placed R1 (10k resistor) at (30, 30) mm -- Placed D1 (RED LED) at (50, 30) mm - -**Result:** -- Opened KiCAD PCB editor -- Both components visible at correct positions ✅ -- All properties (reference, value, rotation) correct ✅ - -### Test 2: UI→MCP (Verified ✅) - -**Setup:** -- User moved R1 from (30, 30) mm to (59.175, 49.0) mm in UI -- User saved file (Ctrl+S) - -**Result:** -- MCP read board via `get_board_info` -- New position detected correctly ✅ -- D1 position unchanged (as expected) ✅ - -## Current Capabilities - -### What Works - -1. **Bidirectional sync** (via file save/reload) -2. **Component placement** (MCP→UI) -3. **Component reading** (UI→MCP) -4. **Position/rotation updates** (both directions) -5. **Value/reference changes** (both directions) -6. **Trace routing** (both directions) -7. **Net information** (both directions) -8. **Board properties** (size, layers, design rules) - -### MCP Tools for Collaboration - -**Reading board state:** -- `get_board_info` - Get all components and their positions -- `get_project_info` - Get project metadata -- `list_components` - List all components (if implemented) - -**Modifying board:** -- `place_component` - Add new components -- `add_trace` - Add copper traces -- `add_via` - Add vias -- `add_copper_pour` - Add copper zones -- `add_mounting_hole` - Add mounting holes -- `add_board_text` - Add text to board - -## Limitations - -### Current Limitations - -1. **Manual Save Required** - - UI changes require manual save (Ctrl+S) - - No automatic file watching (yet) - - Workaround: Always save before asking Claude - -2. **Manual Reload Required** - - MCP changes require reload in UI - - Options: File → Revert, or close/reopen - - Future: Could implement auto-reload trigger - -3. **No Live Sync** - - Changes not visible until save/reload - - Not truly "real-time" (more like "near-time") - - File-based sync has ~1-5 second latency - -4. **No Conflict Detection** - - If both edit simultaneously, last save wins - - No merge conflict resolution - - Best practice: Take turns editing - -5. **No Change Notifications** - - MCP doesn't know when UI saves - - UI doesn't know when MCP saves - - Future: Could add file system watchers - -### Known Issues - -1. **Zone Filling:** Copper pours created by MCP won't be filled (requires UI to fill) -2. **Undo History:** UI undo history lost after MCP changes -3. **DRC Errors:** MCP doesn't run design rule checks automatically - -## Best Practices - -### For AI-Human Collaboration - -1. **Establish Turn-Taking:** - ``` - User: "I'm going to add some components, one sec" - [User edits in UI] - User: "Done, saved the file" - Claude: [reads changes] "I see you added C1 and C2..." - ``` - -2. **Always Save/Reload:** - - Human: Save after every change (Ctrl+S) - - Human: Reload after Claude makes changes - - Claude: Always read fresh before making decisions - -3. **Communicate Changes:** - ``` - Claude: "I'm placing R1-R4 now..." - [MCP places components] - Claude: "Done! Reload the board to see them" - User: [File → Revert] - ``` - -4. **Use Descriptive References:** - - Good: R1, R2, C1, C2 (sequential) - - Bad: R_temp, R_test (unclear) - -### Workflow Patterns - -**Pattern 1: AI Does Layout, Human Reviews** -``` -1. Claude places all components via MCP -2. Claude routes critical traces via MCP -3. Human opens in KiCAD UI -4. Human fine-tunes positions -5. Human completes routing -6. Saves → Claude reads final result -``` - -**Pattern 2: Human Sketches, AI Refines** -``` -1. Human places major components in UI -2. Saves → Claude reads layout -3. Claude suggests improvements -4. Claude places remaining components via MCP -5. Human reloads and reviews -6. Iterate until satisfied -``` - -**Pattern 3: Pair Programming Style** -``` -User: "Place a 10k pull-up resistor on pin 3" -Claude: [places R1 at calculated position] - "Done! Check position (45, 20) mm" -User: [reloads] "Looks good, now add the LED" -Claude: [places D1] -[Continue back-and-forth] -``` - -## Future Enhancements - -### Planned Improvements - -1. **File System Watchers** (Week 4+) - - Auto-detect when UI saves file - - Auto-reload UI when MCP saves (via IPC) - - Near-instant sync (<100ms) - -2. **IPC Backend** (Week 3) - - Direct communication with KiCAD process - - Live sync without file save/reload - - True real-time collaboration - -3. **Change Notifications** - - MCP sends notification when it modifies board - - UI shows toast: "Claude added 4 components" - - Automatic reload option - -4. **Conflict Detection** - - Detect when both edited same component - - Show diff/merge UI - - Allow choosing which changes to keep - -5. **Collaborative Cursor** - - Show Claude's "cursor" in UI - - Highlight component being placed - - Visual feedback for AI actions - -### Long-Term Vision - -**Fully Real-Time Collaboration:** -- Both AI and human see changes instantly -- No manual save/reload required -- Conflict detection and resolution -- Visual indicators for who's editing what -- Chat/comment system for design discussion - -**Example Future Workflow:** -``` -[Claude and human both have board open] -Claude: [starts placing R1] - [R1 appears in UI with "Claude is placing..." indicator] -User: [sees R1 appear in real-time] - [moves D1 to better position] - [Claude sees D1 move instantly] -Claude: "Good position for D1! I'll route them now" - [traces appear as Claude creates them] -``` - -## Technical Details - -### File Format - -KiCAD uses S-expression format (`.kicad_pcb`): -```lisp -(kicad_pcb (version 20240108) (generator "pcbnew") - (footprint "Resistor_SMD:R_0603_1608Metric" - (layer "F.Cu") - (at 30.0 30.0 0) - (property "Reference" "R1") - (property "Value" "10k") - ... - ) -) -``` - -### Sync Mechanism - -**Current (File-based):** -1. MCP: `pcbnew.SaveBoard(path, board)` → writes file -2. UI: File → Revert → reads file -3. Latency: ~1-5 seconds (manual) - -**Future (IPC-based):** -1. MCP: `kicad.AddFootprint(...)` → sends IPC command -2. KiCAD: Receives command → updates internal state -3. UI: Automatically refreshes display -4. Latency: ~50-100ms (automatic) - -### Python API Used - -```python -import pcbnew - -# Load board -board = pcbnew.LoadBoard('project.kicad_pcb') - -# Read components -for fp in board.GetFootprints(): - ref = fp.Reference().GetText() - pos = fp.GetPosition() - x_mm = pos.x / 1_000_000.0 - y_mm = pos.y / 1_000_000.0 - -# Modify board -module = pcbnew.FootprintLoad(lib_path, 'R_0603') -module.SetPosition(pcbnew.VECTOR2I(x_nm, y_nm)) -board.Add(module) - -# Save changes -pcbnew.SaveBoard('project.kicad_pcb', board) -``` - -## Troubleshooting - -### "I don't see MCP changes in KiCAD UI" - -**Cause:** UI hasn't reloaded the file - -**Solution:** -1. File → Revert (or Ctrl+R if configured) -2. Or close PCB editor and reopen -3. Or restart KiCAD - -### "MCP doesn't see my UI changes" - -**Cause:** File not saved - -**Solution:** -1. Save file: Ctrl+S or File → Save -2. Verify save: Check file modification time -3. Ask Claude to read board again - -### "Changes disappeared after reload" - -**Cause:** File overwritten by other party - -**Solution:** -1. Always save before asking MCP to make changes -2. Don't edit while MCP is working -3. Take turns to avoid conflicts - -### "Components appear in wrong positions" - -**Cause:** Unit conversion error or coordinate system mismatch - -**Solution:** -1. Check KiCAD units (View → Switch Units) -2. MCP uses millimeters internally -3. Report issue if positions consistently wrong - -## Conclusion - -**The real-time collaboration workflow is WORKING and TESTED! ✅** - -The KiCAD MCP Server successfully enables paired circuit board design between AI (Claude) and human designers. While it requires manual save/reload steps, both MCP→UI and UI→MCP workflows function correctly. - -**Current State:** "Near-real-time" collaboration (1-5 second latency) - -**Future State:** True real-time with IPC backend (<100ms latency) - -**Mission Accomplished:** Real-time paired circuit board design is operational and ready for use! 🎉 - ---- - -## Related Documentation - -- [LIBRARY_INTEGRATION.md](./LIBRARY_INTEGRATION.md) - Component library system -- [STATUS_SUMMARY.md](./STATUS_SUMMARY.md) - Current implementation status -- [ROADMAP.md](./ROADMAP.md) - Future development plans -- [API.md](./API.md) - Full MCP API reference - -## Changelog - -**2025-11-01 - v2.1.0-alpha** -- ✅ Tested MCP→UI workflow (placing components via MCP, viewing in UI) -- ✅ Tested UI→MCP workflow (editing in UI, reading via MCP) -- ✅ Documented best practices and limitations -- ✅ Confirmed real-time collaboration mission is met +# Real-Time Collaboration Workflow + +**Status:** ✅ TESTED AND WORKING +**Date:** 2025-11-01 +**Version:** 2.1.0-alpha + +## Overview + +The KiCAD MCP Server enables **real-time paired circuit board design** between Claude Code (via MCP) and a human designer using the KiCAD UI. Both workflows have been tested and confirmed working: + +- ✅ **MCP→UI**: AI places components, human sees them in KiCAD +- ✅ **UI→MCP**: Human edits board, AI reads changes back + +## How It Works + +### Architecture + +The MCP server uses KiCAD's Python API (`pcbnew` module) to read and write `.kicad_pcb` files. The KiCAD UI and MCP both operate on the same file, enabling collaboration through the file system. + +``` +┌─────────────────┐ ┌──────────────────┐ +│ Claude Code │ │ Human Designer │ +│ (via MCP) │ │ (KiCAD UI) │ +└────────┬────────┘ └────────┬─────────┘ + │ │ + │ pcbnew Python API │ KiCAD UI + │ │ + ▼ ▼ + ┌─────────────────────────────────────┐ + │ project.kicad_pcb (file system) │ + └─────────────────────────────────────┘ +``` + +### MCP→UI Workflow (AI to Human) + +**Use case:** Claude places components via MCP, human sees them in KiCAD UI + +1. **Claude places components** via MCP tools: + + ```python + # MCP internally uses: + board = pcbnew.LoadBoard('project.kicad_pcb') + module = pcbnew.FootprintLoad(library_path, 'R_0603_1608Metric') + module.SetPosition(pcbnew.VECTOR2I(x_nm, y_nm)) + board.Add(module) + pcbnew.SaveBoard('project.kicad_pcb', board) + ``` + +2. **Human opens/reloads in KiCAD UI:** + - **Option A (first time):** Open the project in KiCAD + - **Option B (already open):** File → Revert or close and reopen the PCB editor + - Components appear instantly ✅ + +**Example:** + +``` +User: "Place a 10k resistor at position 30, 30mm" +Claude: [uses place_component MCP tool] + ✅ Placed R1: 10k at (30.0, 30.0) mm +User: [opens KiCAD UI] + [sees R1 at the specified position] +``` + +### UI→MCP Workflow (Human to AI) + +**Use case:** Human edits board in KiCAD UI, Claude reads changes via MCP + +1. **Human makes changes in KiCAD UI:** + - Move components + - Add new components + - Route traces + - Edit properties + +2. **Human saves the file:** + - Ctrl+S or File → Save + - KiCAD writes changes to `.kicad_pcb` file + +3. **Claude reads changes** via MCP tools: + + ```python + # MCP internally uses: + board = pcbnew.LoadBoard('project.kicad_pcb') + footprints = board.GetFootprints() + # Reads all current component positions, values, etc. + ``` + +4. **Claude can see the updates:** + - New component positions + - Added/removed components + - Updated values and references + - New traces and nets + +**Example:** + +``` +User: "I moved R1 to a new position, can you see it?" +Claude: [uses get_board_info MCP tool] + Yes! I can see R1 is now at (59.175, 49.0) mm + (previously it was at 30.0, 30.0 mm) +``` + +## Tested Workflows + +### Test 1: MCP→UI (Verified ✅) + +**Setup:** + +- Created new board via MCP (100x80mm) +- Placed R1 (10k resistor) at (30, 30) mm +- Placed D1 (RED LED) at (50, 30) mm + +**Result:** + +- Opened KiCAD PCB editor +- Both components visible at correct positions ✅ +- All properties (reference, value, rotation) correct ✅ + +### Test 2: UI→MCP (Verified ✅) + +**Setup:** + +- User moved R1 from (30, 30) mm to (59.175, 49.0) mm in UI +- User saved file (Ctrl+S) + +**Result:** + +- MCP read board via `get_board_info` +- New position detected correctly ✅ +- D1 position unchanged (as expected) ✅ + +## Current Capabilities + +### What Works + +1. **Bidirectional sync** (via file save/reload) +2. **Component placement** (MCP→UI) +3. **Component reading** (UI→MCP) +4. **Position/rotation updates** (both directions) +5. **Value/reference changes** (both directions) +6. **Trace routing** (both directions) +7. **Net information** (both directions) +8. **Board properties** (size, layers, design rules) + +### MCP Tools for Collaboration + +**Reading board state:** + +- `get_board_info` - Get all components and their positions +- `get_project_info` - Get project metadata +- `list_components` - List all components (if implemented) + +**Modifying board:** + +- `place_component` - Add new components +- `add_trace` - Add copper traces +- `add_via` - Add vias +- `add_copper_pour` - Add copper zones +- `add_mounting_hole` - Add mounting holes +- `add_board_text` - Add text to board + +## Limitations + +### Current Limitations + +1. **Manual Save Required** + - UI changes require manual save (Ctrl+S) + - No automatic file watching (yet) + - Workaround: Always save before asking Claude + +2. **Manual Reload Required** + - MCP changes require reload in UI + - Options: File → Revert, or close/reopen + - Future: Could implement auto-reload trigger + +3. **No Live Sync** + - Changes not visible until save/reload + - Not truly "real-time" (more like "near-time") + - File-based sync has ~1-5 second latency + +4. **No Conflict Detection** + - If both edit simultaneously, last save wins + - No merge conflict resolution + - Best practice: Take turns editing + +5. **No Change Notifications** + - MCP doesn't know when UI saves + - UI doesn't know when MCP saves + - Future: Could add file system watchers + +### Known Issues + +1. **Zone Filling:** Copper pours created by MCP won't be filled (requires UI to fill) +2. **Undo History:** UI undo history lost after MCP changes +3. **DRC Errors:** MCP doesn't run design rule checks automatically + +## Best Practices + +### For AI-Human Collaboration + +1. **Establish Turn-Taking:** + + ``` + User: "I'm going to add some components, one sec" + [User edits in UI] + User: "Done, saved the file" + Claude: [reads changes] "I see you added C1 and C2..." + ``` + +2. **Always Save/Reload:** + - Human: Save after every change (Ctrl+S) + - Human: Reload after Claude makes changes + - Claude: Always read fresh before making decisions + +3. **Communicate Changes:** + + ``` + Claude: "I'm placing R1-R4 now..." + [MCP places components] + Claude: "Done! Reload the board to see them" + User: [File → Revert] + ``` + +4. **Use Descriptive References:** + - Good: R1, R2, C1, C2 (sequential) + - Bad: R_temp, R_test (unclear) + +### Workflow Patterns + +**Pattern 1: AI Does Layout, Human Reviews** + +``` +1. Claude places all components via MCP +2. Claude routes critical traces via MCP +3. Human opens in KiCAD UI +4. Human fine-tunes positions +5. Human completes routing +6. Saves → Claude reads final result +``` + +**Pattern 2: Human Sketches, AI Refines** + +``` +1. Human places major components in UI +2. Saves → Claude reads layout +3. Claude suggests improvements +4. Claude places remaining components via MCP +5. Human reloads and reviews +6. Iterate until satisfied +``` + +**Pattern 3: Pair Programming Style** + +``` +User: "Place a 10k pull-up resistor on pin 3" +Claude: [places R1 at calculated position] + "Done! Check position (45, 20) mm" +User: [reloads] "Looks good, now add the LED" +Claude: [places D1] +[Continue back-and-forth] +``` + +## Future Enhancements + +### Planned Improvements + +1. **File System Watchers** (Week 4+) + - Auto-detect when UI saves file + - Auto-reload UI when MCP saves (via IPC) + - Near-instant sync (<100ms) + +2. **IPC Backend** (Week 3) + - Direct communication with KiCAD process + - Live sync without file save/reload + - True real-time collaboration + +3. **Change Notifications** + - MCP sends notification when it modifies board + - UI shows toast: "Claude added 4 components" + - Automatic reload option + +4. **Conflict Detection** + - Detect when both edited same component + - Show diff/merge UI + - Allow choosing which changes to keep + +5. **Collaborative Cursor** + - Show Claude's "cursor" in UI + - Highlight component being placed + - Visual feedback for AI actions + +### Long-Term Vision + +**Fully Real-Time Collaboration:** + +- Both AI and human see changes instantly +- No manual save/reload required +- Conflict detection and resolution +- Visual indicators for who's editing what +- Chat/comment system for design discussion + +**Example Future Workflow:** + +``` +[Claude and human both have board open] +Claude: [starts placing R1] + [R1 appears in UI with "Claude is placing..." indicator] +User: [sees R1 appear in real-time] + [moves D1 to better position] + [Claude sees D1 move instantly] +Claude: "Good position for D1! I'll route them now" + [traces appear as Claude creates them] +``` + +## Technical Details + +### File Format + +KiCAD uses S-expression format (`.kicad_pcb`): + +```lisp +(kicad_pcb (version 20240108) (generator "pcbnew") + (footprint "Resistor_SMD:R_0603_1608Metric" + (layer "F.Cu") + (at 30.0 30.0 0) + (property "Reference" "R1") + (property "Value" "10k") + ... + ) +) +``` + +### Sync Mechanism + +**Current (File-based):** + +1. MCP: `pcbnew.SaveBoard(path, board)` → writes file +2. UI: File → Revert → reads file +3. Latency: ~1-5 seconds (manual) + +**Future (IPC-based):** + +1. MCP: `kicad.AddFootprint(...)` → sends IPC command +2. KiCAD: Receives command → updates internal state +3. UI: Automatically refreshes display +4. Latency: ~50-100ms (automatic) + +### Python API Used + +```python +import pcbnew + +# Load board +board = pcbnew.LoadBoard('project.kicad_pcb') + +# Read components +for fp in board.GetFootprints(): + ref = fp.Reference().GetText() + pos = fp.GetPosition() + x_mm = pos.x / 1_000_000.0 + y_mm = pos.y / 1_000_000.0 + +# Modify board +module = pcbnew.FootprintLoad(lib_path, 'R_0603') +module.SetPosition(pcbnew.VECTOR2I(x_nm, y_nm)) +board.Add(module) + +# Save changes +pcbnew.SaveBoard('project.kicad_pcb', board) +``` + +## Troubleshooting + +### "I don't see MCP changes in KiCAD UI" + +**Cause:** UI hasn't reloaded the file + +**Solution:** + +1. File → Revert (or Ctrl+R if configured) +2. Or close PCB editor and reopen +3. Or restart KiCAD + +### "MCP doesn't see my UI changes" + +**Cause:** File not saved + +**Solution:** + +1. Save file: Ctrl+S or File → Save +2. Verify save: Check file modification time +3. Ask Claude to read board again + +### "Changes disappeared after reload" + +**Cause:** File overwritten by other party + +**Solution:** + +1. Always save before asking MCP to make changes +2. Don't edit while MCP is working +3. Take turns to avoid conflicts + +### "Components appear in wrong positions" + +**Cause:** Unit conversion error or coordinate system mismatch + +**Solution:** + +1. Check KiCAD units (View → Switch Units) +2. MCP uses millimeters internally +3. Report issue if positions consistently wrong + +## Conclusion + +**The real-time collaboration workflow is WORKING and TESTED! ✅** + +The KiCAD MCP Server successfully enables paired circuit board design between AI (Claude) and human designers. While it requires manual save/reload steps, both MCP→UI and UI→MCP workflows function correctly. + +**Current State:** "Near-real-time" collaboration (1-5 second latency) + +**Future State:** True real-time with IPC backend (<100ms latency) + +**Mission Accomplished:** Real-time paired circuit board design is operational and ready for use! 🎉 + +--- + +## Related Documentation + +- [LIBRARY_INTEGRATION.md](./LIBRARY_INTEGRATION.md) - Component library system +- [STATUS_SUMMARY.md](./STATUS_SUMMARY.md) - Current implementation status +- [ROADMAP.md](./ROADMAP.md) - Future development plans +- [API.md](./API.md) - Full MCP API reference + +## Changelog + +**2025-11-01 - v2.1.0-alpha** + +- ✅ Tested MCP→UI workflow (placing components via MCP, viewing in UI) +- ✅ Tested UI→MCP workflow (editing in UI, reading via MCP) +- ✅ Documented best practices and limitations +- ✅ Confirmed real-time collaboration mission is met diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index a1f6347..14643e7 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -10,6 +10,7 @@ ## Completed Milestones ### v1.0.0 - Core Foundation (October 2025) + - [x] MCP protocol implementation (JSON-RPC 2.0, MCP 2025-06-18) - [x] Project management (create, open, save) - [x] Board operations (size, outline, layers, mounting holes, text) @@ -21,12 +22,14 @@ - [x] UI auto-launch and detection ### v2.0.0-alpha - Router and IPC (November-December 2025) + - [x] Tool router pattern -- 70% AI context reduction - [x] IPC backend for real-time KiCAD UI synchronization (21 commands) - [x] Hybrid SWIG/IPC backend with automatic fallback - [x] Comprehensive Windows support with automated setup ### v2.1.0-alpha - Schematics and JLCPCB (January 2026) + - [x] Complete schematic workflow fix (Issue #26) - [x] Dynamic symbol loading -- access to all ~10,000 KiCad symbols - [x] Intelligent wiring system with pin discovery and smart routing @@ -36,6 +39,7 @@ - [x] Local symbol library search (contributor: @l3wi) ### 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] route_pad_to_pad with auto-via insertion for cross-layer connections - [x] copy_routing_pattern for trace replication @@ -57,12 +61,14 @@ ## Current Focus: v2.3+ ### Documentation Overhaul (In Progress) + - [ ] Per-feature documentation for all 122 tools - [ ] Architecture guide for contributors - [ ] End-to-end PCB design workflow guide - [ ] Documentation index ### Quality and Stability + - [ ] Expand test coverage across all tool categories - [ ] Performance profiling for large boards - [ ] Update package.json version to match CHANGELOG @@ -72,24 +78,28 @@ ## Planned Features ### Supplier Integration + - [ ] Digikey API integration - [ ] Mouser API integration - [ ] Smart BOM management with real-time pricing - [ ] Cost optimization across suppliers ### Design Patterns and Templates + - [ ] Circuit patterns library (voltage regulators, USB, microcontrollers) - [ ] Board templates (Arduino shields, RPi HATs, Feather wings) - [ ] Auto-suggest trace widths by current - [ ] Impedance-controlled trace support ### Advanced Capabilities + - [ ] Panelization support - [ ] Multi-board project management - [ ] High-speed design helpers (length matching, via stitching) - [ ] SPICE simulation integration ### Community and Education + - [ ] Example project gallery with tutorials - [ ] Video walkthrough series - [ ] 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_ diff --git a/docs/ROUTER_ARCHITECTURE.md b/docs/ROUTER_ARCHITECTURE.md index ba98dac..e81e4e8 100644 --- a/docs/ROUTER_ARCHITECTURE.md +++ b/docs/ROUTER_ARCHITECTURE.md @@ -1,353 +1,383 @@ -# Router Architecture Design - -## Overview - -This document describes the router pattern implementation for the KiCAD MCP Server. The router reduces context window consumption by organizing 122+ tools into 8 discoverable categories, keeping only the most frequently used tools directly visible. - -## Architecture Layers - -``` -┌─────────────────────────────────────────────────────────────┐ -│ MCP Client (Claude) │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ KiCAD MCP Server │ -│ ┌─────────────────────────────────────────────────────────┐│ -│ │ DIRECT TOOLS (Always Visible - 12) ││ -│ │ • create_project • open_project • save_project ││ -│ │ • get_project_info • place_component • move_component ││ -│ │ • add_net • route_trace • get_board_info ││ -│ │ • set_board_size • add_board_outline • check_kicad_ui││ -│ └─────────────────────────────────────────────────────────┘│ -│ ┌─────────────────────────────────────────────────────────┐│ -│ │ ROUTER TOOLS (Discovery - 4) ││ -│ │ • list_tool_categories • get_category_tools ││ -│ │ • execute_tool • search_tools ││ -│ └─────────────────────────────────────────────────────────┘│ -│ │ │ -│ ▼ │ -│ ┌─────────────────────────────────────────────────────────┐│ -│ │ ROUTED TOOLS (Hidden - 110+) ││ -│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ -│ │ │ board │ │component │ │ export │ │ drc │ ││ -│ │ │ tools │ │ tools │ │ tools │ │ tools │ ││ -│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ ││ -│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ -│ │ │schematic │ │ library │ │ routing │ │footprint │ ││ -│ │ │ tools │ │ tools │ │ tools │ │ tools │ ││ -│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ ││ -│ └─────────────────────────────────────────────────────────┘│ -└─────────────────────────────────────────────────────────────┘ -``` - -## Tool Categories - -### Direct Tools (12 tools - always visible) - -These cover the primary workflow (80%+ of use cases): - -1. **Project Lifecycle** (4): - - `create_project` - Create new KiCAD project - - `open_project` - Open existing project - - `save_project` - Save current project - - `get_project_info` - Get project information - -2. **Core PCB Operations** (6): - - `place_component` - Place component on board - - `move_component` - Move component to new position - - `add_net` - Create a new net - - `route_trace` - Route trace between points - - `get_board_info` - Get board information - - `set_board_size` - Set board dimensions - -3. **Board Setup** (1): - - `add_board_outline` - Add board outline - -4. **UI Management** (1): - - `check_kicad_ui` - Check if KiCAD UI is running - -### Routed Categories (8+ categories, 110+ tools) - -#### 1. `board` - Board Configuration & Layout (9 tools) -Setup and configuration operations. - -**Tools:** -- `add_layer` - Add PCB layer -- `set_active_layer` - Set active layer -- `get_layer_list` - List all layers -- `add_mounting_hole` - Add mounting hole -- `add_board_text` - Add text to board -- `add_zone` - Add copper zone/pour -- `get_board_extents` - Get board boundaries -- `get_board_2d_view` - Get 2D visualization -- `launch_kicad_ui` - Launch KiCAD UI - -#### 2. `component` - Advanced Component Operations (8 tools) -Beyond basic placement. - -**Tools:** -- `rotate_component` - Rotate component -- `delete_component` - Delete component -- `edit_component` - Edit component properties -- `find_component` - Find component by reference/value -- `get_component_properties` - Get component properties -- `add_component_annotation` - Add component annotation -- `group_components` - Group components together -- `replace_component` - Replace component with another - -#### 3. `export` - File Export & Manufacturing (8 tools) -Generate output files for fabrication and documentation. - -**Tools:** -- `export_gerber` - Export Gerber files -- `export_pdf` - Export PDF -- `export_svg` - Export SVG -- `export_3d` - Export 3D model (STEP/STL/VRML/OBJ) -- `export_bom` - Export bill of materials -- `export_netlist` - Export netlist -- `export_position_file` - Export component positions -- `export_vrml` - Export VRML 3D model - -#### 4. `drc` - Design Rules & Validation (9 tools) -Design rule checking and electrical validation. - -**Tools:** -- `set_design_rules` - Configure design rules -- `get_design_rules` - Get current rules -- `run_drc` - Run design rule check -- `add_net_class` - Add net class -- `assign_net_to_class` - Assign net to class -- `set_layer_constraints` - Set layer constraints -- `check_clearance` - Check clearance between items -- `get_drc_violations` - Get DRC violations - -#### 5. `schematic` - Schematic Operations (9 tools) -Schematic editor operations. - -**Tools:** -- `create_schematic` - Create new schematic -- `add_schematic_component` - Add component to schematic -- `add_wire` - Add wire connection -- `add_schematic_connection` - Connect component pins -- `add_schematic_net_label` - Add net label -- `connect_to_net` - Connect pin to net -- `get_net_connections` - Get net connections -- `generate_netlist` - Generate netlist - -#### 6. `library` - Footprint Library Access (4 tools) -Search and browse footprint libraries. - -**Tools:** -- `list_libraries` - List available libraries -- `search_footprints` - Search footprints -- `list_library_footprints` - List library footprints -- `get_footprint_info` - Get footprint details - -#### 7. `routing` - Advanced Routing (3 tools) -Advanced routing operations beyond basic trace routing. - -**Tools:** -- `add_via` - Add via -- `add_copper_pour` - Add copper pour - -**Note:** `add_net` and `route_trace` are direct tools as they're core operations. - -## Router Tools - -### 1. `list_tool_categories` -**Description:** List all available tool categories with descriptions and tool counts. - -**Parameters:** None - -**Returns:** -```json -{ - "total_categories": 7, - "total_tools": 47, - "categories": [ - { - "name": "board", - "description": "Board configuration: layers, mounting holes, zones, visualization", - "tool_count": 9 - }, - // ... more categories - ] -} -``` - -### 2. `get_category_tools` -**Description:** Get detailed information about all tools in a specific category. - -**Parameters:** -- `category` (string) - Category name from `list_tool_categories` - -**Returns:** -```json -{ - "category": "export", - "description": "File export for fabrication and documentation: Gerber, PDF, BOM, 3D models", - "tools": [ - { - "name": "export_gerber", - "description": "Export Gerber files for PCB fabrication", - "parameters": { /* zod schema */ } - }, - // ... more tools - ] -} -``` - -### 3. `execute_tool` -**Description:** Execute a tool from any category. - -**Parameters:** -- `tool_name` (string) - Tool name from `get_category_tools` -- `params` (object, optional) - Tool parameters - -**Returns:** Tool execution result - -### 4. `search_tools` -**Description:** Search for tools by keyword across all categories. - -**Parameters:** -- `query` (string) - Search term (e.g., "gerber", "zone", "export") - -**Returns:** -```json -{ - "query": "export", - "count": 8, - "matches": [ - { - "category": "export", - "tool": "export_gerber", - "description": "Export Gerber files for PCB fabrication" - }, - // ... more matches - ] -} -``` - -## Implementation Files - -### New Files to Create - -1. **`src/tools/registry.ts`** - - Tool category definitions - - Tool metadata storage - - Lookup maps (by name, by category) - - Search functionality - -2. **`src/tools/router.ts`** - - Router tool implementations - - `list_tool_categories` handler - - `get_category_tools` handler - - `execute_tool` handler - - `search_tools` handler - -3. **`src/tools/direct.ts`** - - Export direct tool definitions - - Keep existing tool implementations but organized - -### Modified Files - -1. **`src/server.ts`** or **`src/kicad-server.ts`** - - Register only direct tools + router tools - - Remove registration of routed tools - - Tools still callable via `execute_tool` - -## Migration Strategy - -### Phase 1: Create Infrastructure -1. Create `registry.ts` with all tool definitions -2. Create `router.ts` with router tools -3. Create `direct.ts` with direct tool list - -### Phase 2: Update Server -1. Modify server registration to use direct + router only -2. Keep all existing tool handlers intact -3. Route through `execute_tool` - -### Phase 3: Testing -1. Test direct tools work as before -2. Test router tools (list/get/execute/search) -3. Test routed tools via `execute_tool` - -### Phase 4: Optimization (Optional) -1. Add caching for tool lookups -2. Add tool usage analytics -3. Implement intelligent tool suggestions - -## Benefits - -1. **Context Efficiency**: 70% reduction in tokens (~28K saved) -2. **Better Organization**: Tools grouped by function -3. **Discoverability**: Easy to find the right tool -4. **Scalability**: Can add unlimited tools without bloating context -5. **Backwards Compatible**: Existing Python commands still work - -## Usage Examples - -### Example 1: User Wants to Export Gerbers - -``` -User: "Export gerbers for this board" - -Claude's workflow: -1. Sees "export" keyword -2. Calls search_tools({ query: "gerber" }) - → Returns: { category: "export", tool: "export_gerber", ... } -3. Calls execute_tool({ - tool_name: "export_gerber", - params: { outputDir: "./gerbers" } - }) - → Returns: { success: true, files: [...] } - -Claude: "I've exported the Gerber files to ./gerbers/" -``` - -### Example 2: User Wants to Place Component - -``` -User: "Add a 0805 resistor at position 10,20" - -Claude's workflow: -1. Sees place_component in direct tools -2. Calls place_component({ - componentId: "R_0805", - position: { x: 10, y: 20, unit: "mm" } - }) - → Returns: { success: true, reference: "R1" } - -Claude: "Added R1 (0805 resistor) at position (10, 20) mm" -``` - -### Example 3: User Wants Unknown Operation - -``` -User: "Check the board for design rule violations" - -Claude's workflow: -1. Uncertain which tool to use -2. Calls search_tools({ query: "design rule violations" }) - → Returns: { category: "drc", tool: "run_drc", ...} -3. Calls get_category_tools({ category: "drc" }) - → Returns full DRC category tools with parameters -4. Calls execute_tool({ - tool_name: "run_drc", - params: {} - }) - → Returns: DRC results - -Claude: "I ran the design rule check. Found 3 violations: ..." -``` - -## Success Metrics - -- ✅ Token usage: ~12K (vs 40K before) -- ✅ Tool discovery time: <2 calls (search → execute) -- ✅ User experience: Unchanged (seamless) -- ✅ Maintainability: Improved (organized categories) -- ✅ Scalability: Can add 100+ more tools easily +# Router Architecture Design + +## Overview + +This document describes the router pattern implementation for the KiCAD MCP Server. The router reduces context window consumption by organizing 122+ tools into 8 discoverable categories, keeping only the most frequently used tools directly visible. + +## Architecture Layers + +``` +┌─────────────────────────────────────────────────────────────┐ +│ MCP Client (Claude) │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ KiCAD MCP Server │ +│ ┌─────────────────────────────────────────────────────────┐│ +│ │ DIRECT TOOLS (Always Visible - 12) ││ +│ │ • create_project • open_project • save_project ││ +│ │ • get_project_info • place_component • move_component ││ +│ │ • add_net • route_trace • get_board_info ││ +│ │ • set_board_size • add_board_outline • check_kicad_ui││ +│ └─────────────────────────────────────────────────────────┘│ +│ ┌─────────────────────────────────────────────────────────┐│ +│ │ ROUTER TOOLS (Discovery - 4) ││ +│ │ • list_tool_categories • get_category_tools ││ +│ │ • execute_tool • search_tools ││ +│ └─────────────────────────────────────────────────────────┘│ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────┐│ +│ │ ROUTED TOOLS (Hidden - 110+) ││ +│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ +│ │ │ board │ │component │ │ export │ │ drc │ ││ +│ │ │ tools │ │ tools │ │ tools │ │ tools │ ││ +│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ ││ +│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ +│ │ │schematic │ │ library │ │ routing │ │footprint │ ││ +│ │ │ tools │ │ tools │ │ tools │ │ tools │ ││ +│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ ││ +│ └─────────────────────────────────────────────────────────┘│ +└─────────────────────────────────────────────────────────────┘ +``` + +## Tool Categories + +### Direct Tools (12 tools - always visible) + +These cover the primary workflow (80%+ of use cases): + +1. **Project Lifecycle** (4): + - `create_project` - Create new KiCAD project + - `open_project` - Open existing project + - `save_project` - Save current project + - `get_project_info` - Get project information + +2. **Core PCB Operations** (6): + - `place_component` - Place component on board + - `move_component` - Move component to new position + - `add_net` - Create a new net + - `route_trace` - Route trace between points + - `get_board_info` - Get board information + - `set_board_size` - Set board dimensions + +3. **Board Setup** (1): + - `add_board_outline` - Add board outline + +4. **UI Management** (1): + - `check_kicad_ui` - Check if KiCAD UI is running + +### Routed Categories (8+ categories, 110+ tools) + +#### 1. `board` - Board Configuration & Layout (9 tools) + +Setup and configuration operations. + +**Tools:** + +- `add_layer` - Add PCB layer +- `set_active_layer` - Set active layer +- `get_layer_list` - List all layers +- `add_mounting_hole` - Add mounting hole +- `add_board_text` - Add text to board +- `add_zone` - Add copper zone/pour +- `get_board_extents` - Get board boundaries +- `get_board_2d_view` - Get 2D visualization +- `launch_kicad_ui` - Launch KiCAD UI + +#### 2. `component` - Advanced Component Operations (8 tools) + +Beyond basic placement. + +**Tools:** + +- `rotate_component` - Rotate component +- `delete_component` - Delete component +- `edit_component` - Edit component properties +- `find_component` - Find component by reference/value +- `get_component_properties` - Get component properties +- `add_component_annotation` - Add component annotation +- `group_components` - Group components together +- `replace_component` - Replace component with another + +#### 3. `export` - File Export & Manufacturing (8 tools) + +Generate output files for fabrication and documentation. + +**Tools:** + +- `export_gerber` - Export Gerber files +- `export_pdf` - Export PDF +- `export_svg` - Export SVG +- `export_3d` - Export 3D model (STEP/STL/VRML/OBJ) +- `export_bom` - Export bill of materials +- `export_netlist` - Export netlist +- `export_position_file` - Export component positions +- `export_vrml` - Export VRML 3D model + +#### 4. `drc` - Design Rules & Validation (9 tools) + +Design rule checking and electrical validation. + +**Tools:** + +- `set_design_rules` - Configure design rules +- `get_design_rules` - Get current rules +- `run_drc` - Run design rule check +- `add_net_class` - Add net class +- `assign_net_to_class` - Assign net to class +- `set_layer_constraints` - Set layer constraints +- `check_clearance` - Check clearance between items +- `get_drc_violations` - Get DRC violations + +#### 5. `schematic` - Schematic Operations (9 tools) + +Schematic editor operations. + +**Tools:** + +- `create_schematic` - Create new schematic +- `add_schematic_component` - Add component to schematic +- `add_wire` - Add wire connection +- `add_schematic_connection` - Connect component pins +- `add_schematic_net_label` - Add net label +- `connect_to_net` - Connect pin to net +- `get_net_connections` - Get net connections +- `generate_netlist` - Generate netlist + +#### 6. `library` - Footprint Library Access (4 tools) + +Search and browse footprint libraries. + +**Tools:** + +- `list_libraries` - List available libraries +- `search_footprints` - Search footprints +- `list_library_footprints` - List library footprints +- `get_footprint_info` - Get footprint details + +#### 7. `routing` - Advanced Routing (3 tools) + +Advanced routing operations beyond basic trace routing. + +**Tools:** + +- `add_via` - Add via +- `add_copper_pour` - Add copper pour + +**Note:** `add_net` and `route_trace` are direct tools as they're core operations. + +## Router Tools + +### 1. `list_tool_categories` + +**Description:** List all available tool categories with descriptions and tool counts. + +**Parameters:** None + +**Returns:** + +```json +{ + "total_categories": 7, + "total_tools": 47, + "categories": [ + { + "name": "board", + "description": "Board configuration: layers, mounting holes, zones, visualization", + "tool_count": 9 + } + // ... more categories + ] +} +``` + +### 2. `get_category_tools` + +**Description:** Get detailed information about all tools in a specific category. + +**Parameters:** + +- `category` (string) - Category name from `list_tool_categories` + +**Returns:** + +```json +{ + "category": "export", + "description": "File export for fabrication and documentation: Gerber, PDF, BOM, 3D models", + "tools": [ + { + "name": "export_gerber", + "description": "Export Gerber files for PCB fabrication", + "parameters": { + /* zod schema */ + } + } + // ... more tools + ] +} +``` + +### 3. `execute_tool` + +**Description:** Execute a tool from any category. + +**Parameters:** + +- `tool_name` (string) - Tool name from `get_category_tools` +- `params` (object, optional) - Tool parameters + +**Returns:** Tool execution result + +### 4. `search_tools` + +**Description:** Search for tools by keyword across all categories. + +**Parameters:** + +- `query` (string) - Search term (e.g., "gerber", "zone", "export") + +**Returns:** + +```json +{ + "query": "export", + "count": 8, + "matches": [ + { + "category": "export", + "tool": "export_gerber", + "description": "Export Gerber files for PCB fabrication" + } + // ... more matches + ] +} +``` + +## Implementation Files + +### New Files to Create + +1. **`src/tools/registry.ts`** + - Tool category definitions + - Tool metadata storage + - Lookup maps (by name, by category) + - Search functionality + +2. **`src/tools/router.ts`** + - Router tool implementations + - `list_tool_categories` handler + - `get_category_tools` handler + - `execute_tool` handler + - `search_tools` handler + +3. **`src/tools/direct.ts`** + - Export direct tool definitions + - Keep existing tool implementations but organized + +### Modified Files + +1. **`src/server.ts`** or **`src/kicad-server.ts`** + - Register only direct tools + router tools + - Remove registration of routed tools + - Tools still callable via `execute_tool` + +## Migration Strategy + +### Phase 1: Create Infrastructure + +1. Create `registry.ts` with all tool definitions +2. Create `router.ts` with router tools +3. Create `direct.ts` with direct tool list + +### Phase 2: Update Server + +1. Modify server registration to use direct + router only +2. Keep all existing tool handlers intact +3. Route through `execute_tool` + +### Phase 3: Testing + +1. Test direct tools work as before +2. Test router tools (list/get/execute/search) +3. Test routed tools via `execute_tool` + +### Phase 4: Optimization (Optional) + +1. Add caching for tool lookups +2. Add tool usage analytics +3. Implement intelligent tool suggestions + +## Benefits + +1. **Context Efficiency**: 70% reduction in tokens (~28K saved) +2. **Better Organization**: Tools grouped by function +3. **Discoverability**: Easy to find the right tool +4. **Scalability**: Can add unlimited tools without bloating context +5. **Backwards Compatible**: Existing Python commands still work + +## Usage Examples + +### Example 1: User Wants to Export Gerbers + +``` +User: "Export gerbers for this board" + +Claude's workflow: +1. Sees "export" keyword +2. Calls search_tools({ query: "gerber" }) + → Returns: { category: "export", tool: "export_gerber", ... } +3. Calls execute_tool({ + tool_name: "export_gerber", + params: { outputDir: "./gerbers" } + }) + → Returns: { success: true, files: [...] } + +Claude: "I've exported the Gerber files to ./gerbers/" +``` + +### Example 2: User Wants to Place Component + +``` +User: "Add a 0805 resistor at position 10,20" + +Claude's workflow: +1. Sees place_component in direct tools +2. Calls place_component({ + componentId: "R_0805", + position: { x: 10, y: 20, unit: "mm" } + }) + → Returns: { success: true, reference: "R1" } + +Claude: "Added R1 (0805 resistor) at position (10, 20) mm" +``` + +### Example 3: User Wants Unknown Operation + +``` +User: "Check the board for design rule violations" + +Claude's workflow: +1. Uncertain which tool to use +2. Calls search_tools({ query: "design rule violations" }) + → Returns: { category: "drc", tool: "run_drc", ...} +3. Calls get_category_tools({ category: "drc" }) + → Returns full DRC category tools with parameters +4. Calls execute_tool({ + tool_name: "run_drc", + params: {} + }) + → Returns: DRC results + +Claude: "I ran the design rule check. Found 3 violations: ..." +``` + +## Success Metrics + +- ✅ Token usage: ~12K (vs 40K before) +- ✅ Tool discovery time: <2 calls (search → execute) +- ✅ User experience: Unchanged (seamless) +- ✅ Maintainability: Improved (organized categories) +- ✅ Scalability: Can add 100+ more tools easily diff --git a/docs/ROUTER_QUICK_START.md b/docs/ROUTER_QUICK_START.md index db5e6b1..5f7ddf5 100644 --- a/docs/ROUTER_QUICK_START.md +++ b/docs/ROUTER_QUICK_START.md @@ -1,165 +1,197 @@ -# Router Quick Start Guide - -## What is the Router? - -The KiCAD MCP Server includes an intelligent tool router that organizes 122+ tools into 8 discoverable categories. This reduces AI context usage by up to 70% while maintaining full access to all functionality. - -## How It Works - -Instead of loading all 59 tool schemas into every conversation, Claude now sees: -- **12 direct tools** for high-frequency operations (always visible) -- **4 router tools** for discovering and executing the other 47 tools - -When you ask Claude to do something (like "export gerber files"), it will: -1. Search for relevant tools using `search_tools` -2. Find the `export_gerber` tool in the "export" category -3. Execute it via `execute_tool` with your parameters -4. Return the results - -**You don't need to change how you interact with Claude** - the discovery happens automatically! - -## Tool Categories - -The 110+ routed tools are organized into these categories: - -### 1. board (9 tools) -Board configuration: layers, mounting holes, zones, visualization -- add_layer, set_active_layer, get_layer_list -- add_mounting_hole, add_board_text -- add_zone, get_board_extents, get_board_2d_view -- launch_kicad_ui - -### 2. component (8 tools) -Advanced component operations: edit, delete, search, group, annotate -- rotate_component, delete_component, edit_component -- find_component, get_component_properties -- add_component_annotation, group_components, replace_component - -### 3. export (8 tools) -File export for fabrication and documentation -- export_gerber, export_pdf, export_svg, export_3d -- export_bom, export_netlist, export_position_file, export_vrml - -### 4. drc (8 tools) -Design rule checking and electrical validation -- set_design_rules, get_design_rules, run_drc -- add_net_class, assign_net_to_class, set_layer_constraints -- check_clearance, get_drc_violations - -### 5. schematic (8 tools) -Schematic operations: create, add components, wire connections -- create_schematic, add_schematic_component, add_wire -- add_schematic_connection, add_schematic_net_label -- connect_to_net, get_net_connections, generate_netlist - -### 6. library (4 tools) -Footprint library access and search -- list_libraries, search_footprints -- list_library_footprints, get_footprint_info - -### 7. routing (2 tools) -Advanced routing operations -- add_via, add_copper_pour - -## Direct Tools (Always Available) - -These 12 tools are always visible for common operations: - -**Project Lifecycle:** -- create_project, open_project, save_project, get_project_info - -**Core PCB Operations:** -- place_component, move_component -- add_net, route_trace -- get_board_info, set_board_size -- add_board_outline - -**UI Management:** -- check_kicad_ui - -## Router Tools - -### list_tool_categories -Browse all available tool categories. - -**Example:** -``` -Claude, what tool categories are available? -``` - -### get_category_tools -View all tools in a specific category. - -**Example:** -``` -Show me all export tools available. -``` - -### search_tools -Find tools by keyword. - -**Example:** -``` -Search for tools related to "gerber" or "mounting holes" -``` - -### execute_tool -Execute any routed tool with parameters. - -**Example:** -``` -Execute the export_gerber tool with outputDir set to ./fabrication -``` - -## Usage Examples - -### Natural Interaction (Recommended) -Just ask Claude what you want - it handles discovery automatically: - -``` -"Export gerber files to ./output" -"Add a mounting hole at x=10, y=10" -"Run a design rule check" -"Create a copper pour on the ground layer" -``` - -### Manual Discovery (Optional) -You can also browse tools explicitly: - -``` -"List all tool categories" -"What export tools are available?" -"Search for DRC tools" -``` - -## Benefits - -1. **Reduced Context Usage**: 70% less AI context consumed per conversation -2. **Organized Tools**: Logical categorization makes tools easy to find -3. **Seamless Experience**: Works transparently - no changes to how you interact -4. **Extensible**: Easy to add new tools and categories -5. **Backwards Compatible**: All existing tools still work - -## Technical Details - -- **Registry**: `src/tools/registry.ts` - Tool categorization and lookup -- **Router**: `src/tools/router.ts` - Discovery and execution implementation -- **Server Integration**: `src/server.ts` - Router tools registered at startup - -For implementation details, see: -- [ROUTER_ARCHITECTURE.md](ROUTER_ARCHITECTURE.md) - Design specification -- [ROUTER_IMPLEMENTATION_STATUS.md](ROUTER_IMPLEMENTATION_STATUS.md) - Current status -- [TOOL_INVENTORY.md](TOOL_INVENTORY.md) - Complete tool catalog - -## Token Savings - -**Before Router:** -- 122 tools × ~700 tokens each = ~85K tokens per conversation - -**After Router (Current):** -- 12 direct tools + 4 router tools = 16 tools visible -- Routed tools discovered on-demand -- ~12-15K tokens per conversation -- **~80% reduction** in context usage - -The router pattern is complete and functional, providing efficient tool discovery while maintaining full access to all 122+ tools. +# Router Quick Start Guide + +## What is the Router? + +The KiCAD MCP Server includes an intelligent tool router that organizes 122+ tools into 8 discoverable categories. This reduces AI context usage by up to 70% while maintaining full access to all functionality. + +## How It Works + +Instead of loading all 59 tool schemas into every conversation, Claude now sees: + +- **12 direct tools** for high-frequency operations (always visible) +- **4 router tools** for discovering and executing the other 47 tools + +When you ask Claude to do something (like "export gerber files"), it will: + +1. Search for relevant tools using `search_tools` +2. Find the `export_gerber` tool in the "export" category +3. Execute it via `execute_tool` with your parameters +4. Return the results + +**You don't need to change how you interact with Claude** - the discovery happens automatically! + +## Tool Categories + +The 110+ routed tools are organized into these categories: + +### 1. board (9 tools) + +Board configuration: layers, mounting holes, zones, visualization + +- add_layer, set_active_layer, get_layer_list +- add_mounting_hole, add_board_text +- add_zone, get_board_extents, get_board_2d_view +- launch_kicad_ui + +### 2. component (8 tools) + +Advanced component operations: edit, delete, search, group, annotate + +- rotate_component, delete_component, edit_component +- find_component, get_component_properties +- add_component_annotation, group_components, replace_component + +### 3. export (8 tools) + +File export for fabrication and documentation + +- export_gerber, export_pdf, export_svg, export_3d +- export_bom, export_netlist, export_position_file, export_vrml + +### 4. drc (8 tools) + +Design rule checking and electrical validation + +- set_design_rules, get_design_rules, run_drc +- add_net_class, assign_net_to_class, set_layer_constraints +- check_clearance, get_drc_violations + +### 5. schematic (8 tools) + +Schematic operations: create, add components, wire connections + +- create_schematic, add_schematic_component, add_wire +- add_schematic_connection, add_schematic_net_label +- connect_to_net, get_net_connections, generate_netlist + +### 6. library (4 tools) + +Footprint library access and search + +- list_libraries, search_footprints +- list_library_footprints, get_footprint_info + +### 7. routing (2 tools) + +Advanced routing operations + +- add_via, add_copper_pour + +## Direct Tools (Always Available) + +These 12 tools are always visible for common operations: + +**Project Lifecycle:** + +- create_project, open_project, save_project, get_project_info + +**Core PCB Operations:** + +- place_component, move_component +- add_net, route_trace +- get_board_info, set_board_size +- add_board_outline + +**UI Management:** + +- check_kicad_ui + +## Router Tools + +### list_tool_categories + +Browse all available tool categories. + +**Example:** + +``` +Claude, what tool categories are available? +``` + +### get_category_tools + +View all tools in a specific category. + +**Example:** + +``` +Show me all export tools available. +``` + +### search_tools + +Find tools by keyword. + +**Example:** + +``` +Search for tools related to "gerber" or "mounting holes" +``` + +### execute_tool + +Execute any routed tool with parameters. + +**Example:** + +``` +Execute the export_gerber tool with outputDir set to ./fabrication +``` + +## Usage Examples + +### Natural Interaction (Recommended) + +Just ask Claude what you want - it handles discovery automatically: + +``` +"Export gerber files to ./output" +"Add a mounting hole at x=10, y=10" +"Run a design rule check" +"Create a copper pour on the ground layer" +``` + +### Manual Discovery (Optional) + +You can also browse tools explicitly: + +``` +"List all tool categories" +"What export tools are available?" +"Search for DRC tools" +``` + +## Benefits + +1. **Reduced Context Usage**: 70% less AI context consumed per conversation +2. **Organized Tools**: Logical categorization makes tools easy to find +3. **Seamless Experience**: Works transparently - no changes to how you interact +4. **Extensible**: Easy to add new tools and categories +5. **Backwards Compatible**: All existing tools still work + +## Technical Details + +- **Registry**: `src/tools/registry.ts` - Tool categorization and lookup +- **Router**: `src/tools/router.ts` - Discovery and execution implementation +- **Server Integration**: `src/server.ts` - Router tools registered at startup + +For implementation details, see: + +- [ROUTER_ARCHITECTURE.md](ROUTER_ARCHITECTURE.md) - Design specification +- [ROUTER_IMPLEMENTATION_STATUS.md](ROUTER_IMPLEMENTATION_STATUS.md) - Current status +- [TOOL_INVENTORY.md](TOOL_INVENTORY.md) - Complete tool catalog + +## Token Savings + +**Before Router:** + +- 122 tools × ~700 tokens each = ~85K tokens per conversation + +**After Router (Current):** + +- 12 direct tools + 4 router tools = 16 tools visible +- Routed tools discovered on-demand +- ~12-15K tokens per conversation +- **~80% reduction** in context usage + +The router pattern is complete and functional, providing efficient tool discovery while maintaining full access to all 122+ tools. diff --git a/docs/ROUTING_TOOLS_REFERENCE.md b/docs/ROUTING_TOOLS_REFERENCE.md index b332295..3b99ea5 100644 --- a/docs/ROUTING_TOOLS_REFERENCE.md +++ b/docs/ROUTING_TOOLS_REFERENCE.md @@ -12,17 +12,19 @@ Create a new net on the PCB. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| name | string | Yes | Net name | -| netClass | string | No | Net class name | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | -------------- | +| name | string | Yes | Net name | +| netClass | string | No | Net class name | **Usage Notes:** + - Creates a new net that can be assigned to traces and pads - If the net already exists, it will be reused - Net class assignment is optional; defaults to "Default" if not specified **Example:** + ```json { "name": "VCC_3V3", @@ -38,25 +40,27 @@ Route a trace segment between two XY points on a fixed layer. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| start | object | Yes | Start position with x, y, and optional unit | -| end | object | Yes | End position with x, y, and optional unit | -| layer | string | Yes | PCB layer | -| width | number | Yes | Trace width in mm | -| net | string | Yes | Net name | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | ------------------------------------------- | +| start | object | Yes | Start position with x, y, and optional unit | +| end | object | Yes | End position with x, y, and optional unit | +| layer | string | Yes | PCB layer | +| width | number | Yes | Trace width in mm | +| net | string | Yes | Net name | **Usage Notes:** + - 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 - 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 **Example:** + ```json { - "start": {"x": 100.0, "y": 50.0, "unit": "mm"}, - "end": {"x": 120.0, "y": 50.0, "unit": "mm"}, + "start": { "x": 100.0, "y": 50.0, "unit": "mm" }, + "end": { "x": 120.0, "y": 50.0, "unit": "mm" }, "layer": "F.Cu", "width": 0.25, "net": "GND" @@ -71,17 +75,18 @@ PREFERRED tool for pad-to-pad routing. Looks up pad positions automatically, det **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| 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) | -| toRef | string | Yes | Reference of the target component (e.g. 'U1') | -| toPad | string/number | Yes | Pad number on the target component (e.g. '15' or 15) | -| layer | string | No | PCB layer (default: F.Cu) | -| width | number | No | Trace width in mm (default: board default) | -| net | string | No | Net name override (default: auto-detected from pad) | +| Parameter | Type | Required | Description | +| --------- | ------------- | -------- | ---------------------------------------------------- | +| 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) | +| toRef | string | Yes | Reference of the target component (e.g. 'U1') | +| toPad | string/number | Yes | Pad number on the target component (e.g. '15' or 15) | +| layer | string | No | PCB layer (default: F.Cu) | +| width | number | No | Trace width in mm (default: board default) | +| net | string | No | Net name override (default: auto-detected from pad) | **Usage Notes:** + - This is the PREFERRED tool for routing between component pads - Automatically looks up pad positions - no need to query them separately - 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 **Example:** + ```json { "fromRef": "U2", @@ -110,22 +116,24 @@ Add a via to the PCB. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| position | object | Yes | Via position with x, y, and optional unit | -| net | string | Yes | Net name | -| viaType | string | No | Via type: "through", "blind", or "buried" | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | ----------------------------------------- | +| position | object | Yes | Via position with x, y, and optional unit | +| net | string | Yes | Net name | +| viaType | string | No | Via type: "through", "blind", or "buried" | **Usage Notes:** + - Through vias connect all layers (default) - Blind vias connect an outer layer to one or more inner layers - Buried vias connect two or more inner layers without reaching outer layers - Position coordinates use mm by default **Example:** + ```json { - "position": {"x": 110.0, "y": 50.0, "unit": "mm"}, + "position": { "x": 110.0, "y": 50.0, "unit": "mm" }, "net": "GND", "viaType": "through" } @@ -141,27 +149,29 @@ Route a differential pair between two sets of points. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| positivePad | object | Yes | Positive pad with reference and pad number | -| negativePad | object | Yes | Negative pad with reference and pad number | -| layer | string | Yes | PCB layer | -| width | number | Yes | Trace width in mm | -| gap | number | Yes | Gap between traces in mm | -| positiveNet | string | Yes | Positive net name | -| negativeNet | string | Yes | Negative net name | +| Parameter | Type | Required | Description | +| ----------- | ------ | -------- | ------------------------------------------ | +| positivePad | object | Yes | Positive pad with reference and pad number | +| negativePad | object | Yes | Negative pad with reference and pad number | +| layer | string | Yes | PCB layer | +| width | number | Yes | Trace width in mm | +| gap | number | Yes | Gap between traces in mm | +| positiveNet | string | Yes | Positive net name | +| negativeNet | string | Yes | Negative net name | **Usage Notes:** + - Used for high-speed signals like USB, Ethernet, HDMI, etc. - Maintains controlled impedance through consistent trace width and gap - Both traces are routed in parallel with specified separation - Pad object format: `{"reference": "U1", "pad": "1"}` **Example:** + ```json { - "positivePad": {"reference": "J1", "pad": "2"}, - "negativePad": {"reference": "J1", "pad": "3"}, + "positivePad": { "reference": "J1", "pad": "2" }, + "negativePad": { "reference": "J1", "pad": "3" }, "layer": "F.Cu", "width": 0.2, "gap": 0.2, @@ -178,14 +188,15 @@ Copy routing pattern (traces and vias) from a group of source components to a ma **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| 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']) | -| includeVias | boolean | No | Also copy vias (default: true) | -| traceWidth | number | No | Override trace width in mm (default: keep original width) | +| Parameter | Type | Required | Description | +| ----------- | ------------- | -------- | ----------------------------------------------------------------------------------------- | +| 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']) | +| includeVias | boolean | No | Also copy vias (default: true) | +| traceWidth | number | No | Override trace width in mm (default: keep original width) | **Usage Notes:** + - 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 - 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 **Example:** + ```json { "sourceRefs": ["U1", "R1", "C1"], @@ -212,18 +224,20 @@ Get a list of all nets in the PCB with optional statistics. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| includeStats | boolean | No | Include statistics (track count, total length, etc.) | -| unit | string | No | Unit for length measurements: "mm" or "inch" | +| Parameter | Type | Required | Description | +| ------------ | ------- | -------- | ---------------------------------------------------- | +| includeStats | boolean | No | Include statistics (track count, total length, etc.) | +| unit | string | No | Unit for length measurements: "mm" or "inch" | **Usage Notes:** + - Returns all nets present in the board - Statistics include track count, via count, and total trace length - Useful for verifying net connectivity and routing completeness - Length measurements default to mm **Example:** + ```json { "includeStats": true, @@ -239,21 +253,23 @@ Create a new net class with custom design rules. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| name | string | Yes | Net class name | -| traceWidth | number | No | Default trace width in mm | -| clearance | number | No | Clearance in mm | -| viaDiameter | number | No | Via diameter in mm | -| viaDrill | number | No | Via drill size in mm | +| Parameter | Type | Required | Description | +| ----------- | ------ | -------- | ------------------------- | +| name | string | Yes | Net class name | +| traceWidth | number | No | Default trace width in mm | +| clearance | number | No | Clearance in mm | +| viaDiameter | number | No | Via diameter in mm | +| viaDrill | number | No | Via drill size in mm | **Usage Notes:** + - Net classes define design rules for groups of nets - 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` - All measurements in mm **Example:** + ```json { "name": "Power", @@ -274,21 +290,23 @@ Delete traces from the PCB. Can delete by UUID, position, or bulk-delete all tra **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| traceUuid | string | No | UUID of a specific trace to delete | -| position | object | No | Delete trace nearest to this position (x, y, optional unit) | -| net | string | No | Delete all traces on this net (bulk delete) | -| layer | string | No | Filter by layer when using net-based deletion | -| includeVias | boolean | No | Include vias in net-based deletion | +| Parameter | Type | Required | Description | +| ----------- | ------- | -------- | ----------------------------------------------------------- | +| traceUuid | string | No | UUID of a specific trace to delete | +| position | object | No | Delete trace nearest to this position (x, y, optional unit) | +| net | string | No | Delete all traces on this net (bulk delete) | +| layer | string | No | Filter by layer when using net-based deletion | +| includeVias | boolean | No | Include vias in net-based deletion | **Usage Notes:** + - Three deletion modes: by UUID (specific), by position (nearest), or by net (bulk) - Position-based deletion finds the closest trace to the specified coordinates - Net-based deletion can be filtered by layer - Vias are excluded from net-based deletion by default unless includeVias is true **Example (bulk delete):** + ```json { "net": "GND", @@ -305,20 +323,22 @@ Query traces on the board with optional filters by net, layer, or bounding box. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| net | string | No | Filter by net name | -| layer | string | No | Filter by layer name | -| boundingBox | object | No | Filter by bounding box region (x1, y1, x2, y2, optional unit) | -| unit | string | No | Unit for coordinates: "mm" or "inch" | +| Parameter | Type | Required | Description | +| ----------- | ------ | -------- | ------------------------------------------------------------- | +| net | string | No | Filter by net name | +| layer | string | No | Filter by layer name | +| boundingBox | object | No | Filter by bounding box region (x1, y1, x2, y2, optional unit) | +| unit | string | No | Unit for coordinates: "mm" or "inch" | **Usage Notes:** + - Returns trace information including UUID, position, width, layer, and net - Filters can be combined (e.g., specific net on specific layer) - Bounding box uses rectangular region defined by opposite corners - Useful for analyzing routing in specific board regions or on specific nets **Example:** + ```json { "net": "VCC_3V3", @@ -334,20 +354,22 @@ Modify an existing trace (change width, layer, or net). **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| traceUuid | string | Yes | UUID of the trace to modify | -| width | number | No | New trace width in mm | -| layer | string | No | New layer name | -| net | string | No | New net name | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | --------------------------- | +| traceUuid | string | Yes | UUID of the trace to modify | +| width | number | No | New trace width in mm | +| layer | string | No | New layer name | +| net | string | No | New net name | **Usage Notes:** + - Requires the trace UUID, which can be obtained from `query_traces` - At least one modification parameter (width, layer, or net) must be provided - Use with caution when changing nets - ensure electrical correctness - Width changes are useful for adjusting impedance or current capacity **Example:** + ```json { "traceUuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", @@ -365,14 +387,15 @@ Add a copper pour (ground/power plane) to the PCB. **Parameters:** -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| layer | string | Yes | PCB layer | -| net | string | Yes | Net name | -| 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. | +| Parameter | Type | Required | Description | +| --------- | ------------- | -------- | ----------------------------------------------------------------------------------------- | +| layer | string | Yes | PCB layer | +| net | string | Yes | Net name | +| 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. | **Usage Notes:** + - Copper pours are typically used for ground and power planes - If no outline is specified, the pour fills the entire board area - 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 **Example:** + ```json { "layer": "B.Cu", "net": "GND", "clearance": 0.2, "outline": [ - {"x": 10.0, "y": 10.0}, - {"x": 90.0, "y": 10.0}, - {"x": 90.0, "y": 60.0}, - {"x": 10.0, "y": 60.0} + { "x": 10.0, "y": 10.0 }, + { "x": 90.0, "y": 10.0 }, + { "x": 90.0, "y": 60.0 }, + { "x": 10.0, "y": 60.0 } ] } ``` @@ -405,6 +429,7 @@ Refill all copper zones on the board. None **Usage Notes:** + - 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 - 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 **Example:** + ```json {} ``` @@ -439,6 +465,7 @@ The simplest and most robust approach for connecting component pads: ``` This automatically: + - Looks up the exact pad positions - Detects the net from the pads - Creates the trace on the appropriate layer diff --git a/docs/SCHEMATIC_TOOLS_REFERENCE.md b/docs/SCHEMATIC_TOOLS_REFERENCE.md index 54f0dad..a1d7823 100644 --- a/docs/SCHEMATIC_TOOLS_REFERENCE.md +++ b/docs/SCHEMATIC_TOOLS_REFERENCE.md @@ -8,268 +8,296 @@ This document provides a complete reference for the 27 schematic tools in the Ki ## Component Operations (8 tools) ### add_schematic_component + Add a component to the schematic. Symbol format is 'Library:SymbolName' (e.g., 'Device:R', 'EDA-MCP:ESP32-C3'). -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the schematic file | -| symbol | string | Yes | Symbol library:name reference (e.g., Device:R, EDA-MCP:ESP32-C3) | -| reference | string | Yes | Component reference (e.g., R1, U1) | -| value | string | No | Component value | -| footprint | string | No | KiCAD footprint (e.g. Resistor_SMD:R_0603_1608Metric) | -| position | object | No | Position on schematic with x and y coordinates | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ---------------------------------------------------------------- | +| schematicPath | string | Yes | Path to the schematic file | +| symbol | string | Yes | Symbol library:name reference (e.g., Device:R, EDA-MCP:ESP32-C3) | +| reference | string | Yes | Component reference (e.g., R1, U1) | +| value | string | No | Component value | +| footprint | string | No | KiCAD footprint (e.g. Resistor_SMD:R_0603_1608Metric) | +| position | object | No | Position on schematic with x and y coordinates | **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 + 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 | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| reference | string | Yes | Reference designator of the component to remove (e.g. R1, U3) | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ------------------------------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| reference | string | Yes | Reference designator of the component to remove (e.g. R1, U3) | ### 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. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| 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) | -| value | string | No | New value string (e.g. 10k, 100nF) | -| newReference | string | No | Rename the reference designator (e.g. R1 → R10) | -| fieldPositions | object | No | Reposition field labels: map of field name to {x, y, angle} (e.g. {"Reference": {"x": 12.5, "y": 17.0}}) | +| Parameter | Type | Required | Description | +| -------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| 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) | +| value | string | No | New value string (e.g. 10k, 100nF) | +| newReference | string | No | Rename the reference designator (e.g. R1 → R10) | +| 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 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 | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| reference | string | Yes | Component reference designator (e.g. R1, U1) | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | -------------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| reference | string | Yes | Component reference designator (e.g. R1, U1) | ### 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. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| filter | object | No | Optional filters with libId and/or referencePrefix fields | -| 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') | +| Parameter | Type | Required | Description | +| ---------------------- | ------ | -------- | --------------------------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| filter | object | No | Optional filters with libId and/or referencePrefix fields | +| 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') | ### move_schematic_component + Move a placed symbol to a new position in the schematic. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| reference | string | Yes | Reference designator (e.g., R1, U1) | -| position | object | Yes | New position with x and y coordinates | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| reference | string | Yes | Reference designator (e.g., R1, U1) | +| position | object | Yes | New position with x and y coordinates | ### rotate_schematic_component + Rotate a placed symbol in the schematic. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| reference | string | Yes | Reference designator (e.g., R1, U1) | -| angle | number | Yes | Rotation angle in degrees (0, 90, 180, 270) | -| mirror | enum | No | Optional mirror axis ("x" or "y") | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ------------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| reference | string | Yes | Reference designator (e.g., R1, U1) | +| angle | number | Yes | Rotation angle in degrees (0, 90, 180, 270) | +| mirror | enum | No | Optional mirror axis ("x" or "y") | ### annotate_schematic + Assign reference designators to unannotated components (R? → R1, R2, ...). Must be called before tools that require known references. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | --------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | ## Wiring and Connections (8 tools) ### add_wire + Add a wire connection in the schematic. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| start | object | Yes | Start position with x and y coordinates | -| end | object | Yes | End position with x and y coordinates | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | --------------------------------------- | +| start | object | Yes | Start position with x and y coordinates | +| end | object | Yes | End position with x and y coordinates | ### 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). -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the schematic file | -| sourceRef | string | Yes | Source component reference (e.g., R1) | -| sourcePin | string | Yes | Source pin name/number (e.g., 1, 2, GND) | -| targetRef | string | Yes | Target component reference (e.g., C1) | -| targetPin | string | Yes | Target pin name/number (e.g., 1, 2, VCC) | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ---------------------------------------- | +| schematicPath | string | Yes | Path to the schematic file | +| sourceRef | string | Yes | Source component reference (e.g., R1) | +| sourcePin | string | Yes | Source pin name/number (e.g., 1, 2, GND) | +| targetRef | string | Yes | Target component reference (e.g., C1) | +| targetPin | string | Yes | Target pin name/number (e.g., 1, 2, VCC) | ### add_schematic_net_label + Add a net label to the schematic. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the schematic file | -| netName | string | Yes | Name of the net (e.g., VCC, GND, SIGNAL_1) | -| position | array | Yes | Position [x, y] for the label | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ------------------------------------------ | +| schematicPath | string | Yes | Path to the schematic file | +| netName | string | Yes | Name of the net (e.g., VCC, GND, SIGNAL_1) | +| position | array | Yes | Position [x, y] for the label | ### connect_to_net + Connect a component pin to a named net. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the schematic file | -| componentRef | string | Yes | Component reference (e.g., U1, R1) | -| pinName | string | Yes | Pin name/number to connect | -| netName | string | Yes | Name of the net to connect to | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ---------------------------------- | +| schematicPath | string | Yes | Path to the schematic file | +| componentRef | string | Yes | Component reference (e.g., U1, R1) | +| pinName | string | Yes | Pin name/number to connect | +| netName | string | Yes | Name of the net to connect to | **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 -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 | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the schematic file | -| sourceRef | string | Yes | Source connector reference (e.g. J1) | -| targetRef | string | Yes | Target connector reference (e.g. J2) | -| netPrefix | string | No | Net name prefix, e.g. 'CSI' → CSI_1, CSI_2 (default: PIN) | -| pinOffset | number | No | Add to pin number when building net name (default: 0) | +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 | +| ------------- | ------ | -------- | --------------------------------------------------------- | +| schematicPath | string | Yes | Path to the schematic file | +| sourceRef | string | Yes | Source connector reference (e.g. J1) | +| targetRef | string | Yes | Target connector reference (e.g. J2) | +| netPrefix | string | No | Net name prefix, e.g. 'CSI' → CSI_1, CSI_2 (default: PIN) | +| pinOffset | number | No | Add to pin number when building net name (default: 0) | **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 + 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 | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the schematic file | -| reference | string | Yes | Component reference designator (e.g. U1, R1, J2) | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ------------------------------------------------ | +| schematicPath | string | Yes | Path to the schematic file | +| reference | string | Yes | Component reference designator (e.g. U1, R1, J2) | ### delete_schematic_wire + Remove a wire from the schematic by start and end coordinates. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| start | object | Yes | Wire start position with x and y coordinates | -| end | object | Yes | Wire end position with x and y coordinates | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | -------------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| start | object | Yes | Wire start position with x and y coordinates | +| end | object | Yes | Wire end position with x and y coordinates | ### delete_schematic_net_label + Remove a net label from the schematic. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| 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) | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | -------------------------------------------------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| 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) | ## Net Analysis (4 tools) ### get_net_connections + Get all connections for a named net. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the schematic file | -| netName | string | Yes | Name of the net to query | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | -------------------------- | +| schematicPath | string | Yes | Path to the schematic file | +| 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. ### list_schematic_nets + List all nets in the schematic with their connections. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | --------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | ### list_schematic_wires + List all wires in the schematic with start/end coordinates. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | --------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | ### list_schematic_labels + List all net labels, global labels, and power flags in the schematic. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | --------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | ## Schematic Creation and Export (5 tools) ### create_schematic + Create a new schematic. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| name | string | Yes | Schematic name | -| path | string | No | Optional path | +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | -------------- | +| name | string | Yes | Schematic name | +| path | string | No | Optional path | ### export_schematic_svg + Export schematic to SVG format using kicad-cli. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| outputPath | string | Yes | Output SVG file path | -| blackAndWhite | boolean | No | Export in black and white | +| Parameter | Type | Required | Description | +| ------------- | ------- | -------- | --------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| outputPath | string | Yes | Output SVG file path | +| blackAndWhite | boolean | No | Export in black and white | ### export_schematic_pdf + Export schematic to PDF format using kicad-cli. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| outputPath | string | Yes | Output PDF file path | -| blackAndWhite | boolean | No | Export in black and white | +| Parameter | Type | Required | Description | +| ------------- | ------- | -------- | --------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| outputPath | string | Yes | Output PDF file path | +| blackAndWhite | boolean | No | Export in black and white | ### 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. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch file | -| format | enum | No | Output format ("png" or "svg", default: png) | -| width | number | No | Image width in pixels (default: 1200) | -| height | number | No | Image height in pixels (default: 900) | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | -------------------------------------------- | +| schematicPath | string | Yes | Path to the .kicad_sch file | +| format | enum | No | Output format ("png" or "svg", default: png) | +| width | number | No | Image width in pixels (default: 1200) | +| height | number | No | Image height in pixels (default: 900) | ### generate_netlist + Generate a netlist from the schematic. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the schematic file | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | -------------------------- | +| 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). ## Validation and Synchronization (3 tools) ### 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. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Path to the .kicad_sch schematic file | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ------------------------------------- | +| 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. ### 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. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| schematicPath | string | Yes | Absolute path to the .kicad_sch schematic file | -| boardPath | string | Yes | Absolute path to the .kicad_pcb board file | +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | ---------------------------------------------- | +| schematicPath | string | Yes | Absolute path to the .kicad_sch schematic file | +| boardPath | string | Yes | Absolute path to the .kicad_pcb board file | **Usage Notes:** This is the F8 equivalent. It synchronizes the schematic design to the PCB, creating footprints on the board and assigning nets. This step is critical in the workflow: design in schematic → sync_schematic_to_board → place and route on PCB. ## Example Workflows ### Basic Circuit Design + 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. - 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 ### FFC Passthrough Adapter + 1. **Add connectors:** Place two FFC connectors using `add_schematic_component` - Example: J1 and J2, both 20-pin FFC connectors 2. **Connect passthrough:** Use `connect_passthrough` with `sourceRef: "J1"`, `targetRef: "J2"`, `netPrefix: "CSI"` diff --git a/docs/STATUS_SUMMARY.md b/docs/STATUS_SUMMARY.md index b46e076..df216c8 100644 --- a/docs/STATUS_SUMMARY.md +++ b/docs/STATUS_SUMMARY.md @@ -8,46 +8,47 @@ ## Quick Stats -| Metric | Value | -|--------|-------| -| Total MCP Tools | 122 | -| Tool Categories | 16 | -| KiCAD 9.0 Compatible | Yes (verified) | -| Platforms | Linux, Windows, macOS | -| JLCPCB Parts Catalog | 2.5M+ components | -| Symbol Access | ~10,000 via dynamic loading | -| Footprint Libraries | 153+ auto-discovered | -| Contributors | 10+ | -| MCP Protocol Version | 2025-06-18 | +| Metric | Value | +| -------------------- | --------------------------- | +| Total MCP Tools | 122 | +| Tool Categories | 16 | +| KiCAD 9.0 Compatible | Yes (verified) | +| Platforms | Linux, Windows, macOS | +| JLCPCB Parts Catalog | 2.5M+ components | +| Symbol Access | ~10,000 via dynamic loading | +| Footprint Libraries | 153+ auto-discovered | +| Contributors | 10+ | +| MCP Protocol Version | 2025-06-18 | --- ## Feature Completion Matrix -| Feature Category | Status | Tool Count | Details | -|-----------------|--------|------------|---------| -| Project Management | Complete | 5 | Create, open, save, info, snapshot | -| 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 | -| Routing | Complete | 13 | Traces, vias, pad-to-pad, differential pairs, netclasses, copy pattern | -| Design Rules / DRC | Complete | 8 | Set/get rules, DRC, net classes, clearance checks | -| Export | Complete | 8 | Gerber, PDF, SVG, 3D, BOM, netlist, position file, VRML | -| Schematic | Complete | 27 | Components, wiring, net labels, connections, ERC, export, sync to board | -| Footprint Libraries | Complete | 4 | List, search, browse, info | -| Symbol Libraries | Complete | 4 | List, search, browse, info | -| Footprint Creator | Complete | 4 | Create custom footprints, edit pads, register libraries | -| Symbol Creator | Complete | 4 | Create custom symbols, register libraries | -| Datasheet Tools | Complete | 2 | LCSC datasheet enrichment | -| JLCPCB Integration | Complete | 5 | Local DB, search, part details, stats, alternatives | -| Freerouting | Complete | 4 | Autoroute, DSN export, SES import, availability check | -| UI Management | Complete | 2 | Check/launch KiCAD | -| Router Tools | Complete | 4 | Category browsing, tool search, execute | +| Feature Category | Status | Tool Count | Details | +| ------------------- | -------- | ---------- | ----------------------------------------------------------------------- | +| Project Management | Complete | 5 | Create, open, save, info, snapshot | +| 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 | +| Routing | Complete | 13 | Traces, vias, pad-to-pad, differential pairs, netclasses, copy pattern | +| Design Rules / DRC | Complete | 8 | Set/get rules, DRC, net classes, clearance checks | +| Export | Complete | 8 | Gerber, PDF, SVG, 3D, BOM, netlist, position file, VRML | +| Schematic | Complete | 27 | Components, wiring, net labels, connections, ERC, export, sync to board | +| Footprint Libraries | Complete | 4 | List, search, browse, info | +| Symbol Libraries | Complete | 4 | List, search, browse, info | +| Footprint Creator | Complete | 4 | Create custom footprints, edit pads, register libraries | +| Symbol Creator | Complete | 4 | Create custom symbols, register libraries | +| Datasheet Tools | Complete | 2 | LCSC datasheet enrichment | +| JLCPCB Integration | Complete | 5 | Local DB, search, part details, stats, alternatives | +| Freerouting | Complete | 4 | Autoroute, DSN export, SES import, availability check | +| UI Management | Complete | 2 | Check/launch KiCAD | +| Router Tools | Complete | 4 | Category browsing, tool search, execute | --- ## Architecture ### SWIG Backend (File-based) -- Default + - **Status:** Stable - Direct pcbnew API access via KiCAD's Python bindings - Requires manual KiCAD UI reload to see changes @@ -55,13 +56,16 @@ - Auto-saves after every board-modifying command ### IPC Backend (Real-time) -- Experimental + - **Status:** Functional, 21 commands implemented - Real-time UI synchronization with KiCAD 9+ - Requires KiCAD running with IPC API enabled - Automatic fallback to SWIG when unavailable ### Hybrid Approach + The server automatically selects the best backend: + - IPC when KiCAD is running with IPC enabled - SWIG fallback when IPC is unavailable - Some operations use both (e.g., footprint placement) @@ -71,18 +75,21 @@ The server automatically selects the best backend: ## Platform Support ### Linux -- Primary Platform + - KiCAD 9.0 detection: Working - Process management: Working - Library discovery: Working (153+ libraries) - IPC backend: Working ### Windows -- Fully Supported + - Automated setup script (setup-windows.ps1) - Process detection via Toolhelp32 API - Library paths auto-detected - Troubleshooting guide available (WINDOWS_TROUBLESHOOTING.md) ### macOS -- Community Supported + - Configuration provided - Process detection implemented - Library paths configured @@ -93,6 +100,7 @@ The server automatically selects the best backend: ## Recent Development Highlights ### v2.2.3 (2026-03-11) + - FFC/ribbon cable passthrough workflow (connect_passthrough, sync_schematic_to_board) - Project snapshot system - SVG logo import @@ -101,20 +109,24 @@ The server automatically selects the best backend: - Critical B.Cu routing fixes ### v2.2.2-alpha (2026-03-01) + - route_pad_to_pad with auto-via insertion - copy_routing_pattern for trace replication - Project-local library resolution ### v2.2.1-alpha (2026-02-28) + - edit_schematic_component with field position support - Footprint and symbol creator tools ### v2.2.0-alpha (2026-02-27) + - 13 new routing/component tools - Datasheet enrichment tools - SWIG/UUID bug fixes ### v2.1.0-alpha (2026-01-10) + - Complete schematic wiring system - Dynamic symbol loading (~10,000 symbols) - JLCPCB parts integration @@ -124,35 +136,38 @@ The server automatically selects the best backend: ## Community Contributors -| Contributor | Key Contributions | -|------------|-------------------| -| Kletternaut | Routing tools, footprint/symbol creators, passthrough workflow, template fixes | -| Mehanik | Schematic inspection/editing tools, component field positions | -| jflaflamme | Freerouting autorouter integration with Docker/Podman | -| l3wi | Local symbol library search, JLCPCB third-party library support | -| gwall-ceres | MCP protocol compliance, Windows compatibility | -| fariouche | Bug fixes | -| shuofengzhang | XDG relative path handling | -| sid115 | Windows setup script improvements | -| pasrom | MCP server bug fixes | +| Contributor | Key Contributions | +| ------------- | ------------------------------------------------------------------------------ | +| Kletternaut | Routing tools, footprint/symbol creators, passthrough workflow, template fixes | +| Mehanik | Schematic inspection/editing tools, component field positions | +| jflaflamme | Freerouting autorouter integration with Docker/Podman | +| l3wi | Local symbol library search, JLCPCB third-party library support | +| gwall-ceres | MCP protocol compliance, Windows compatibility | +| fariouche | Bug fixes | +| shuofengzhang | XDG relative path handling | +| sid115 | Windows setup script improvements | +| pasrom | MCP server bug fixes | --- ## Getting Help **For Users:** + 1. Check [README.md](../README.md) for installation 2. Review [KNOWN_ISSUES.md](KNOWN_ISSUES.md) for common problems 3. Check logs: `~/.kicad-mcp/logs/kicad_interface.log` **For Contributors:** + 1. Read [CONTRIBUTING.md](../CONTRIBUTING.md) for development setup 2. Check [ARCHITECTURE.md](ARCHITECTURE.md) for system design 3. Review the [Documentation Index](INDEX.md) for all available docs **Issues:** + - Open an issue on GitHub with OS, KiCAD version, and error details --- -*Last Updated: 2026-03-21* +_Last Updated: 2026-03-21_ diff --git a/docs/SVG_IMPORT_GUIDE.md b/docs/SVG_IMPORT_GUIDE.md index 5752776..0a11f74 100644 --- a/docs/SVG_IMPORT_GUIDE.md +++ b/docs/SVG_IMPORT_GUIDE.md @@ -14,18 +14,19 @@ Imports an SVG file as filled graphic polygons onto a PCB layer. Curves are line **Parameters:** -| Parameter | Type | Required | Default | Description | -|-----------|------|----------|---------|-------------| -| `pcbPath` | string | Yes | -- | Path to the .kicad_pcb file | -| `svgPath` | string | Yes | -- | Path to the SVG logo file | -| `x` | number | Yes | -- | X position of the logo top-left corner in mm | -| `y` | number | Yes | -- | Y position of the logo top-left corner in mm | -| `width` | number | Yes | -- | Target width of the logo in mm (height scales to preserve aspect ratio) | -| `layer` | string | No | F.SilkS | PCB layer name (e.g., F.SilkS, B.SilkS, F.Cu, B.Cu) | -| `strokeWidth` | number | No | 0 | Outline stroke width in mm (0 = no outline) | -| `filled` | boolean | No | true | Fill polygons with solid color | +| Parameter | Type | Required | Default | Description | +| ------------- | ------- | -------- | ------- | ----------------------------------------------------------------------- | +| `pcbPath` | string | Yes | -- | Path to the .kicad_pcb file | +| `svgPath` | string | Yes | -- | Path to the SVG logo file | +| `x` | number | Yes | -- | X position of the logo top-left corner in mm | +| `y` | number | Yes | -- | Y position of the logo top-left corner in mm | +| `width` | number | Yes | -- | Target width of the logo in mm (height scales to preserve aspect ratio) | +| `layer` | string | No | F.SilkS | PCB layer name (e.g., F.SilkS, B.SilkS, F.Cu, B.Cu) | +| `strokeWidth` | number | No | 0 | Outline stroke width in mm (0 = no outline) | +| `filled` | boolean | No | true | Fill polygons with solid color | **Returns:** + - Polygon count - Final dimensions (width x height in mm) - Layer used @@ -35,18 +36,21 @@ Imports an SVG file as filled graphic polygons onto a PCB layer. Curves are line ## SVG Requirements ### Supported Features + - Path elements with M, L, H, V, C, S, Q, T, A, Z commands - Filled shapes (polygons, rectangles, circles, ellipses) - Nested groups and transforms - Cubic and quadratic Bezier curves (linearized automatically) ### Recommendations + - Use simple, solid shapes -- avoid complex gradients or filters - Convert text to paths/outlines before importing - Ensure shapes are filled (not just stroked) for best results - Keep the SVG clean -- remove unnecessary metadata and layers ### What Will Not Work + - Raster images embedded in SVG - CSS-based styling (inline style attributes are preferred) - 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 If starting from a raster image (PNG, JPG): + - Use a vector graphics editor (Inkscape, Illustrator, Figma) to trace the image - In Inkscape: Path > Trace Bitmap to convert - Export as plain SVG If starting from a vector logo: + - Open in a vector editor - Convert all text to paths (Object to Path / Create Outlines) - Remove unnecessary layers and hidden elements @@ -87,14 +93,14 @@ Re-run `import_svg_logo` with different position, width, or layer parameters. ## Layer Options -| Layer | Use Case | -|-------|----------| -| `F.SilkS` | Front silkscreen (most common for logos) | -| `B.SilkS` | Back silkscreen | -| `F.Cu` | Front copper (logo as exposed copper) | -| `B.Cu` | Back copper | -| `F.Mask` | Front solder mask opening (exposes copper underneath) | -| `B.Mask` | Back solder mask opening | +| Layer | Use Case | +| --------- | ----------------------------------------------------- | +| `F.SilkS` | Front silkscreen (most common for logos) | +| `B.SilkS` | Back silkscreen | +| `F.Cu` | Front copper (logo as exposed copper) | +| `B.Cu` | Back copper | +| `F.Mask` | Front solder mask opening (exposes copper underneath) | +| `B.Mask` | Back solder mask opening | --- diff --git a/docs/TOOL_INVENTORY.md b/docs/TOOL_INVENTORY.md index f71a7e3..5254698 100644 --- a/docs/TOOL_INVENTORY.md +++ b/docs/TOOL_INVENTORY.md @@ -16,325 +16,325 @@ The server uses a **router pattern** to reduce AI context usage. Tools fall into ## Project Management (5 tools) -*Source: `src/tools/project.ts`* +_Source: `src/tools/project.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `create_project` | Create a new KiCAD project (.kicad_pro, .kicad_pcb, .kicad_sch) | Direct | -| `open_project` | Open an existing KiCAD project | Direct | -| `save_project` | Save the current project | Direct | -| `get_project_info` | Get project metadata and information | Direct | +| Tool | Description | Access | +| ------------------ | ---------------------------------------------------------------- | ------ | +| `create_project` | Create a new KiCAD project (.kicad_pro, .kicad_pcb, .kicad_sch) | Direct | +| `open_project` | Open an existing KiCAD project | Direct | +| `save_project` | Save the current project | Direct | +| `get_project_info` | Get project metadata and information | Direct | | `snapshot_project` | Save a named checkpoint snapshot (renders PDF, saves step label) | Direct | --- ## Board Management (12 tools) -*Source: `src/tools/board.ts`* +_Source: `src/tools/board.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `set_board_size` | Set PCB dimensions (width, height, unit) | Direct | -| `add_board_outline` | Add board outline (rectangle, circle, polygon, rounded_rectangle) | Direct | -| `get_board_info` | Get board metadata and properties | Direct | -| `add_layer` | Add copper/technical/signal layer | Routed (board) | -| `set_active_layer` | Change the active working layer | Routed (board) | -| `get_layer_list` | List all layers on the board | Routed (board) | -| `add_mounting_hole` | Add mounting hole with optional pad | Routed (board) | -| `add_board_text` | Add text annotation to board | Routed (board) | -| `add_zone` | Add copper zone/pour with clearance settings | Routed (board) | -| `get_board_extents` | Get bounding box of board | Routed (board) | -| `get_board_2d_view` | Render 2D board view (PNG/JPG/SVG) | Routed (board) | -| `import_svg_logo` | Import SVG file as polygons on silkscreen layer | Additional | +| Tool | Description | Access | +| ------------------- | ----------------------------------------------------------------- | -------------- | +| `set_board_size` | Set PCB dimensions (width, height, unit) | Direct | +| `add_board_outline` | Add board outline (rectangle, circle, polygon, rounded_rectangle) | Direct | +| `get_board_info` | Get board metadata and properties | Direct | +| `add_layer` | Add copper/technical/signal layer | Routed (board) | +| `set_active_layer` | Change the active working layer | Routed (board) | +| `get_layer_list` | List all layers on the board | Routed (board) | +| `add_mounting_hole` | Add mounting hole with optional pad | Routed (board) | +| `add_board_text` | Add text annotation to board | Routed (board) | +| `add_zone` | Add copper zone/pour with clearance settings | Routed (board) | +| `get_board_extents` | Get bounding box of board | Routed (board) | +| `get_board_2d_view` | Render 2D board view (PNG/JPG/SVG) | Routed (board) | +| `import_svg_logo` | Import SVG file as polygons on silkscreen layer | Additional | --- ## Component Management (16 tools) -*Source: `src/tools/component.ts`* +_Source: `src/tools/component.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `place_component` | Place footprint on PCB (position, rotation, reference, value) | Direct | -| `move_component` | Move component to new position | Direct | -| `rotate_component` | Rotate component (absolute angle) | Routed (component) | -| `delete_component` | Remove component from board | Routed (component) | -| `edit_component` | Edit component properties (reference, value, footprint) | Routed (component) | -| `find_component` | Search components by reference or value | Routed (component) | -| `get_component_properties` | Get all properties of a component | Routed (component) | -| `add_component_annotation` | Add annotation/comment to component | Routed (component) | -| `group_components` | Group multiple components together | Routed (component) | -| `replace_component` | Replace component with different footprint | Routed (component) | -| `get_component_pads` | Get all pad information for a component | Additional | -| `get_component_list` | List all components with optional filters | Additional | -| `get_pad_position` | Get precise position of a specific pad | Additional | -| `place_component_array` | Place array of components (rows x columns) | Additional | -| `align_components` | Align components (horizontal, vertical, grid) | Additional | -| `duplicate_component` | Duplicate component with offset | Additional | +| Tool | Description | Access | +| -------------------------- | ------------------------------------------------------------- | ------------------ | +| `place_component` | Place footprint on PCB (position, rotation, reference, value) | Direct | +| `move_component` | Move component to new position | Direct | +| `rotate_component` | Rotate component (absolute angle) | Routed (component) | +| `delete_component` | Remove component from board | Routed (component) | +| `edit_component` | Edit component properties (reference, value, footprint) | Routed (component) | +| `find_component` | Search components by reference or value | Routed (component) | +| `get_component_properties` | Get all properties of a component | Routed (component) | +| `add_component_annotation` | Add annotation/comment to component | Routed (component) | +| `group_components` | Group multiple components together | Routed (component) | +| `replace_component` | Replace component with different footprint | Routed (component) | +| `get_component_pads` | Get all pad information for a component | Additional | +| `get_component_list` | List all components with optional filters | Additional | +| `get_pad_position` | Get precise position of a specific pad | Additional | +| `place_component_array` | Place array of components (rows x columns) | Additional | +| `align_components` | Align components (horizontal, vertical, grid) | Additional | +| `duplicate_component` | Duplicate component with offset | Additional | --- ## Routing (13 tools) -*Source: `src/tools/routing.ts`* +_Source: `src/tools/routing.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `add_net` | Create a new net on the PCB | Direct | -| `route_trace` | Route trace segment between XY points (single layer) | Direct | -| `add_via` | Add via (through/blind/buried) | Routed (routing) | -| `add_copper_pour` | Add copper pour / ground plane | Routed (routing) | -| `delete_trace` | Delete traces by UUID, position, or bulk by net | Additional | -| `query_traces` | Query/filter traces by net, layer, or bounding box | Additional | -| `get_nets_list` | List all nets with statistics | Additional | -| `modify_trace` | Modify existing trace (width, layer, net) | Additional | -| `create_netclass` | Create net class with design rules | Additional | -| `route_differential_pair` | Route differential pair traces | Additional | -| `refill_zones` | Refill all copper zones | Additional | -| `route_pad_to_pad` | Route trace between two pads with auto-via insertion | Additional | -| `copy_routing_pattern` | Copy routing from source to target component groups | Additional | +| Tool | Description | Access | +| ------------------------- | ---------------------------------------------------- | ---------------- | +| `add_net` | Create a new net on the PCB | Direct | +| `route_trace` | Route trace segment between XY points (single layer) | Direct | +| `add_via` | Add via (through/blind/buried) | Routed (routing) | +| `add_copper_pour` | Add copper pour / ground plane | Routed (routing) | +| `delete_trace` | Delete traces by UUID, position, or bulk by net | Additional | +| `query_traces` | Query/filter traces by net, layer, or bounding box | Additional | +| `get_nets_list` | List all nets with statistics | Additional | +| `modify_trace` | Modify existing trace (width, layer, net) | Additional | +| `create_netclass` | Create net class with design rules | Additional | +| `route_differential_pair` | Route differential pair traces | Additional | +| `refill_zones` | Refill all copper zones | Additional | +| `route_pad_to_pad` | Route trace between two pads with auto-via insertion | Additional | +| `copy_routing_pattern` | Copy routing from source to target component groups | Additional | --- ## Design Rules and DRC (8 tools) -*Source: `src/tools/design-rules.ts`* +_Source: `src/tools/design-rules.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `set_design_rules` | Set global design rules (clearance, track width, via sizes) | Routed (drc) | -| `get_design_rules` | Get current design rules | Routed (drc) | -| `run_drc` | Run design rule check | Routed (drc) | -| `add_net_class` | Add net class with custom rules | Routed (drc) | -| `assign_net_to_class` | Assign net to a net class | Routed (drc) | -| `set_layer_constraints` | Set layer-specific constraints | Routed (drc) | -| `check_clearance` | Check clearance between two items | Routed (drc) | -| `get_drc_violations` | Get DRC violation list (filter by severity) | Routed (drc) | +| Tool | Description | Access | +| ----------------------- | ----------------------------------------------------------- | ------------ | +| `set_design_rules` | Set global design rules (clearance, track width, via sizes) | Routed (drc) | +| `get_design_rules` | Get current design rules | Routed (drc) | +| `run_drc` | Run design rule check | Routed (drc) | +| `add_net_class` | Add net class with custom rules | Routed (drc) | +| `assign_net_to_class` | Assign net to a net class | Routed (drc) | +| `set_layer_constraints` | Set layer-specific constraints | Routed (drc) | +| `check_clearance` | Check clearance between two items | Routed (drc) | +| `get_drc_violations` | Get DRC violation list (filter by severity) | Routed (drc) | --- ## Export (8 tools) -*Source: `src/tools/export.ts`* +_Source: `src/tools/export.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `export_gerber` | Export Gerber files for fabrication | Routed (export) | -| `export_pdf` | Export PDF with layer selection and page size | Routed (export) | -| `export_svg` | Export SVG vector graphics | Routed (export) | -| `export_3d` | Export 3D model (STEP, STL, VRML, OBJ) | Routed (export) | -| `export_bom` | Export Bill of Materials (CSV, XML, HTML, JSON) | Routed (export) | -| `export_netlist` | Export netlist (KiCad, Spice, Cadstar, OrcadPCB2) | Routed (export) | +| Tool | Description | Access | +| ---------------------- | ------------------------------------------------- | --------------- | +| `export_gerber` | Export Gerber files for fabrication | Routed (export) | +| `export_pdf` | Export PDF with layer selection and page size | Routed (export) | +| `export_svg` | Export SVG vector graphics | Routed (export) | +| `export_3d` | Export 3D model (STEP, STL, VRML, OBJ) | Routed (export) | +| `export_bom` | Export Bill of Materials (CSV, XML, HTML, JSON) | Routed (export) | +| `export_netlist` | Export netlist (KiCad, Spice, Cadstar, OrcadPCB2) | Routed (export) | | `export_position_file` | Export component position file for pick and place | Routed (export) | -| `export_vrml` | Export VRML 3D model | Routed (export) | +| `export_vrml` | Export VRML 3D model | Routed (export) | --- ## Schematic (27 tools) -*Source: `src/tools/schematic.ts`* +_Source: `src/tools/schematic.ts`_ ### Component Operations -| Tool | Description | Access | -|------|-------------|--------| -| `add_schematic_component` | Add component to schematic (symbol from library) | Direct | -| `delete_schematic_component` | Remove component from schematic | Additional | -| `edit_schematic_component` | Edit component properties (footprint, value, reference) | Additional | -| `get_schematic_component` | Get component info with field positions | Additional | -| `list_schematic_components` | List all components in schematic | Direct | -| `move_schematic_component` | Move component to new position | Routed (schematic) | -| `rotate_schematic_component` | Rotate component | Routed (schematic) | -| `annotate_schematic` | Auto-annotate reference designators | Direct | +| Tool | Description | Access | +| ---------------------------- | ------------------------------------------------------- | ------------------ | +| `add_schematic_component` | Add component to schematic (symbol from library) | Direct | +| `delete_schematic_component` | Remove component from schematic | Additional | +| `edit_schematic_component` | Edit component properties (footprint, value, reference) | Additional | +| `get_schematic_component` | Get component info with field positions | Additional | +| `list_schematic_components` | List all components in schematic | Direct | +| `move_schematic_component` | Move component to new position | Routed (schematic) | +| `rotate_schematic_component` | Rotate component | Routed (schematic) | +| `annotate_schematic` | Auto-annotate reference designators | Direct | ### Wiring and Connections -| Tool | Description | Access | -|------|-------------|--------| -| `add_wire` | Add wire connection between two points | Routed (schematic) | -| `delete_schematic_wire` | Delete wire segment | Routed (schematic) | -| `add_schematic_connection` | Connect two component pins with wire | Routed (schematic) | -| `add_schematic_net_label` | Add net label to schematic | Direct | -| `delete_schematic_net_label` | Delete net label | Routed (schematic) | -| `connect_to_net` | Connect component pin to named net | Direct | -| `connect_passthrough` | Connect all matching pins between two connectors | Direct | -| `get_schematic_pin_locations` | Get pin locations for a component | Additional | +| Tool | Description | Access | +| ----------------------------- | ------------------------------------------------ | ------------------ | +| `add_wire` | Add wire connection between two points | Routed (schematic) | +| `delete_schematic_wire` | Delete wire segment | Routed (schematic) | +| `add_schematic_connection` | Connect two component pins with wire | Routed (schematic) | +| `add_schematic_net_label` | Add net label to schematic | Direct | +| `delete_schematic_net_label` | Delete net label | Routed (schematic) | +| `connect_to_net` | Connect component pin to named net | Direct | +| `connect_passthrough` | Connect all matching pins between two connectors | Direct | +| `get_schematic_pin_locations` | Get pin locations for a component | Additional | ### Net Analysis -| Tool | Description | Access | -|------|-------------|--------| -| `get_net_connections` | Get all connections for a net | Routed (schematic) | -| `list_schematic_nets` | List all nets in schematic | Routed (schematic) | -| `list_schematic_wires` | List all wires in schematic | Routed (schematic) | -| `list_schematic_labels` | List all net labels | Routed (schematic) | +| Tool | Description | Access | +| ----------------------- | ----------------------------- | ------------------ | +| `get_net_connections` | Get all connections for a net | Routed (schematic) | +| `list_schematic_nets` | List all nets in schematic | Routed (schematic) | +| `list_schematic_wires` | List all wires in schematic | Routed (schematic) | +| `list_schematic_labels` | List all net labels | Routed (schematic) | ### Schematic Creation and Export -| Tool | Description | Access | -|------|-------------|--------| -| `create_schematic` | Create a new schematic file | Routed (schematic) | -| `get_schematic_view` | Get schematic as image (PNG/SVG) | Routed (schematic) | -| `export_schematic_svg` | Export schematic to SVG | Routed (schematic) | -| `export_schematic_pdf` | Export schematic to PDF | Routed (schematic) | +| Tool | Description | Access | +| ---------------------- | -------------------------------- | ------------------ | +| `create_schematic` | Create a new schematic file | Routed (schematic) | +| `get_schematic_view` | Get schematic as image (PNG/SVG) | Routed (schematic) | +| `export_schematic_svg` | Export schematic to SVG | Routed (schematic) | +| `export_schematic_pdf` | Export schematic to PDF | Routed (schematic) | ### Validation and Synchronization -| Tool | Description | Access | -|------|-------------|--------| -| `run_erc` | Run electrical rule check | Additional | -| `generate_netlist` | Generate netlist from schematic | Routed (schematic) | -| `sync_schematic_to_board` | Sync schematic components/nets to PCB (F8 equivalent) | Direct | +| Tool | Description | Access | +| ------------------------- | ----------------------------------------------------- | ------------------ | +| `run_erc` | Run electrical rule check | Additional | +| `generate_netlist` | Generate netlist from schematic | Routed (schematic) | +| `sync_schematic_to_board` | Sync schematic components/nets to PCB (F8 equivalent) | Direct | --- ## Footprint Libraries (4 tools) -*Source: `src/tools/library.ts`* +_Source: `src/tools/library.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `list_libraries` | List all footprint libraries | Routed (library) | -| `search_footprints` | Search footprints across libraries | Routed (library) | +| Tool | Description | Access | +| ------------------------- | ------------------------------------- | ---------------- | +| `list_libraries` | List all footprint libraries | Routed (library) | +| `search_footprints` | Search footprints across libraries | Routed (library) | | `list_library_footprints` | List footprints in a specific library | Routed (library) | -| `get_footprint_info` | Get detailed footprint information | Routed (library) | +| `get_footprint_info` | Get detailed footprint information | Routed (library) | --- ## Symbol Libraries (4 tools) -*Source: `src/tools/library-symbol.ts`* +_Source: `src/tools/library-symbol.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `list_symbol_libraries` | List all symbol libraries from sym-lib-table | Additional | -| `search_symbols` | Search symbols by name, LCSC ID, or description | Additional | -| `list_library_symbols` | List symbols in a specific library | Additional | -| `get_symbol_info` | Get detailed symbol information | Additional | +| Tool | Description | Access | +| ----------------------- | ----------------------------------------------- | ---------- | +| `list_symbol_libraries` | List all symbol libraries from sym-lib-table | Additional | +| `search_symbols` | Search symbols by name, LCSC ID, or description | Additional | +| `list_library_symbols` | List symbols in a specific library | Additional | +| `get_symbol_info` | Get detailed symbol information | Additional | --- ## Footprint Creator (4 tools) -*Source: `src/tools/footprint.ts`* +_Source: `src/tools/footprint.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `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 | -| `register_footprint_library` | Register .pretty library in fp-lib-table | Additional | -| `list_footprint_libraries` | List available .pretty libraries | Additional | +| Tool | Description | Access | +| ---------------------------- | ------------------------------------------------------------------------ | ---------- | +| `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 | +| `register_footprint_library` | Register .pretty library in fp-lib-table | Additional | +| `list_footprint_libraries` | List available .pretty libraries | Additional | --- ## Symbol Creator (4 tools) -*Source: `src/tools/symbol-creator.ts`* +_Source: `src/tools/symbol-creator.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `create_symbol` | Create custom .kicad_sym symbol (pins, rectangles, polylines) | Additional | -| `delete_symbol` | Remove symbol from library | Additional | -| `list_symbols_in_library` | List all symbols in a .kicad_sym file | Additional | -| `register_symbol_library` | Register library in sym-lib-table | Additional | +| Tool | Description | Access | +| ------------------------- | ------------------------------------------------------------- | ---------- | +| `create_symbol` | Create custom .kicad_sym symbol (pins, rectangles, polylines) | Additional | +| `delete_symbol` | Remove symbol from library | Additional | +| `list_symbols_in_library` | List all symbols in a .kicad_sym file | Additional | +| `register_symbol_library` | Register library in sym-lib-table | Additional | --- ## 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 | -| `get_datasheet_url` | Get LCSC datasheet URL for a component | Additional | +| `get_datasheet_url` | Get LCSC datasheet URL for a component | Additional | --- ## JLCPCB Integration (5 tools) -*Source: `src/tools/jlcpcb-api.ts`* +_Source: `src/tools/jlcpcb-api.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `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 | -| `get_jlcpcb_part` | Get detailed part info with pricing | Additional | -| `get_jlcpcb_database_stats` | Get database statistics | Additional | -| `suggest_jlcpcb_alternatives` | Find cheaper or in-stock alternatives | Additional | +| Tool | Description | Access | +| ----------------------------- | ------------------------------------------------------- | ---------- | +| `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 | +| `get_jlcpcb_part` | Get detailed part info with pricing | Additional | +| `get_jlcpcb_database_stats` | Get database statistics | Additional | +| `suggest_jlcpcb_alternatives` | Find cheaper or in-stock alternatives | Additional | --- ## Freerouting Autorouter (4 tools) -*Source: `src/tools/freerouting.ts`* +_Source: `src/tools/freerouting.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `autoroute` | Run Freerouting autorouter (export DSN, route, import SES) | Routed (autoroute) | -| `export_dsn` | Export Specctra DSN file for manual routing | Routed (autoroute) | -| `import_ses` | Import routed SES file back into PCB | Routed (autoroute) | -| `check_freerouting` | Check Java and Freerouting JAR availability | Routed (autoroute) | +| Tool | Description | Access | +| ------------------- | ---------------------------------------------------------- | ------------------ | +| `autoroute` | Run Freerouting autorouter (export DSN, route, import SES) | Routed (autoroute) | +| `export_dsn` | Export Specctra DSN file for manual routing | Routed (autoroute) | +| `import_ses` | Import routed SES file back into PCB | Routed (autoroute) | +| `check_freerouting` | Check Java and Freerouting JAR availability | Routed (autoroute) | --- ## UI Management (2 tools) -*Source: `src/tools/ui.ts`* +_Source: `src/tools/ui.ts`_ -| Tool | Description | Access | -|------|-------------|--------| -| `check_kicad_ui` | Check if KiCAD UI is running | Direct | +| Tool | Description | Access | +| ----------------- | ----------------------------------------- | -------------- | +| `check_kicad_ui` | Check if KiCAD UI is running | Direct | | `launch_kicad_ui` | Launch KiCAD UI (optionally with project) | Routed (board) | --- ## Router Tools (4 tools) -*Source: `src/tools/router.ts`* +_Source: `src/tools/router.ts`_ These meta-tools provide discovery and execution of routed tools: -| Tool | Description | -|------|-------------| +| Tool | Description | +| ---------------------- | ------------------------------------ | | `list_tool_categories` | Browse all available tool categories | -| `get_category_tools` | View tools in a specific category | -| `search_tools` | Find tools by keyword | -| `execute_tool` | Run any routed tool with parameters | +| `get_category_tools` | View tools in a specific category | +| `search_tools` | Find tools by keyword | +| `execute_tool` | Run any routed tool with parameters | --- ## Summary by Access Type -| Access Type | Count | Description | -|-------------|-------|-------------| -| Direct | 18 | Always visible, no router needed | -| Routed | 65 | Discovered via router, invoked via `execute_tool` | -| Router | 4 | Meta-tools for discovering and running routed tools | -| Additional | 35 | Always visible, registered directly | -| **Total** | **122** | | +| Access Type | Count | Description | +| ----------- | ------- | --------------------------------------------------- | +| Direct | 18 | Always visible, no router needed | +| Routed | 65 | Discovered via router, invoked via `execute_tool` | +| Router | 4 | Meta-tools for discovering and running routed tools | +| Additional | 35 | Always visible, registered directly | +| **Total** | **122** | | ## Summary by Category -| Category | Tool Count | -|----------|------------| -| Project Management | 5 | -| Board Management | 12 | -| Component Management | 16 | -| Routing | 13 | -| Design Rules / DRC | 8 | -| Export | 8 | -| Schematic | 27 | -| Footprint Libraries | 4 | -| Symbol Libraries | 4 | -| Footprint Creator | 4 | -| Symbol Creator | 4 | -| Datasheet | 2 | -| JLCPCB Integration | 5 | -| Freerouting | 4 | -| UI Management | 2 | -| Router | 4 | -| **Total** | **122** | +| Category | Tool Count | +| -------------------- | ---------- | +| Project Management | 5 | +| Board Management | 12 | +| Component Management | 16 | +| Routing | 13 | +| Design Rules / DRC | 8 | +| Export | 8 | +| Schematic | 27 | +| Footprint Libraries | 4 | +| Symbol Libraries | 4 | +| Footprint Creator | 4 | +| Symbol Creator | 4 | +| Datasheet | 2 | +| JLCPCB Integration | 5 | +| Freerouting | 4 | +| UI Management | 2 | +| Router | 4 | +| **Total** | **122** | ## Token Impact diff --git a/docs/UI_AUTO_LAUNCH.md b/docs/UI_AUTO_LAUNCH.md index 8e4ecee..05f2315 100644 --- a/docs/UI_AUTO_LAUNCH.md +++ b/docs/UI_AUTO_LAUNCH.md @@ -1,399 +1,425 @@ -# KiCAD UI Auto-Launch Feature - -Automatically detect and launch KiCAD UI when needed, providing seamless visual feedback for PCB design operations. - ---- - -## 🎯 Overview - -The KiCAD MCP server can now: -- ✅ Detect if KiCAD UI is running -- ✅ Launch KiCAD automatically when needed -- ✅ Open projects directly in the UI -- ✅ Work across Linux, macOS, and Windows - ---- - -## 🚀 Quick Start - -### Enable Auto-Launch - -Add to your MCP configuration: - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], - "env": { - "KICAD_AUTO_LAUNCH": "true" - } - } - } -} -``` - -### Manual Control (Default) - -Without `KICAD_AUTO_LAUNCH=true`, you manually control when KiCAD launches using the new MCP tools. - ---- - -## 🛠️ New MCP Tools - -### 1. `check_kicad_ui` - -Check if KiCAD is currently running. - -**Parameters:** None - -**Example:** -```typescript -{ - "command": "check_kicad_ui", - "params": {} -} -``` - -**Response:** -```json -{ - "success": true, - "running": true, - "processes": [ - { - "pid": "12345", - "name": "pcbnew", - "command": "/usr/bin/pcbnew /tmp/project.kicad_pcb" - } - ], - "message": "KiCAD is running" -} -``` - -### 2. `launch_kicad_ui` - -Launch KiCAD UI, optionally with a project file. - -**Parameters:** -- `projectPath` (optional): Path to `.kicad_pcb` file to open -- `autoLaunch` (optional): Whether to launch if not running (default: true) - -**Example:** -```typescript -{ - "command": "launch_kicad_ui", - "params": { - "projectPath": "/tmp/mcp_demo/New_Project.kicad_pcb" - } -} -``` - -**Response:** -```json -{ - "success": true, - "running": true, - "launched": true, - "message": "KiCAD launched successfully", - "project": "/tmp/mcp_demo/New_Project.kicad_pcb", - "processes": [...] -} -``` - ---- - -## 🔄 Workflow Examples - -### Example 1: Manual Launch - -``` -User: "Check if KiCAD is running" -Claude: Uses check_kicad_ui → "KiCAD is not running" - -User: "Launch it with the demo project" -Claude: Uses launch_kicad_ui → KiCAD opens with project loaded! -``` - -### Example 2: Auto-Launch Mode - -With `KICAD_AUTO_LAUNCH=true`: - -``` -User: "Create a new Arduino shield PCB" -Claude: - 1. Creates project - 2. Detects KiCAD not running - 3. Automatically launches KiCAD with the new project - 4. You see the board in real-time as it's designed! -``` - -### Example 3: Side-by-Side Design - -``` -┌────────────────────────────────────────────────────────┐ -│ Workflow: AI-Assisted PCB Design │ -├────────────────────────────────────────────────────────┤ -│ │ -│ 1. User: "Create a 100mm square board" │ -│ → Claude creates project │ -│ → KiCAD auto-launches if not running │ -│ │ -│ 2. User: "Add 4 mounting holes at corners" │ -│ → Claude adds holes │ -│ → KiCAD detects file change, prompts to reload │ -│ → User clicks "Yes" → sees holes appear! │ -│ │ -│ 3. User: "Perfect! Now add a circular outline..." │ -│ → Iterative design continues... │ -│ │ -└────────────────────────────────────────────────────────┘ -``` - ---- - -## ⚙️ Configuration Options - -### Environment Variables - -| Variable | Default | Description | -|----------|---------|-------------| -| `KICAD_AUTO_LAUNCH` | `false` | Auto-launch KiCAD when needed | -| `KICAD_EXECUTABLE` | auto-detect | Override KiCAD executable path | - -### Custom Executable Path - -If KiCAD is installed in a non-standard location: - -```json -{ - "env": { - "KICAD_AUTO_LAUNCH": "true", - "KICAD_EXECUTABLE": "/opt/kicad/bin/pcbnew" - } -} -``` - ---- - -## 🔍 How It Works - -### Process Detection - -**Linux:** -```bash -pgrep -f "pcbnew|kicad" -``` - -**macOS:** -```bash -pgrep -f "KiCad|pcbnew" -``` - -**Windows:** -```powershell -tasklist /FI "IMAGENAME eq pcbnew.exe" -``` - -### Auto-Discovery of Executable - -The system searches for KiCAD in: - -**Linux:** -- `/usr/bin/pcbnew` -- `/usr/local/bin/pcbnew` -- `/usr/bin/kicad` - -**macOS:** -- `/Applications/KiCad/KiCad.app/Contents/MacOS/kicad` -- `/Applications/KiCad/pcbnew.app/Contents/MacOS/pcbnew` - -**Windows:** -- `C:/Program Files/KiCad/9.0/bin/pcbnew.exe` -- `C:/Program Files/KiCad/8.0/bin/pcbnew.exe` - -### Launch Process - -1. Check if KiCAD is already running -2. If not, find executable path -3. Spawn process with optional project path -4. Wait up to 5 seconds for process to start -5. Verify process is running -6. Return status to MCP client - ---- - -## 💡 Use Cases - -### 1. Beginner-Friendly Workflow - -User doesn't need to know how to launch KiCAD manually: -``` -User: "Help me design a simple LED board" -Claude: [Auto-launches KiCAD, creates project, designs board] -``` - -### 2. Streamlined Iteration - -For rapid prototyping with visual feedback: -``` -1. Claude creates board → KiCAD opens -2. User sees board, requests changes -3. Claude modifies → KiCAD reloads -4. Repeat until satisfied -``` - -### 3. Batch Processing - -Process multiple designs without manual intervention: -```python -for design in designs: - create_project(design) - # KiCAD auto-launches and loads each one - add_components(design) - route_board(design) - export_gerbers(design) -``` - ---- - -## 🐛 Troubleshooting - -### KiCAD Doesn't Launch - -**Check executable path:** -```bash -# Linux/macOS -which pcbnew - -# Windows -where pcbnew.exe -``` - -**Override if needed:** -```json -{ - "env": { - "KICAD_EXECUTABLE": "/path/to/pcbnew" - } -} -``` - -### Process Detection Fails - -**Manual check:** -```bash -# Linux/macOS -ps aux | grep kicad - -# Windows -tasklist | findstr kicad -``` - -**Verify permissions:** -- Ensure user can execute `pgrep` (Linux/macOS) -- Ensure user can execute `tasklist` (Windows) - -### Auto-Launch Doesn't Work - -1. Check `KICAD_AUTO_LAUNCH` is set to `"true"` (string, not boolean) -2. Verify KiCAD is in PATH or set `KICAD_EXECUTABLE` -3. Check MCP server logs for errors -4. Try manual launch first: `launch_kicad_ui` - ---- - -## 📊 Implementation Details - -### Files Modified/Created - -**New Files:** -- `python/utils/kicad_process.py` - Process management utilities -- `src/tools/ui.ts` - MCP tool definitions -- `docs/UI_AUTO_LAUNCH.md` - This documentation - -**Modified Files:** -- `python/kicad_interface.py` - Added UI command handlers -- `src/server.ts` - Registered UI tools - -### API Reference - -**Python:** -```python -from utils.kicad_process import KiCADProcessManager, check_and_launch_kicad - -# Check if running -manager = KiCADProcessManager() -is_running = manager.is_running() - -# Launch KiCAD -success = manager.launch(project_path="/path/to/file.kicad_pcb") - -# Get process info -processes = manager.get_process_info() - -# High-level helper -result = check_and_launch_kicad( - project_path=Path("/path/to/file.kicad_pcb"), - auto_launch=True -) -``` - -**MCP Tools:** -```typescript -// Check status -await callKicadScript("check_kicad_ui", {}); - -// Launch -await callKicadScript("launch_kicad_ui", { - projectPath: "/path/to/project.kicad_pcb", - autoLaunch: true -}); -``` - ---- - -## 🔮 Future Enhancements - -### Planned Features - -- **Window Management:** Bring KiCAD to front, minimize/maximize -- **Multi-Instance:** Handle multiple KiCAD instances -- **IPC Integration:** Seamless integration with IPC backend -- **Status Notifications:** Push notifications when KiCAD state changes -- **Auto-Close:** Option to close KiCAD after operations complete - -### IPC Mode (Coming Weeks 2-3) - -When IPC backend is fully implemented: -``` -KiCAD runs in background → MCP connects via IPC → Real-time updates -No file reloading needed! Changes appear instantly. -``` - ---- - -## 📝 Summary - -**Before this feature:** -``` -User manually launches KiCAD -User manually opens project -Claude makes changes -User manually reloads -``` - -**After this feature:** -``` -User: "Design a board" -→ KiCAD auto-launches with project -→ Changes appear (with quick reload) -→ Seamless AI-assisted design! -``` - ---- - -**Last Updated:** 2025-10-26 -**Version:** 2.0.0-alpha.1 -**Status:** ✅ Production Ready +# KiCAD UI Auto-Launch Feature + +Automatically detect and launch KiCAD UI when needed, providing seamless visual feedback for PCB design operations. + +--- + +## 🎯 Overview + +The KiCAD MCP server can now: + +- ✅ Detect if KiCAD UI is running +- ✅ Launch KiCAD automatically when needed +- ✅ Open projects directly in the UI +- ✅ Work across Linux, macOS, and Windows + +--- + +## 🚀 Quick Start + +### Enable Auto-Launch + +Add to your MCP configuration: + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["/path/to/KiCAD-MCP-Server/dist/index.js"], + "env": { + "KICAD_AUTO_LAUNCH": "true" + } + } + } +} +``` + +### Manual Control (Default) + +Without `KICAD_AUTO_LAUNCH=true`, you manually control when KiCAD launches using the new MCP tools. + +--- + +## 🛠️ New MCP Tools + +### 1. `check_kicad_ui` + +Check if KiCAD is currently running. + +**Parameters:** None + +**Example:** + +```typescript +{ + "command": "check_kicad_ui", + "params": {} +} +``` + +**Response:** + +```json +{ + "success": true, + "running": true, + "processes": [ + { + "pid": "12345", + "name": "pcbnew", + "command": "/usr/bin/pcbnew /tmp/project.kicad_pcb" + } + ], + "message": "KiCAD is running" +} +``` + +### 2. `launch_kicad_ui` + +Launch KiCAD UI, optionally with a project file. + +**Parameters:** + +- `projectPath` (optional): Path to `.kicad_pcb` file to open +- `autoLaunch` (optional): Whether to launch if not running (default: true) + +**Example:** + +```typescript +{ + "command": "launch_kicad_ui", + "params": { + "projectPath": "/tmp/mcp_demo/New_Project.kicad_pcb" + } +} +``` + +**Response:** + +```json +{ + "success": true, + "running": true, + "launched": true, + "message": "KiCAD launched successfully", + "project": "/tmp/mcp_demo/New_Project.kicad_pcb", + "processes": [...] +} +``` + +--- + +## 🔄 Workflow Examples + +### Example 1: Manual Launch + +``` +User: "Check if KiCAD is running" +Claude: Uses check_kicad_ui → "KiCAD is not running" + +User: "Launch it with the demo project" +Claude: Uses launch_kicad_ui → KiCAD opens with project loaded! +``` + +### Example 2: Auto-Launch Mode + +With `KICAD_AUTO_LAUNCH=true`: + +``` +User: "Create a new Arduino shield PCB" +Claude: + 1. Creates project + 2. Detects KiCAD not running + 3. Automatically launches KiCAD with the new project + 4. You see the board in real-time as it's designed! +``` + +### Example 3: Side-by-Side Design + +``` +┌────────────────────────────────────────────────────────┐ +│ Workflow: AI-Assisted PCB Design │ +├────────────────────────────────────────────────────────┤ +│ │ +│ 1. User: "Create a 100mm square board" │ +│ → Claude creates project │ +│ → KiCAD auto-launches if not running │ +│ │ +│ 2. User: "Add 4 mounting holes at corners" │ +│ → Claude adds holes │ +│ → KiCAD detects file change, prompts to reload │ +│ → User clicks "Yes" → sees holes appear! │ +│ │ +│ 3. User: "Perfect! Now add a circular outline..." │ +│ → Iterative design continues... │ +│ │ +└────────────────────────────────────────────────────────┘ +``` + +--- + +## ⚙️ Configuration Options + +### Environment Variables + +| Variable | Default | Description | +| ------------------- | ----------- | ------------------------------ | +| `KICAD_AUTO_LAUNCH` | `false` | Auto-launch KiCAD when needed | +| `KICAD_EXECUTABLE` | auto-detect | Override KiCAD executable path | + +### Custom Executable Path + +If KiCAD is installed in a non-standard location: + +```json +{ + "env": { + "KICAD_AUTO_LAUNCH": "true", + "KICAD_EXECUTABLE": "/opt/kicad/bin/pcbnew" + } +} +``` + +--- + +## 🔍 How It Works + +### Process Detection + +**Linux:** + +```bash +pgrep -f "pcbnew|kicad" +``` + +**macOS:** + +```bash +pgrep -f "KiCad|pcbnew" +``` + +**Windows:** + +```powershell +tasklist /FI "IMAGENAME eq pcbnew.exe" +``` + +### Auto-Discovery of Executable + +The system searches for KiCAD in: + +**Linux:** + +- `/usr/bin/pcbnew` +- `/usr/local/bin/pcbnew` +- `/usr/bin/kicad` + +**macOS:** + +- `/Applications/KiCad/KiCad.app/Contents/MacOS/kicad` +- `/Applications/KiCad/pcbnew.app/Contents/MacOS/pcbnew` + +**Windows:** + +- `C:/Program Files/KiCad/9.0/bin/pcbnew.exe` +- `C:/Program Files/KiCad/8.0/bin/pcbnew.exe` + +### Launch Process + +1. Check if KiCAD is already running +2. If not, find executable path +3. Spawn process with optional project path +4. Wait up to 5 seconds for process to start +5. Verify process is running +6. Return status to MCP client + +--- + +## 💡 Use Cases + +### 1. Beginner-Friendly Workflow + +User doesn't need to know how to launch KiCAD manually: + +``` +User: "Help me design a simple LED board" +Claude: [Auto-launches KiCAD, creates project, designs board] +``` + +### 2. Streamlined Iteration + +For rapid prototyping with visual feedback: + +``` +1. Claude creates board → KiCAD opens +2. User sees board, requests changes +3. Claude modifies → KiCAD reloads +4. Repeat until satisfied +``` + +### 3. Batch Processing + +Process multiple designs without manual intervention: + +```python +for design in designs: + create_project(design) + # KiCAD auto-launches and loads each one + add_components(design) + route_board(design) + export_gerbers(design) +``` + +--- + +## 🐛 Troubleshooting + +### KiCAD Doesn't Launch + +**Check executable path:** + +```bash +# Linux/macOS +which pcbnew + +# Windows +where pcbnew.exe +``` + +**Override if needed:** + +```json +{ + "env": { + "KICAD_EXECUTABLE": "/path/to/pcbnew" + } +} +``` + +### Process Detection Fails + +**Manual check:** + +```bash +# Linux/macOS +ps aux | grep kicad + +# Windows +tasklist | findstr kicad +``` + +**Verify permissions:** + +- Ensure user can execute `pgrep` (Linux/macOS) +- Ensure user can execute `tasklist` (Windows) + +### Auto-Launch Doesn't Work + +1. Check `KICAD_AUTO_LAUNCH` is set to `"true"` (string, not boolean) +2. Verify KiCAD is in PATH or set `KICAD_EXECUTABLE` +3. Check MCP server logs for errors +4. Try manual launch first: `launch_kicad_ui` + +--- + +## 📊 Implementation Details + +### Files Modified/Created + +**New Files:** + +- `python/utils/kicad_process.py` - Process management utilities +- `src/tools/ui.ts` - MCP tool definitions +- `docs/UI_AUTO_LAUNCH.md` - This documentation + +**Modified Files:** + +- `python/kicad_interface.py` - Added UI command handlers +- `src/server.ts` - Registered UI tools + +### API Reference + +**Python:** + +```python +from utils.kicad_process import KiCADProcessManager, check_and_launch_kicad + +# Check if running +manager = KiCADProcessManager() +is_running = manager.is_running() + +# Launch KiCAD +success = manager.launch(project_path="/path/to/file.kicad_pcb") + +# Get process info +processes = manager.get_process_info() + +# High-level helper +result = check_and_launch_kicad( + project_path=Path("/path/to/file.kicad_pcb"), + auto_launch=True +) +``` + +**MCP Tools:** + +```typescript +// Check status +await callKicadScript("check_kicad_ui", {}); + +// Launch +await callKicadScript("launch_kicad_ui", { + projectPath: "/path/to/project.kicad_pcb", + autoLaunch: true, +}); +``` + +--- + +## 🔮 Future Enhancements + +### Planned Features + +- **Window Management:** Bring KiCAD to front, minimize/maximize +- **Multi-Instance:** Handle multiple KiCAD instances +- **IPC Integration:** Seamless integration with IPC backend +- **Status Notifications:** Push notifications when KiCAD state changes +- **Auto-Close:** Option to close KiCAD after operations complete + +### IPC Mode (Coming Weeks 2-3) + +When IPC backend is fully implemented: + +``` +KiCAD runs in background → MCP connects via IPC → Real-time updates +No file reloading needed! Changes appear instantly. +``` + +--- + +## 📝 Summary + +**Before this feature:** + +``` +User manually launches KiCAD +User manually opens project +Claude makes changes +User manually reloads +``` + +**After this feature:** + +``` +User: "Design a board" +→ KiCAD auto-launches with project +→ Changes appear (with quick reload) +→ Seamless AI-assisted design! +``` + +--- + +**Last Updated:** 2025-10-26 +**Version:** 2.0.0-alpha.1 +**Status:** ✅ Production Ready diff --git a/docs/VISUAL_FEEDBACK.md b/docs/VISUAL_FEEDBACK.md index 9c75ef6..92d7612 100644 --- a/docs/VISUAL_FEEDBACK.md +++ b/docs/VISUAL_FEEDBACK.md @@ -1,184 +1,193 @@ -# Visual Feedback: Seeing MCP Changes in KiCAD UI - -This document explains how to see changes made by the MCP server in the KiCAD UI in real-time or near-real-time. - -## Current Status (Week 1 - SWIG Backend) - -**Active Backend:** SWIG (legacy pcbnew Python API) -**Real-time Updates:** Not available yet -**IPC Backend:** Skeleton implemented, operations coming in Weeks 2-3 - ---- - -## 🎯 Best Current Workflow (SWIG + Manual Reload) - -### Setup - -1. **Open your project in KiCAD PCB Editor** - ```bash - pcbnew /tmp/kicad_test_project/New_Project.kicad_pcb - ``` - -2. **Make changes via MCP** (Claude Code, Claude Desktop, etc.) - - Example: Add board outline, mounting holes, etc. - - Each operation saves the file automatically - -3. **Reload in KiCAD UI** - - **Option A (Automatic):** KiCAD 8.0+ detects file changes and shows a reload prompt - - **Option B (Manual):** File → Revert to reload from disk - - **Keyboard shortcut:** None by default (but you can assign one) - -### Workflow Example - -``` -┌─────────────────────────────────────────────────────────┐ -│ Terminal: Claude Code │ -├─────────────────────────────────────────────────────────┤ -│ You: "Create a 100x80mm board with 4 mounting holes" │ -│ │ -│ Claude: ✓ Added board outline (100x80mm) │ -│ ✓ Added mounting hole at (5,5) │ -│ ✓ Added mounting hole at (95,5) │ -│ ✓ Added mounting hole at (95,75) │ -│ ✓ Added mounting hole at (5,75) │ -│ ✓ Saved project │ -└─────────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────────┐ -│ KiCAD PCB Editor │ -├─────────────────────────────────────────────────────────┤ -│ [Reload prompt appears] │ -│ "File has been modified. Reload?" │ -│ │ -│ Click "Yes" → Changes appear instantly! 🎉 │ -└─────────────────────────────────────────────────────────┘ -``` - ---- - -## 🔮 Future: IPC Backend (Weeks 2-3) - -When fully implemented, the IPC backend will provide **true real-time updates**: - -### How It Will Work - -``` -Claude MCP → IPC Socket → Running KiCAD → Instant UI Update -``` - -**No file reloading required** - changes appear as you make them! - -### IPC Setup (When Available) - -1. **Enable IPC in KiCAD** - - Preferences → Advanced Preferences - - Search for "IPC" - - Enable: "Enable IPC API Server" - - Restart KiCAD - -2. **Install kicad-python** (Already installed ✓) - ```bash - pip install kicad-python - ``` - -3. **Configure MCP Server** - Add to your MCP config: - ```json - { - "env": { - "KICAD_BACKEND": "ipc" - } - } - ``` - -4. **Start KiCAD first, then use MCP** - - Changes will appear in real-time - - No manual reloading needed - -### Current IPC Status - -| Feature | Status | -|---------|--------| -| Connection to KiCAD | ✅ Working | -| Version checking | ✅ Working | -| Project operations | ⏳ Week 2-3 | -| Board operations | ⏳ Week 2-3 | -| Component operations | ⏳ Week 2-3 | -| Routing operations | ⏳ Week 2-3 | - ---- - -## 🛠️ Monitoring Helper (Optional) - -A helper script is available to monitor file changes: - -```bash -# Watch for changes and notify -./scripts/auto_refresh_kicad.sh /tmp/kicad_test_project/New_Project.kicad_pcb -``` - -This will print a message each time the MCP server saves changes. - ---- - -## 💡 Tips for Best Experience - -### 1. Side-by-Side Windows -``` -┌──────────────────┬──────────────────┐ -│ Claude Code │ KiCAD PCB │ -│ (Terminal) │ Editor │ -│ │ │ -│ Making changes │ Viewing results │ -└──────────────────┴──────────────────┘ -``` - -### 2. Quick Reload Workflow -- Keep KiCAD focused in one window -- Make changes via Claude in another -- Press Alt+Tab → Click "Reload" → See changes -- Repeat - -### 3. Save Frequently -The MCP server auto-saves after each operation, so changes are immediately available for reload. - -### 4. Verify Before Complex Operations -For complex changes (multiple components, routing, etc.): -1. Make the change -2. Reload in KiCAD -3. Verify it looks correct -4. Proceed with next change - ---- - -## 🔍 Troubleshooting - -### KiCAD Doesn't Detect File Changes - -**Cause:** Some KiCAD versions or configurations don't auto-detect -**Solution:** Use File → Revert manually - -### Changes Don't Appear After Reload - -**Cause:** MCP operation may have failed -**Solution:** Check the MCP response for success: true - -### File is Locked - -**Cause:** KiCAD has the file open exclusively -**Solution:** -- KiCAD should allow external modifications -- If not, close the file in KiCAD, let MCP make changes, then reopen - ---- - -## 📅 Roadmap - -**Current (Week 1):** SWIG backend with manual reload -**Week 2-3:** IPC backend implementation -**Week 4+:** Real-time collaboration features - ---- - -**Last Updated:** 2025-10-26 -**Version:** 2.0.0-alpha.1 +# Visual Feedback: Seeing MCP Changes in KiCAD UI + +This document explains how to see changes made by the MCP server in the KiCAD UI in real-time or near-real-time. + +## Current Status (Week 1 - SWIG Backend) + +**Active Backend:** SWIG (legacy pcbnew Python API) +**Real-time Updates:** Not available yet +**IPC Backend:** Skeleton implemented, operations coming in Weeks 2-3 + +--- + +## 🎯 Best Current Workflow (SWIG + Manual Reload) + +### Setup + +1. **Open your project in KiCAD PCB Editor** + + ```bash + pcbnew /tmp/kicad_test_project/New_Project.kicad_pcb + ``` + +2. **Make changes via MCP** (Claude Code, Claude Desktop, etc.) + - Example: Add board outline, mounting holes, etc. + - Each operation saves the file automatically + +3. **Reload in KiCAD UI** + - **Option A (Automatic):** KiCAD 8.0+ detects file changes and shows a reload prompt + - **Option B (Manual):** File → Revert to reload from disk + - **Keyboard shortcut:** None by default (but you can assign one) + +### Workflow Example + +``` +┌─────────────────────────────────────────────────────────┐ +│ Terminal: Claude Code │ +├─────────────────────────────────────────────────────────┤ +│ You: "Create a 100x80mm board with 4 mounting holes" │ +│ │ +│ Claude: ✓ Added board outline (100x80mm) │ +│ ✓ Added mounting hole at (5,5) │ +│ ✓ Added mounting hole at (95,5) │ +│ ✓ Added mounting hole at (95,75) │ +│ ✓ Added mounting hole at (5,75) │ +│ ✓ Saved project │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ KiCAD PCB Editor │ +├─────────────────────────────────────────────────────────┤ +│ [Reload prompt appears] │ +│ "File has been modified. Reload?" │ +│ │ +│ Click "Yes" → Changes appear instantly! 🎉 │ +└─────────────────────────────────────────────────────────┘ +``` + +--- + +## 🔮 Future: IPC Backend (Weeks 2-3) + +When fully implemented, the IPC backend will provide **true real-time updates**: + +### How It Will Work + +``` +Claude MCP → IPC Socket → Running KiCAD → Instant UI Update +``` + +**No file reloading required** - changes appear as you make them! + +### IPC Setup (When Available) + +1. **Enable IPC in KiCAD** + - Preferences → Advanced Preferences + - Search for "IPC" + - Enable: "Enable IPC API Server" + - Restart KiCAD + +2. **Install kicad-python** (Already installed ✓) + + ```bash + pip install kicad-python + ``` + +3. **Configure MCP Server** + Add to your MCP config: + + ```json + { + "env": { + "KICAD_BACKEND": "ipc" + } + } + ``` + +4. **Start KiCAD first, then use MCP** + - Changes will appear in real-time + - No manual reloading needed + +### Current IPC Status + +| Feature | Status | +| -------------------- | ----------- | +| Connection to KiCAD | ✅ Working | +| Version checking | ✅ Working | +| Project operations | ⏳ Week 2-3 | +| Board operations | ⏳ Week 2-3 | +| Component operations | ⏳ Week 2-3 | +| Routing operations | ⏳ Week 2-3 | + +--- + +## 🛠️ Monitoring Helper (Optional) + +A helper script is available to monitor file changes: + +```bash +# Watch for changes and notify +./scripts/auto_refresh_kicad.sh /tmp/kicad_test_project/New_Project.kicad_pcb +``` + +This will print a message each time the MCP server saves changes. + +--- + +## 💡 Tips for Best Experience + +### 1. Side-by-Side Windows + +``` +┌──────────────────┬──────────────────┐ +│ Claude Code │ KiCAD PCB │ +│ (Terminal) │ Editor │ +│ │ │ +│ Making changes │ Viewing results │ +└──────────────────┴──────────────────┘ +``` + +### 2. Quick Reload Workflow + +- Keep KiCAD focused in one window +- Make changes via Claude in another +- Press Alt+Tab → Click "Reload" → See changes +- Repeat + +### 3. Save Frequently + +The MCP server auto-saves after each operation, so changes are immediately available for reload. + +### 4. Verify Before Complex Operations + +For complex changes (multiple components, routing, etc.): + +1. Make the change +2. Reload in KiCAD +3. Verify it looks correct +4. Proceed with next change + +--- + +## 🔍 Troubleshooting + +### KiCAD Doesn't Detect File Changes + +**Cause:** Some KiCAD versions or configurations don't auto-detect +**Solution:** Use File → Revert manually + +### Changes Don't Appear After Reload + +**Cause:** MCP operation may have failed +**Solution:** Check the MCP response for success: true + +### File is Locked + +**Cause:** KiCAD has the file open exclusively +**Solution:** + +- KiCAD should allow external modifications +- If not, close the file in KiCAD, let MCP make changes, then reopen + +--- + +## 📅 Roadmap + +**Current (Week 1):** SWIG backend with manual reload +**Week 2-3:** IPC backend implementation +**Week 4+:** Real-time collaboration features + +--- + +**Last Updated:** 2025-10-26 +**Version:** 2.0.0-alpha.1 diff --git a/docs/WINDOWS_TROUBLESHOOTING.md b/docs/WINDOWS_TROUBLESHOOTING.md index 1a36548..a4b9f0b 100644 --- a/docs/WINDOWS_TROUBLESHOOTING.md +++ b/docs/WINDOWS_TROUBLESHOOTING.md @@ -1,475 +1,493 @@ -# Windows Troubleshooting Guide - -This guide helps diagnose and fix common issues when setting up KiCAD MCP Server on Windows. - -## Quick Start: Automated Setup - -**Before manually troubleshooting, try the automated setup script:** - -```powershell -# Open PowerShell in the KiCAD-MCP-Server directory -.\setup-windows.ps1 -``` - -This script will: -- Detect your KiCAD installation -- Verify all prerequisites -- Install dependencies -- Build the project -- Generate configuration -- Run diagnostic tests - -If the automated setup fails, continue with the manual troubleshooting below. - ---- - -## Common Issues and Solutions - -### Issue 1: Server Exits Immediately (Most Common) - -**Symptom:** Claude Desktop logs show "Server transport closed unexpectedly" - -**Cause:** Python process crashes during startup, usually due to missing pcbnew module - -**Solution:** - -1. **Check the log file** (this has the actual error): - ``` - %USERPROFILE%\.kicad-mcp\logs\kicad_interface.log - ``` - Open in Notepad and look at the last 50-100 lines. - -2. **Test pcbnew import manually:** - ```powershell - & "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew; print(pcbnew.GetBuildVersion())" - ``` - - **Expected:** Prints KiCAD version like `9.0.0` - - **If it fails:** - - KiCAD's Python module isn't installed - - Reinstall KiCAD with default options - - Make sure "Install Python" is checked during installation - -3. **Verify PYTHONPATH in your config:** - ```json - { - "mcpServers": { - "kicad": { - "env": { - "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" - } - } - } - } - ``` - ---- - -### Issue 2: KiCAD Not Found - -**Symptom:** Log shows "No KiCAD installations found" - -**Solution:** - -1. **Check if KiCAD is installed:** - ```powershell - Test-Path "C:\Program Files\KiCad\9.0" - ``` - -2. **If KiCAD is installed elsewhere:** - - Find your KiCAD installation directory - - Update PYTHONPATH in config to match your installation - - Example for version 8.0: - ``` - "PYTHONPATH": "C:\\Program Files\\KiCad\\8.0\\lib\\python3\\dist-packages" - ``` - -3. **If KiCAD is not installed:** - - Download from https://www.kicad.org/download/windows/ - - Install version 9.0 or higher - - Use default installation path - ---- - -### Issue 3: Node.js Not Found - -**Symptom:** Cannot run `npm install` or `npm run build` - -**Solution:** - -1. **Check if Node.js is installed:** - ```powershell - node --version - npm --version - ``` - -2. **If not installed:** - - Download Node.js 18+ from https://nodejs.org/ - - Install with default options - - Restart PowerShell after installation - -3. **If installed but not in PATH:** - ```powershell - # Add to PATH temporarily - $env:PATH += ";C:\Program Files\nodejs" - ``` - ---- - -### Issue 4: Build Fails with TypeScript Errors - -**Symptom:** `npm run build` shows TypeScript compilation errors - -**Solution:** - -1. **Clean and reinstall dependencies:** - ```powershell - Remove-Item node_modules -Recurse -Force - Remove-Item package-lock.json -Force - npm install - npm run build - ``` - -2. **Check Node.js version:** - ```powershell - node --version # Should be v18.0.0 or higher - ``` - -3. **If still failing:** - ```powershell - # Try with legacy peer deps - npm install --legacy-peer-deps - npm run build - ``` - ---- - -### Issue 5: Python Dependencies Missing - -**Symptom:** Log shows errors about missing Python packages (Pillow, cairosvg, etc.) - -**Solution:** - -1. **Install with KiCAD's Python:** - ```powershell - & "C:\Program Files\KiCad\9.0\bin\python.exe" -m pip install -r requirements.txt - ``` - -2. **If pip is not available:** - ```powershell - # Download get-pip.py - Invoke-WebRequest -Uri https://bootstrap.pypa.io/get-pip.py -OutFile get-pip.py - - # Install pip - & "C:\Program Files\KiCad\9.0\bin\python.exe" get-pip.py - - # Then install requirements - & "C:\Program Files\KiCad\9.0\bin\python.exe" -m pip install -r requirements.txt - ``` - ---- - -### Issue 6: Permission Denied Errors - -**Symptom:** Cannot write to Program Files or access certain directories - -**Solution:** - -1. **Run PowerShell as Administrator:** - - Right-click PowerShell icon - - Select "Run as Administrator" - - Navigate to KiCAD-MCP-Server directory - - Run setup again - -2. **Or clone to user directory:** - ```powershell - cd $HOME\Documents - git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git - cd KiCAD-MCP-Server - .\setup-windows.ps1 - ``` - ---- - -### Issue 7: Path Issues in Configuration - -**Symptom:** Config file paths not working - -**Common mistakes:** -```json -// ❌ Wrong - single backslashes -"args": ["C:\Users\Name\KiCAD-MCP-Server\dist\index.js"] - -// ❌ Wrong - mixed slashes -"args": ["C:\Users/Name\KiCAD-MCP-Server/dist\index.js"] - -// ✅ Correct - double backslashes -"args": ["C:\\Users\\Name\\KiCAD-MCP-Server\\dist\\index.js"] - -// ✅ Also correct - forward slashes -"args": ["C:/Users/Name/KiCAD-MCP-Server/dist/index.js"] -``` - -**Solution:** Use either double backslashes `\\` or forward slashes `/` consistently. - ---- - -### Issue 8: Wrong Python Version - -**Symptom:** Errors about Python 2.7 or Python 3.6 - -**Solution:** - -KiCAD MCP requires Python 3.10+. KiCAD 9.0 includes Python 3.11, which is perfect. - -**Always use KiCAD's bundled Python:** -```json -{ - "mcpServers": { - "kicad": { - "command": "C:\\Program Files\\KiCad\\9.0\\bin\\python.exe", - "args": ["C:\\Users\\YourName\\KiCAD-MCP-Server\\python\\kicad_interface.py"] - } - } -} -``` - -This bypasses Node.js and runs Python directly. - ---- - -## Configuration Examples - -### For Claude Desktop - -Config location: `%APPDATA%\Claude\claude_desktop_config.json` - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["C:\\Users\\YourName\\KiCAD-MCP-Server\\dist\\index.js"], - "env": { - "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages", - "NODE_ENV": "production", - "LOG_LEVEL": "info" - } - } - } -} -``` - -### For Cline (VSCode) - -Config location: `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json` - -```json -{ - "mcpServers": { - "kicad": { - "command": "node", - "args": ["C:\\Users\\YourName\\KiCAD-MCP-Server\\dist\\index.js"], - "env": { - "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" - }, - "description": "KiCAD PCB Design Assistant" - } - } -} -``` - -### Alternative: Python Direct Mode - -If Node.js issues persist, run Python directly: - -```json -{ - "mcpServers": { - "kicad": { - "command": "C:\\Program Files\\KiCad\\9.0\\bin\\python.exe", - "args": ["C:\\Users\\YourName\\KiCAD-MCP-Server\\python\\kicad_interface.py"], - "env": { - "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" - } - } - } -} -``` - ---- - -## Manual Testing Steps - -### Test 1: Verify KiCAD Python - -```powershell -& "C:\Program Files\KiCad\9.0\bin\python.exe" -c @" -import sys -print(f'Python version: {sys.version}') -import pcbnew -print(f'pcbnew version: {pcbnew.GetBuildVersion()}') -print('SUCCESS!') -"@ -``` - -Expected output: -``` -Python version: 3.11.x ... -pcbnew version: 9.0.0 -SUCCESS! -``` - -### Test 2: Verify Node.js - -```powershell -node --version # Should be v18.0.0+ -npm --version # Should be 9.0.0+ -``` - -### Test 3: Build Project - -```powershell -cd C:\Users\YourName\KiCAD-MCP-Server -npm install -npm run build -Test-Path .\dist\index.js # Should output: True -``` - -### Test 4: Run Server Manually - -```powershell -$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" -node .\dist\index.js -``` - -Expected: Server should start and wait for input (doesn't exit immediately) - -**To stop:** Press Ctrl+C - -### Test 5: Check Log File - -```powershell -# View log file -Get-Content "$env:USERPROFILE\.kicad-mcp\logs\kicad_interface.log" -Tail 50 -``` - -Should show successful initialization with no errors. - ---- - -## Advanced Diagnostics - -### Enable Verbose Logging - -Add to your MCP config: -```json -{ - "env": { - "LOG_LEVEL": "debug", - "PYTHONUNBUFFERED": "1" - } -} -``` - -### Check Python sys.path - -```powershell -& "C:\Program Files\KiCad\9.0\bin\python.exe" -c @" -import sys -for path in sys.path: - print(path) -"@ -``` - -Should include: `C:\Program Files\KiCad\9.0\lib\python3\dist-packages` - -### Test MCP Communication - -```powershell -# Start server -$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" -$process = Start-Process -FilePath "node" -ArgumentList ".\dist\index.js" -NoNewWindow -PassThru - -# Wait 3 seconds -Start-Sleep -Seconds 3 - -# Check if still running -if ($process.HasExited) { - Write-Host "Server crashed!" -ForegroundColor Red - Write-Host "Exit code: $($process.ExitCode)" -} else { - Write-Host "Server is running!" -ForegroundColor Green - Stop-Process -Id $process.Id -} -``` - ---- - -## Getting Help - -If none of the above solutions work: - -1. **Run the diagnostic script:** - ```powershell - .\setup-windows.ps1 - ``` - Copy the entire output. - -2. **Collect log files:** - - MCP log: `%USERPROFILE%\.kicad-mcp\logs\kicad_interface.log` - - Claude Desktop log: `%APPDATA%\Claude\logs\mcp*.log` - -3. **Open a GitHub issue:** - - Go to: https://github.com/mixelpixx/KiCAD-MCP-Server/issues - - Title: "Windows Setup Issue: [brief description]" - - Include: - - Windows version (10 or 11) - - Output from setup script - - Log file contents - - Output from manual tests above - ---- - -## Known Limitations on Windows - -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: - ```powershell - # Enable long paths (requires admin) - 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: - ``` - Settings → Windows Security → Virus & threat protection → Exclusions - Add: C:\Users\YourName\KiCAD-MCP-Server - ``` - -4. **Antivirus software** may block Python/Node processes. Temporarily disable for testing. - ---- - -## Success Checklist - -When everything works, you should have: - -- [ ] KiCAD 9.0+ installed at `C:\Program Files\KiCad\9.0` -- [ ] Node.js 18+ installed and in PATH -- [ ] Python can import pcbnew successfully -- [ ] `npm run build` completes without errors -- [ ] `dist\index.js` file exists -- [ ] MCP config file created with correct paths -- [ ] Server starts without immediate crash -- [ ] Log file shows successful initialization -- [ ] Claude Desktop/Cline recognizes the MCP server -- [ ] Can execute: "Create a new KiCAD project" - ---- - -**Last Updated:** 2025-11-05 -**Maintained by:** KiCAD MCP Team - -For the latest updates, see: https://github.com/mixelpixx/KiCAD-MCP-Server +# Windows Troubleshooting Guide + +This guide helps diagnose and fix common issues when setting up KiCAD MCP Server on Windows. + +## Quick Start: Automated Setup + +**Before manually troubleshooting, try the automated setup script:** + +```powershell +# Open PowerShell in the KiCAD-MCP-Server directory +.\setup-windows.ps1 +``` + +This script will: + +- Detect your KiCAD installation +- Verify all prerequisites +- Install dependencies +- Build the project +- Generate configuration +- Run diagnostic tests + +If the automated setup fails, continue with the manual troubleshooting below. + +--- + +## Common Issues and Solutions + +### Issue 1: Server Exits Immediately (Most Common) + +**Symptom:** Claude Desktop logs show "Server transport closed unexpectedly" + +**Cause:** Python process crashes during startup, usually due to missing pcbnew module + +**Solution:** + +1. **Check the log file** (this has the actual error): + + ``` + %USERPROFILE%\.kicad-mcp\logs\kicad_interface.log + ``` + + Open in Notepad and look at the last 50-100 lines. + +2. **Test pcbnew import manually:** + + ```powershell + & "C:\Program Files\KiCad\9.0\bin\python.exe" -c "import pcbnew; print(pcbnew.GetBuildVersion())" + ``` + + **Expected:** Prints KiCAD version like `9.0.0` + + **If it fails:** + - KiCAD's Python module isn't installed + - Reinstall KiCAD with default options + - Make sure "Install Python" is checked during installation + +3. **Verify PYTHONPATH in your config:** + ```json + { + "mcpServers": { + "kicad": { + "env": { + "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" + } + } + } + } + ``` + +--- + +### Issue 2: KiCAD Not Found + +**Symptom:** Log shows "No KiCAD installations found" + +**Solution:** + +1. **Check if KiCAD is installed:** + + ```powershell + Test-Path "C:\Program Files\KiCad\9.0" + ``` + +2. **If KiCAD is installed elsewhere:** + - Find your KiCAD installation directory + - Update PYTHONPATH in config to match your installation + - Example for version 8.0: + ``` + "PYTHONPATH": "C:\\Program Files\\KiCad\\8.0\\lib\\python3\\dist-packages" + ``` + +3. **If KiCAD is not installed:** + - Download from https://www.kicad.org/download/windows/ + - Install version 9.0 or higher + - Use default installation path + +--- + +### Issue 3: Node.js Not Found + +**Symptom:** Cannot run `npm install` or `npm run build` + +**Solution:** + +1. **Check if Node.js is installed:** + + ```powershell + node --version + npm --version + ``` + +2. **If not installed:** + - Download Node.js 18+ from https://nodejs.org/ + - Install with default options + - Restart PowerShell after installation + +3. **If installed but not in PATH:** + ```powershell + # Add to PATH temporarily + $env:PATH += ";C:\Program Files\nodejs" + ``` + +--- + +### Issue 4: Build Fails with TypeScript Errors + +**Symptom:** `npm run build` shows TypeScript compilation errors + +**Solution:** + +1. **Clean and reinstall dependencies:** + + ```powershell + Remove-Item node_modules -Recurse -Force + Remove-Item package-lock.json -Force + npm install + npm run build + ``` + +2. **Check Node.js version:** + + ```powershell + node --version # Should be v18.0.0 or higher + ``` + +3. **If still failing:** + ```powershell + # Try with legacy peer deps + npm install --legacy-peer-deps + npm run build + ``` + +--- + +### Issue 5: Python Dependencies Missing + +**Symptom:** Log shows errors about missing Python packages (Pillow, cairosvg, etc.) + +**Solution:** + +1. **Install with KiCAD's Python:** + + ```powershell + & "C:\Program Files\KiCad\9.0\bin\python.exe" -m pip install -r requirements.txt + ``` + +2. **If pip is not available:** + + ```powershell + # Download get-pip.py + Invoke-WebRequest -Uri https://bootstrap.pypa.io/get-pip.py -OutFile get-pip.py + + # Install pip + & "C:\Program Files\KiCad\9.0\bin\python.exe" get-pip.py + + # Then install requirements + & "C:\Program Files\KiCad\9.0\bin\python.exe" -m pip install -r requirements.txt + ``` + +--- + +### Issue 6: Permission Denied Errors + +**Symptom:** Cannot write to Program Files or access certain directories + +**Solution:** + +1. **Run PowerShell as Administrator:** + - Right-click PowerShell icon + - Select "Run as Administrator" + - Navigate to KiCAD-MCP-Server directory + - Run setup again + +2. **Or clone to user directory:** + ```powershell + cd $HOME\Documents + git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git + cd KiCAD-MCP-Server + .\setup-windows.ps1 + ``` + +--- + +### Issue 7: Path Issues in Configuration + +**Symptom:** Config file paths not working + +**Common mistakes:** + +```json +// ❌ Wrong - single backslashes +"args": ["C:\Users\Name\KiCAD-MCP-Server\dist\index.js"] + +// ❌ Wrong - mixed slashes +"args": ["C:\Users/Name\KiCAD-MCP-Server/dist\index.js"] + +// ✅ Correct - double backslashes +"args": ["C:\\Users\\Name\\KiCAD-MCP-Server\\dist\\index.js"] + +// ✅ Also correct - forward slashes +"args": ["C:/Users/Name/KiCAD-MCP-Server/dist/index.js"] +``` + +**Solution:** Use either double backslashes `\\` or forward slashes `/` consistently. + +--- + +### Issue 8: Wrong Python Version + +**Symptom:** Errors about Python 2.7 or Python 3.6 + +**Solution:** + +KiCAD MCP requires Python 3.10+. KiCAD 9.0 includes Python 3.11, which is perfect. + +**Always use KiCAD's bundled Python:** + +```json +{ + "mcpServers": { + "kicad": { + "command": "C:\\Program Files\\KiCad\\9.0\\bin\\python.exe", + "args": ["C:\\Users\\YourName\\KiCAD-MCP-Server\\python\\kicad_interface.py"] + } + } +} +``` + +This bypasses Node.js and runs Python directly. + +--- + +## Configuration Examples + +### For Claude Desktop + +Config location: `%APPDATA%\Claude\claude_desktop_config.json` + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["C:\\Users\\YourName\\KiCAD-MCP-Server\\dist\\index.js"], + "env": { + "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages", + "NODE_ENV": "production", + "LOG_LEVEL": "info" + } + } + } +} +``` + +### For Cline (VSCode) + +Config location: `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json` + +```json +{ + "mcpServers": { + "kicad": { + "command": "node", + "args": ["C:\\Users\\YourName\\KiCAD-MCP-Server\\dist\\index.js"], + "env": { + "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" + }, + "description": "KiCAD PCB Design Assistant" + } + } +} +``` + +### Alternative: Python Direct Mode + +If Node.js issues persist, run Python directly: + +```json +{ + "mcpServers": { + "kicad": { + "command": "C:\\Program Files\\KiCad\\9.0\\bin\\python.exe", + "args": ["C:\\Users\\YourName\\KiCAD-MCP-Server\\python\\kicad_interface.py"], + "env": { + "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" + } + } + } +} +``` + +--- + +## Manual Testing Steps + +### Test 1: Verify KiCAD Python + +```powershell +& "C:\Program Files\KiCad\9.0\bin\python.exe" -c @" +import sys +print(f'Python version: {sys.version}') +import pcbnew +print(f'pcbnew version: {pcbnew.GetBuildVersion()}') +print('SUCCESS!') +"@ +``` + +Expected output: + +``` +Python version: 3.11.x ... +pcbnew version: 9.0.0 +SUCCESS! +``` + +### Test 2: Verify Node.js + +```powershell +node --version # Should be v18.0.0+ +npm --version # Should be 9.0.0+ +``` + +### Test 3: Build Project + +```powershell +cd C:\Users\YourName\KiCAD-MCP-Server +npm install +npm run build +Test-Path .\dist\index.js # Should output: True +``` + +### Test 4: Run Server Manually + +```powershell +$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" +node .\dist\index.js +``` + +Expected: Server should start and wait for input (doesn't exit immediately) + +**To stop:** Press Ctrl+C + +### Test 5: Check Log File + +```powershell +# View log file +Get-Content "$env:USERPROFILE\.kicad-mcp\logs\kicad_interface.log" -Tail 50 +``` + +Should show successful initialization with no errors. + +--- + +## Advanced Diagnostics + +### Enable Verbose Logging + +Add to your MCP config: + +```json +{ + "env": { + "LOG_LEVEL": "debug", + "PYTHONUNBUFFERED": "1" + } +} +``` + +### Check Python sys.path + +```powershell +& "C:\Program Files\KiCad\9.0\bin\python.exe" -c @" +import sys +for path in sys.path: + print(path) +"@ +``` + +Should include: `C:\Program Files\KiCad\9.0\lib\python3\dist-packages` + +### Test MCP Communication + +```powershell +# Start server +$env:PYTHONPATH = "C:\Program Files\KiCad\9.0\lib\python3\dist-packages" +$process = Start-Process -FilePath "node" -ArgumentList ".\dist\index.js" -NoNewWindow -PassThru + +# Wait 3 seconds +Start-Sleep -Seconds 3 + +# Check if still running +if ($process.HasExited) { + Write-Host "Server crashed!" -ForegroundColor Red + Write-Host "Exit code: $($process.ExitCode)" +} else { + Write-Host "Server is running!" -ForegroundColor Green + Stop-Process -Id $process.Id +} +``` + +--- + +## Getting Help + +If none of the above solutions work: + +1. **Run the diagnostic script:** + + ```powershell + .\setup-windows.ps1 + ``` + + Copy the entire output. + +2. **Collect log files:** + - MCP log: `%USERPROFILE%\.kicad-mcp\logs\kicad_interface.log` + - Claude Desktop log: `%APPDATA%\Claude\logs\mcp*.log` + +3. **Open a GitHub issue:** + - Go to: https://github.com/mixelpixx/KiCAD-MCP-Server/issues + - Title: "Windows Setup Issue: [brief description]" + - Include: + - Windows version (10 or 11) + - Output from setup script + - Log file contents + - Output from manual tests above + +--- + +## Known Limitations on Windows + +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: + + ```powershell + # Enable long paths (requires admin) + 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: + + ``` + Settings → Windows Security → Virus & threat protection → Exclusions + Add: C:\Users\YourName\KiCAD-MCP-Server + ``` + +4. **Antivirus software** may block Python/Node processes. Temporarily disable for testing. + +--- + +## Success Checklist + +When everything works, you should have: + +- [ ] KiCAD 9.0+ installed at `C:\Program Files\KiCad\9.0` +- [ ] Node.js 18+ installed and in PATH +- [ ] Python can import pcbnew successfully +- [ ] `npm run build` completes without errors +- [ ] `dist\index.js` file exists +- [ ] MCP config file created with correct paths +- [ ] Server starts without immediate crash +- [ ] Log file shows successful initialization +- [ ] Claude Desktop/Cline recognizes the MCP server +- [ ] Can execute: "Create a new KiCAD project" + +--- + +**Last Updated:** 2025-11-05 +**Maintained by:** KiCAD MCP Team + +For the latest updates, see: https://github.com/mixelpixx/KiCAD-MCP-Server diff --git a/docs/archive/BUILD_AND_TEST_SESSION.md b/docs/archive/BUILD_AND_TEST_SESSION.md index 50b6ead..76822bd 100644 --- a/docs/archive/BUILD_AND_TEST_SESSION.md +++ b/docs/archive/BUILD_AND_TEST_SESSION.md @@ -1,490 +1,523 @@ -# Build and Test Session Summary -**Date:** October 25, 2025 (Evening) -**Status:** ✅ **SUCCESS** - ---- - -## Session Goals - -Complete the MCP server build and test it with various MCP clients (Claude Desktop, Cline, Claude Code). - ---- - -## Completed Work - -### 1. **Fixed TypeScript Compilation Errors** 🔧 - -**Problem:** Missing TypeScript source files preventing build - -**Files Created:** -- `src/tools/project.ts` (80 lines) - - Registers MCP tools: `create_project`, `open_project`, `save_project`, `get_project_info` - -- `src/tools/routing.ts` (100 lines) - - Registers MCP tools: `add_net`, `route_trace`, `add_via`, `add_copper_pour` - -- `src/tools/schematic.ts` (76 lines) - - Registers MCP tools: `create_schematic`, `add_schematic_component`, `add_wire` - -- `src/utils/resource-helpers.ts` (60 lines) - - Helper functions: `createJsonResponse()`, `createBinaryResponse()`, `createErrorResponse()` - -**Total New Code:** ~316 lines of TypeScript - -**Result:** ✅ TypeScript compilation successful, 72 JavaScript files generated in `dist/` - ---- - -### 2. **Fixed Duplicate Resource Registration** 🐛 - -**Problem:** Both `component.ts` and `library.ts` registered a resource named "component_details" - -**Fix Applied:** -- Renamed library resource to `library_component_details` -- Updated URI template from `kicad://component/{componentId}` to `kicad://library/component/{componentId}` - -**File Modified:** `src/resources/library.ts` - -**Result:** ✅ No more registration conflicts, server starts cleanly - ---- - -### 3. **Successful Server Startup Test** 🚀 - -**Test Command:** -```bash -timeout --signal=TERM 3 node dist/index.js -``` - -**Server Output (All Green):** -``` -[INFO] Using STDIO transport for local communication -[INFO] Registering KiCAD tools, resources, and prompts... -[INFO] Registering board management tools -[INFO] Board management tools registered -[INFO] Registering component management tools -[INFO] Component management tools registered -[INFO] Registering design rule tools -[INFO] Design rule tools registered -[INFO] Registering export tools -[INFO] Export tools registered -[INFO] Registering project resources -[INFO] Project resources registered -[INFO] Registering board resources -[INFO] Board resources registered -[INFO] Registering component resources -[INFO] Component resources registered -[INFO] Registering library resources -[INFO] Library resources registered -[INFO] Registering component prompts -[INFO] Component prompts registered -[INFO] Registering routing prompts -[INFO] Routing prompts registered -[INFO] Registering design prompts -[INFO] Design prompts registered -[INFO] All KiCAD tools, resources, and prompts registered -[INFO] Starting KiCAD MCP server... -[INFO] Starting Python process with script: /home/chris/MCP/KiCAD-MCP-Server/python/kicad_interface.py -[INFO] Using Python executable: python -[INFO] Connecting MCP server to STDIO transport... -[INFO] Successfully connected to STDIO transport -``` - -**Exit Code:** 0 (graceful shutdown) - -**Result:** ✅ Server starts successfully, connects to STDIO, and shuts down gracefully - ---- - -### 4. **Comprehensive Client Configuration Guide** 📖 - -**File Created:** `docs/CLIENT_CONFIGURATION.md` (500+ lines) - -**Contents:** -- Platform-specific configurations: - - Linux (Ubuntu/Debian, Arch) - - macOS (with KiCAD.app paths) - - Windows 10/11 (with proper backslash escaping) - -- Client-specific setup: - - **Claude Desktop** - Full configuration for all platforms - - **Cline (VSCode)** - User settings and workspace settings - - **Claude Code CLI** - MCP config location - - **Generic MCP Client** - STDIO transport setup - -- Troubleshooting section: - - Server not starting - - Client can't connect - - Python module errors - - Finding KiCAD Python paths - -- Advanced topics: - - Multiple KiCAD versions - - Custom logging - - Development vs Production configs - - Security considerations - -**Impact:** New users can configure any MCP client in < 5 minutes! - ---- - -### 5. **Updated Configuration Examples** 📝 - -**Files Updated:** - -1. **`config/linux-config.example.json`** - - Cleaner format (removed unnecessary fields) - - Correct PYTHONPATH with both scripting and dist-packages - - Placeholder: `YOUR_USERNAME` for easy customization - -2. **`config/windows-config.example.json`** - - Fixed path separators (consistent backslashes) - - Correct KiCAD 9.0 Python path: `bin\Lib\site-packages` - - Simplified structure - -3. **`config/macos-config.example.json`** - - Using `Versions/Current` symlink for Python version flexibility - - Updated to match CLIENT_CONFIGURATION.md format - ---- - -### 6. **Updated README.md** 📚 - -**Addition:** New "Configuration for Other Clients" section after Quick Start - -**Changes:** -- Added links to CLIENT_CONFIGURATION.md guide -- Listed all supported MCP clients (Claude Desktop, Cline, Claude Code) -- Highlighted that KiCAD MCP works with ANY MCP-compatible client -- Clear guide reference with feature list - -**Result:** Users immediately know where to find setup instructions for their client - ---- - -## Statistics - -### Files Created/Modified (This Session) - -**New Files (5):** -``` -src/tools/project.ts # 80 lines -src/tools/routing.ts # 100 lines -src/tools/schematic.ts # 76 lines -src/utils/resource-helpers.ts # 60 lines -docs/CLIENT_CONFIGURATION.md # 500+ lines -docs/BUILD_AND_TEST_SESSION.md # This file -``` - -**Modified Files (5):** -``` -src/resources/library.ts # Fixed duplicate registration -config/linux-config.example.json # Updated format -config/windows-config.example.json # Fixed paths -config/macos-config.example.json # Updated format -README.md # Added config guide section -``` - -**Total New Lines:** ~816+ lines of code and documentation - ---- - -## Build Artifacts - -### Generated Files - -**TypeScript Compilation:** -- 72 JavaScript files in `dist/` -- 24 declaration files (`.d.ts`) -- 24 source maps (`.js.map`) - -**Directory Structure:** -``` -dist/ -├── index.js (entry point) -├── server.js (MCP server implementation) -├── kicad-server.js (KiCAD interface) -├── tools/ (10 tool modules) -├── resources/ (6 resource modules) -├── prompts/ (4 prompt modules) -└── utils/ (helper utilities) -``` - ---- - -## Verification Tests - -### ✅ Test 1: TypeScript Compilation -```bash -npm run build -# Result: SUCCESS (no errors) -``` - -### ✅ Test 2: Server Startup -```bash -timeout --signal=TERM 3 node dist/index.js -# Result: SUCCESS (exit code 0) -# - All tools registered -# - All resources registered -# - All prompts registered -# - STDIO transport connected -# - Python process spawned -# - Graceful shutdown -``` - -### ✅ Test 3: Python Integration -- Python process successfully spawned: `/home/chris/MCP/KiCAD-MCP-Server/python/kicad_interface.py` -- Using system Python: `python` (resolved to Python 3.12) -- No Python import errors during startup - ---- - -## Ready for Testing - -### MCP Server Capabilities - -**Registered Tools (20+):** -- Project: create_project, open_project, save_project, get_project_info -- Board: set_board_size, add_board_outline, get_board_properties -- Component: add_component, move_component, rotate_component, get_component_list -- Routing: add_net, route_trace, add_via, add_copper_pour -- Schematic: create_schematic, add_schematic_component, add_wire -- Design Rules: set_track_width, set_via_size, set_clearance, run_drc -- Export: export_gerber, export_pdf, export_svg, export_3d_model - -**Registered Resources (15+):** -- Project info and metadata -- Board info, layers, extents -- Board 2D/3D views (PNG, SVG) -- Component details (placed and library) -- Statistics and analytics - -**Registered Prompts (10+):** -- Component selection guidance -- Routing strategy suggestions -- Design best practices - ---- - -## Next Steps - -### Immediate Testing (Ready Now) - -1. **Test with Claude Code CLI:** - ```bash - # Create config - mkdir -p ~/.config/claude-code - cp docs/CLIENT_CONFIGURATION.md ~/.config/claude-code/ - - # Test connection - claude-code mcp list - claude-code mcp test kicad - ``` - -2. **Test with Claude Desktop:** - - Copy config from `config/linux-config.example.json` - - Edit `~/.config/Claude/claude_desktop_config.json` - - Restart Claude Desktop - - Start conversation and look for KiCAD tools - -3. **Test with Cline (VSCode):** - - Already configured from previous session - - Open VSCode, start Cline chat - - Ask: "What KiCAD tools are available?" - -### Integration Testing - -**Test basic workflow:** -``` -1. Create new project -2. Set board size -3. Add component -4. Create trace -5. Export Gerber files -``` - -**Test resources:** -``` -1. Request board info -2. View 2D board rendering -3. Get component list -4. Check board statistics -``` - ---- - -## Technical Highlights - -### 1. **Modular Tool Registration** - -Each tool module follows consistent pattern: -```typescript -export function registerXxxTools(server: McpServer, callKicadScript: Function) { - server.tool("tool_name", "Description", schema, async (args) => { - const result = await callKicadScript("command_name", args); - return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; - }); -} -``` - -**Benefits:** -- Easy to add new tools -- Consistent error handling -- Clean separation of concerns - -### 2. **Resource Helper Utilities** - -Abstracted common response patterns: -```typescript -createJsonResponse(data, uri) // For JSON data -createBinaryResponse(data, mime) // For images/binary -createErrorResponse(error, msg) // For errors -``` - -**Benefits:** -- DRY principle (Don't Repeat Yourself) -- Consistent response format -- Easy to modify response structure - -### 3. **STDIO Transport** - -Using standard STDIO (stdin/stdout) for MCP protocol: -- No network ports required -- Maximum security (process isolation) -- Works with all MCP clients -- Simple debugging (can pipe commands) - -### 4. **Python Subprocess Integration** - -Server spawns Python process for KiCAD operations: -- Persistent Python process (faster than per-call spawn) -- JSON-RPC communication over stdin/stdout -- Proper error propagation -- Graceful shutdown handling - ---- - -## Achievements - -### Development Infrastructure ✅ -- ✅ TypeScript build pipeline working -- ✅ All source files complete -- ✅ No compilation errors -- ✅ Source maps generated for debugging - -### Server Functionality ✅ -- ✅ MCP protocol implementation working -- ✅ STDIO transport connected -- ✅ Python subprocess integration -- ✅ Tool/resource/prompt registration -- ✅ Graceful startup and shutdown - -### Documentation ✅ -- ✅ Comprehensive client configuration guide -- ✅ Platform-specific examples -- ✅ Troubleshooting section -- ✅ Advanced configuration options - -### Configuration ✅ -- ✅ Linux config example -- ✅ Windows config example -- ✅ macOS config example -- ✅ README updated with guide links - ---- - -## Build Status - -**Week 1 Progress:** 100% ✅ - -| Category | Status | -|----------|--------| -| TypeScript compilation | ✅ Complete | -| Server startup | ✅ Working | -| STDIO transport | ✅ Connected | -| Python integration | ✅ Functional | -| Client configs | ✅ Documented | -| Testing guides | ✅ Available | - ---- - -## Success Criteria Met - -✅ **Build completes without errors** -✅ **Server starts and connects to STDIO** -✅ **All tools/resources registered successfully** -✅ **Python subprocess spawns correctly** -✅ **Configuration documented for all clients** -✅ **Ready for end-to-end testing** - ---- - -## Testing Readiness - -### Can Test Now With: - -1. **Claude Code CLI** - Via `~/.config/claude-code/mcp_config.json` -2. **Claude Desktop** - Via `~/.config/Claude/claude_desktop_config.json` -3. **Cline (VSCode)** - Already configured -4. **Direct STDIO** - Manual JSON-RPC testing - -### Testing Checklist: - -- [ ] Server responds to `initialize` request -- [ ] Server lists tools correctly -- [ ] Server lists resources correctly -- [ ] Server lists prompts correctly -- [ ] Tool invocation returns results -- [ ] Resource fetch returns data -- [ ] Prompt templates work -- [ ] Error handling works -- [ ] Graceful shutdown works - ---- - -## Code Quality - -**Metrics:** -- TypeScript strict mode: ✅ Enabled -- ESLint compliance: ✅ Clean -- Type coverage: ✅ 100% (all exports typed) -- Source maps: ✅ Generated -- Build warnings: 0 -- Build errors: 0 - ---- - -## Session Impact - -### Before This Session: -- TypeScript wouldn't compile (missing files) -- Server had duplicate resource registration bug -- No client configuration documentation -- Unclear how to use with different MCP clients - -### After This Session: -- Complete TypeScript build working -- Server starts cleanly with all features registered -- Comprehensive 500+ line configuration guide -- Ready for testing with any MCP client - ---- - -## Momentum Check - -**Status:** 🟢 **EXCELLENT** - -- Build: ✅ Working -- Tests: ✅ Passing (server startup) -- Docs: ✅ Comprehensive -- Code Quality: ⭐⭐⭐⭐⭐ - -**Ready for:** Live testing with MCP clients - ---- - -**End of Build and Test Session** - -**Next:** Test with Claude Desktop/Code/Cline and verify tool invocations work end-to-end - -🎉 **BUILD SUCCESSFUL - READY FOR TESTING!** 🎉 +# Build and Test Session Summary + +**Date:** October 25, 2025 (Evening) +**Status:** ✅ **SUCCESS** + +--- + +## Session Goals + +Complete the MCP server build and test it with various MCP clients (Claude Desktop, Cline, Claude Code). + +--- + +## Completed Work + +### 1. **Fixed TypeScript Compilation Errors** 🔧 + +**Problem:** Missing TypeScript source files preventing build + +**Files Created:** + +- `src/tools/project.ts` (80 lines) + - Registers MCP tools: `create_project`, `open_project`, `save_project`, `get_project_info` + +- `src/tools/routing.ts` (100 lines) + - Registers MCP tools: `add_net`, `route_trace`, `add_via`, `add_copper_pour` + +- `src/tools/schematic.ts` (76 lines) + - Registers MCP tools: `create_schematic`, `add_schematic_component`, `add_wire` + +- `src/utils/resource-helpers.ts` (60 lines) + - Helper functions: `createJsonResponse()`, `createBinaryResponse()`, `createErrorResponse()` + +**Total New Code:** ~316 lines of TypeScript + +**Result:** ✅ TypeScript compilation successful, 72 JavaScript files generated in `dist/` + +--- + +### 2. **Fixed Duplicate Resource Registration** 🐛 + +**Problem:** Both `component.ts` and `library.ts` registered a resource named "component_details" + +**Fix Applied:** + +- Renamed library resource to `library_component_details` +- Updated URI template from `kicad://component/{componentId}` to `kicad://library/component/{componentId}` + +**File Modified:** `src/resources/library.ts` + +**Result:** ✅ No more registration conflicts, server starts cleanly + +--- + +### 3. **Successful Server Startup Test** 🚀 + +**Test Command:** + +```bash +timeout --signal=TERM 3 node dist/index.js +``` + +**Server Output (All Green):** + +``` +[INFO] Using STDIO transport for local communication +[INFO] Registering KiCAD tools, resources, and prompts... +[INFO] Registering board management tools +[INFO] Board management tools registered +[INFO] Registering component management tools +[INFO] Component management tools registered +[INFO] Registering design rule tools +[INFO] Design rule tools registered +[INFO] Registering export tools +[INFO] Export tools registered +[INFO] Registering project resources +[INFO] Project resources registered +[INFO] Registering board resources +[INFO] Board resources registered +[INFO] Registering component resources +[INFO] Component resources registered +[INFO] Registering library resources +[INFO] Library resources registered +[INFO] Registering component prompts +[INFO] Component prompts registered +[INFO] Registering routing prompts +[INFO] Routing prompts registered +[INFO] Registering design prompts +[INFO] Design prompts registered +[INFO] All KiCAD tools, resources, and prompts registered +[INFO] Starting KiCAD MCP server... +[INFO] Starting Python process with script: /home/chris/MCP/KiCAD-MCP-Server/python/kicad_interface.py +[INFO] Using Python executable: python +[INFO] Connecting MCP server to STDIO transport... +[INFO] Successfully connected to STDIO transport +``` + +**Exit Code:** 0 (graceful shutdown) + +**Result:** ✅ Server starts successfully, connects to STDIO, and shuts down gracefully + +--- + +### 4. **Comprehensive Client Configuration Guide** 📖 + +**File Created:** `docs/CLIENT_CONFIGURATION.md` (500+ lines) + +**Contents:** + +- Platform-specific configurations: + - Linux (Ubuntu/Debian, Arch) + - macOS (with KiCAD.app paths) + - Windows 10/11 (with proper backslash escaping) + +- Client-specific setup: + - **Claude Desktop** - Full configuration for all platforms + - **Cline (VSCode)** - User settings and workspace settings + - **Claude Code CLI** - MCP config location + - **Generic MCP Client** - STDIO transport setup + +- Troubleshooting section: + - Server not starting + - Client can't connect + - Python module errors + - Finding KiCAD Python paths + +- Advanced topics: + - Multiple KiCAD versions + - Custom logging + - Development vs Production configs + - Security considerations + +**Impact:** New users can configure any MCP client in < 5 minutes! + +--- + +### 5. **Updated Configuration Examples** 📝 + +**Files Updated:** + +1. **`config/linux-config.example.json`** + - Cleaner format (removed unnecessary fields) + - Correct PYTHONPATH with both scripting and dist-packages + - Placeholder: `YOUR_USERNAME` for easy customization + +2. **`config/windows-config.example.json`** + - Fixed path separators (consistent backslashes) + - Correct KiCAD 9.0 Python path: `bin\Lib\site-packages` + - Simplified structure + +3. **`config/macos-config.example.json`** + - Using `Versions/Current` symlink for Python version flexibility + - Updated to match CLIENT_CONFIGURATION.md format + +--- + +### 6. **Updated README.md** 📚 + +**Addition:** New "Configuration for Other Clients" section after Quick Start + +**Changes:** + +- Added links to CLIENT_CONFIGURATION.md guide +- Listed all supported MCP clients (Claude Desktop, Cline, Claude Code) +- Highlighted that KiCAD MCP works with ANY MCP-compatible client +- Clear guide reference with feature list + +**Result:** Users immediately know where to find setup instructions for their client + +--- + +## Statistics + +### Files Created/Modified (This Session) + +**New Files (5):** + +``` +src/tools/project.ts # 80 lines +src/tools/routing.ts # 100 lines +src/tools/schematic.ts # 76 lines +src/utils/resource-helpers.ts # 60 lines +docs/CLIENT_CONFIGURATION.md # 500+ lines +docs/BUILD_AND_TEST_SESSION.md # This file +``` + +**Modified Files (5):** + +``` +src/resources/library.ts # Fixed duplicate registration +config/linux-config.example.json # Updated format +config/windows-config.example.json # Fixed paths +config/macos-config.example.json # Updated format +README.md # Added config guide section +``` + +**Total New Lines:** ~816+ lines of code and documentation + +--- + +## Build Artifacts + +### Generated Files + +**TypeScript Compilation:** + +- 72 JavaScript files in `dist/` +- 24 declaration files (`.d.ts`) +- 24 source maps (`.js.map`) + +**Directory Structure:** + +``` +dist/ +├── index.js (entry point) +├── server.js (MCP server implementation) +├── kicad-server.js (KiCAD interface) +├── tools/ (10 tool modules) +├── resources/ (6 resource modules) +├── prompts/ (4 prompt modules) +└── utils/ (helper utilities) +``` + +--- + +## Verification Tests + +### ✅ Test 1: TypeScript Compilation + +```bash +npm run build +# Result: SUCCESS (no errors) +``` + +### ✅ Test 2: Server Startup + +```bash +timeout --signal=TERM 3 node dist/index.js +# Result: SUCCESS (exit code 0) +# - All tools registered +# - All resources registered +# - All prompts registered +# - STDIO transport connected +# - Python process spawned +# - Graceful shutdown +``` + +### ✅ Test 3: Python Integration + +- Python process successfully spawned: `/home/chris/MCP/KiCAD-MCP-Server/python/kicad_interface.py` +- Using system Python: `python` (resolved to Python 3.12) +- No Python import errors during startup + +--- + +## Ready for Testing + +### MCP Server Capabilities + +**Registered Tools (20+):** + +- Project: create_project, open_project, save_project, get_project_info +- Board: set_board_size, add_board_outline, get_board_properties +- Component: add_component, move_component, rotate_component, get_component_list +- Routing: add_net, route_trace, add_via, add_copper_pour +- Schematic: create_schematic, add_schematic_component, add_wire +- Design Rules: set_track_width, set_via_size, set_clearance, run_drc +- Export: export_gerber, export_pdf, export_svg, export_3d_model + +**Registered Resources (15+):** + +- Project info and metadata +- Board info, layers, extents +- Board 2D/3D views (PNG, SVG) +- Component details (placed and library) +- Statistics and analytics + +**Registered Prompts (10+):** + +- Component selection guidance +- Routing strategy suggestions +- Design best practices + +--- + +## Next Steps + +### Immediate Testing (Ready Now) + +1. **Test with Claude Code CLI:** + + ```bash + # Create config + mkdir -p ~/.config/claude-code + cp docs/CLIENT_CONFIGURATION.md ~/.config/claude-code/ + + # Test connection + claude-code mcp list + claude-code mcp test kicad + ``` + +2. **Test with Claude Desktop:** + - Copy config from `config/linux-config.example.json` + - Edit `~/.config/Claude/claude_desktop_config.json` + - Restart Claude Desktop + - Start conversation and look for KiCAD tools + +3. **Test with Cline (VSCode):** + - Already configured from previous session + - Open VSCode, start Cline chat + - Ask: "What KiCAD tools are available?" + +### Integration Testing + +**Test basic workflow:** + +``` +1. Create new project +2. Set board size +3. Add component +4. Create trace +5. Export Gerber files +``` + +**Test resources:** + +``` +1. Request board info +2. View 2D board rendering +3. Get component list +4. Check board statistics +``` + +--- + +## Technical Highlights + +### 1. **Modular Tool Registration** + +Each tool module follows consistent pattern: + +```typescript +export function registerXxxTools(server: McpServer, callKicadScript: Function) { + server.tool("tool_name", "Description", schema, async (args) => { + const result = await callKicadScript("command_name", args); + return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; + }); +} +``` + +**Benefits:** + +- Easy to add new tools +- Consistent error handling +- Clean separation of concerns + +### 2. **Resource Helper Utilities** + +Abstracted common response patterns: + +```typescript +createJsonResponse(data, uri); // For JSON data +createBinaryResponse(data, mime); // For images/binary +createErrorResponse(error, msg); // For errors +``` + +**Benefits:** + +- DRY principle (Don't Repeat Yourself) +- Consistent response format +- Easy to modify response structure + +### 3. **STDIO Transport** + +Using standard STDIO (stdin/stdout) for MCP protocol: + +- No network ports required +- Maximum security (process isolation) +- Works with all MCP clients +- Simple debugging (can pipe commands) + +### 4. **Python Subprocess Integration** + +Server spawns Python process for KiCAD operations: + +- Persistent Python process (faster than per-call spawn) +- JSON-RPC communication over stdin/stdout +- Proper error propagation +- Graceful shutdown handling + +--- + +## Achievements + +### Development Infrastructure ✅ + +- ✅ TypeScript build pipeline working +- ✅ All source files complete +- ✅ No compilation errors +- ✅ Source maps generated for debugging + +### Server Functionality ✅ + +- ✅ MCP protocol implementation working +- ✅ STDIO transport connected +- ✅ Python subprocess integration +- ✅ Tool/resource/prompt registration +- ✅ Graceful startup and shutdown + +### Documentation ✅ + +- ✅ Comprehensive client configuration guide +- ✅ Platform-specific examples +- ✅ Troubleshooting section +- ✅ Advanced configuration options + +### Configuration ✅ + +- ✅ Linux config example +- ✅ Windows config example +- ✅ macOS config example +- ✅ README updated with guide links + +--- + +## Build Status + +**Week 1 Progress:** 100% ✅ + +| Category | Status | +| ---------------------- | ------------- | +| TypeScript compilation | ✅ Complete | +| Server startup | ✅ Working | +| STDIO transport | ✅ Connected | +| Python integration | ✅ Functional | +| Client configs | ✅ Documented | +| Testing guides | ✅ Available | + +--- + +## Success Criteria Met + +✅ **Build completes without errors** +✅ **Server starts and connects to STDIO** +✅ **All tools/resources registered successfully** +✅ **Python subprocess spawns correctly** +✅ **Configuration documented for all clients** +✅ **Ready for end-to-end testing** + +--- + +## Testing Readiness + +### Can Test Now With: + +1. **Claude Code CLI** - Via `~/.config/claude-code/mcp_config.json` +2. **Claude Desktop** - Via `~/.config/Claude/claude_desktop_config.json` +3. **Cline (VSCode)** - Already configured +4. **Direct STDIO** - Manual JSON-RPC testing + +### Testing Checklist: + +- [ ] Server responds to `initialize` request +- [ ] Server lists tools correctly +- [ ] Server lists resources correctly +- [ ] Server lists prompts correctly +- [ ] Tool invocation returns results +- [ ] Resource fetch returns data +- [ ] Prompt templates work +- [ ] Error handling works +- [ ] Graceful shutdown works + +--- + +## Code Quality + +**Metrics:** + +- TypeScript strict mode: ✅ Enabled +- ESLint compliance: ✅ Clean +- Type coverage: ✅ 100% (all exports typed) +- Source maps: ✅ Generated +- Build warnings: 0 +- Build errors: 0 + +--- + +## Session Impact + +### Before This Session: + +- TypeScript wouldn't compile (missing files) +- Server had duplicate resource registration bug +- No client configuration documentation +- Unclear how to use with different MCP clients + +### After This Session: + +- Complete TypeScript build working +- Server starts cleanly with all features registered +- Comprehensive 500+ line configuration guide +- Ready for testing with any MCP client + +--- + +## Momentum Check + +**Status:** 🟢 **EXCELLENT** + +- Build: ✅ Working +- Tests: ✅ Passing (server startup) +- Docs: ✅ Comprehensive +- Code Quality: ⭐⭐⭐⭐⭐ + +**Ready for:** Live testing with MCP clients + +--- + +**End of Build and Test Session** + +**Next:** Test with Claude Desktop/Code/Cline and verify tool invocations work end-to-end + +🎉 **BUILD SUCCESSFUL - READY FOR TESTING!** 🎉 diff --git a/docs/archive/DYNAMIC_LIBRARY_LOADING_PLAN.md b/docs/archive/DYNAMIC_LIBRARY_LOADING_PLAN.md index 4c9386d..1e530f5 100644 --- a/docs/archive/DYNAMIC_LIBRARY_LOADING_PLAN.md +++ b/docs/archive/DYNAMIC_LIBRARY_LOADING_PLAN.md @@ -1,485 +1,509 @@ -# Option 2: Dynamic Library Loading Plan - -## Executive Summary - -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):** -- ✅ Template-based approach working -- ✅ 13 component types supported -- ❌ Limited symbol variety -- ❌ Requires manual template updates for new types - -**Proposed (Option 2):** -- 🎯 Dynamic loading from `.kicad_sym` library files -- 🎯 Access to ~10,000+ KiCad symbols -- 🎯 No template maintenance required -- 🎯 User can specify any library/symbol combination - ---- - -## Problem Analysis - -### kicad-skip Library Limitation - -**Core Issue:** kicad-skip **cannot create symbols from scratch**. It can only: -1. Clone existing symbols from a loaded schematic -2. Modify properties of cloned symbols - -**Current Workaround:** Pre-load template symbols in schematic file - -**Proposed Solution:** Load symbols from KiCad's `.kicad_sym` library files, inject them into the schematic's `lib_symbols` section, then clone from there. - ---- - -## KiCad Symbol Library Architecture - -### Symbol Library File Format (`.kicad_sym`) - -KiCad symbol libraries are S-expression files containing symbol definitions: - -```lisp -(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor) - (symbol "Device:R" - (pin_numbers hide) - (pin_names (offset 0)) - (in_bom yes) - (on_board yes) - (property "Reference" "R" ...) - (property "Value" "R" ...) - ;; Graphics definitions - (symbol "R_0_1" ...) - (symbol "R_1_1" - (pin passive line ...) - ) - ) - (symbol "Device:C" ...) - (symbol "Device:L" ...) - ;; ... thousands more -) -``` - -### Standard KiCad Library Locations - -**Linux:** -- System libraries: `/usr/share/kicad/symbols/` -- User libraries: `~/.local/share/kicad/8.0/symbols/` or `~/.config/kicad/8.0/symbols/` - -**Windows:** -- System libraries: `C:\Program Files\KiCad\9.0\share\kicad\symbols\` -- User libraries: `%APPDATA%\kicad\8.0\symbols\` - -**macOS:** -- System libraries: `/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/` -- User libraries: `~/Library/Preferences/kicad/8.0/symbols/` - -### Standard Library Files - -Common libraries (each containing 50-500 symbols): -- `Device.kicad_sym` - Passives (R, C, L, D, LED, Crystal, etc.) -- `Connector.kicad_sym` - Connectors (headers, USB, etc.) -- `Connector_Generic.kicad_sym` - Generic connectors -- `Transistor_BJT.kicad_sym` - Bipolar transistors -- `Transistor_FET.kicad_sym` - MOSFETs -- `Amplifier_Operational.kicad_sym` - Op-amps -- `Regulator_Linear.kicad_sym` - Voltage regulators -- `MCU_*.kicad_sym` - Microcontrollers -- `Interface_*.kicad_sym` - Interface ICs -- ... 100+ more libraries - ---- - -## Implementation Strategy - -### Phase 1: Library Discovery & Indexing - -**Goal:** Build an index of all available symbols and their locations - -**Implementation:** -```python -class SymbolLibraryManager: - def __init__(self): - self.library_paths = [] - self.symbol_index = {} # {"Device:R": "/path/to/Device.kicad_sym", ...} - - def discover_libraries(self): - """Find all KiCad symbol libraries on the system""" - search_paths = [ - "/usr/share/kicad/symbols/", - os.path.expanduser("~/.local/share/kicad/8.0/symbols/"), - os.path.expanduser("~/.config/kicad/8.0/symbols/"), - ] - - for search_path in search_paths: - if os.path.exists(search_path): - for lib_file in os.listdir(search_path): - if lib_file.endswith('.kicad_sym'): - self.library_paths.append(os.path.join(search_path, lib_file)) - - def index_symbols(self): - """Parse all libraries and build symbol index""" - for lib_path in self.library_paths: - lib_name = os.path.basename(lib_path).replace('.kicad_sym', '') - symbols = self._parse_library(lib_path) - - for symbol_name in symbols: - full_name = f"{lib_name}:{symbol_name}" - self.symbol_index[full_name] = { - 'library': lib_name, - 'library_path': lib_path, - 'symbol_name': symbol_name - } - - def _parse_library(self, lib_path): - """Parse .kicad_sym file and extract symbol names""" - # Use sexpdata (already a dependency of kicad-skip) - import sexpdata - - with open(lib_path, 'r') as f: - data = sexpdata.load(f) - - symbols = [] - for item in data[2:]: # Skip header - if isinstance(item, list) and item[0] == Symbol('symbol'): - symbol_name = item[1] # e.g., "Device:R" - # Extract just the symbol part after ':' - if ':' in symbol_name: - symbol_name = symbol_name.split(':')[1] - symbols.append(symbol_name) - - return symbols -``` - -### Phase 2: Dynamic Symbol Injection - -**Goal:** Load symbol definition from library file and inject into schematic - -**Challenge:** kicad-skip works with loaded schematics, but we need to dynamically add symbols to the `lib_symbols` section. - -**Solution:** Modify the schematic's S-expression data directly before loading with kicad-skip: - -```python -def inject_symbol_into_schematic(schematic_path, library_path, symbol_name): - """ - 1. Read schematic S-expression - 2. Read library S-expression - 3. Extract symbol definition from library - 4. Inject into schematic's lib_symbols section - 5. Save modified schematic - 6. Reload with kicad-skip - """ - import sexpdata - - # Load schematic - with open(schematic_path, 'r') as f: - sch_data = sexpdata.load(f) - - # Load library - with open(library_path, 'r') as f: - lib_data = sexpdata.load(f) - - # Find symbol definition in library - symbol_def = None - for item in lib_data[2:]: - if isinstance(item, list) and item[0] == Symbol('symbol'): - if symbol_name in str(item[1]): - symbol_def = item - break - - if not symbol_def: - raise ValueError(f"Symbol {symbol_name} not found in {library_path}") - - # Find lib_symbols section in schematic - lib_symbols_index = None - for i, item in enumerate(sch_data): - if isinstance(item, list) and item[0] == Symbol('lib_symbols'): - lib_symbols_index = i - break - - # Inject symbol definition - if lib_symbols_index: - sch_data[lib_symbols_index].append(symbol_def) - - # Save modified schematic - with open(schematic_path, 'w') as f: - sexpdata.dump(sch_data, f) - - # Reload with kicad-skip - return Schematic(schematic_path) -``` - -### Phase 3: Template Instance Creation - -**Goal:** Create offscreen template instances that can be cloned - -**After injection:** Symbol definition is in `lib_symbols`, but we need an instance to clone from: - -```python -def create_template_instance(schematic, library_name, symbol_name): - """ - Create an offscreen template instance that can be cloned - Similar to our current _TEMPLATE_R approach - """ - # This requires directly manipulating the S-expression - # Add a symbol instance at offscreen position with special reference - - template_ref = f"_TEMPLATE_{library_name}_{symbol_name}" - - # Create symbol instance (S-expression) - symbol_instance = [ - Symbol('symbol'), - [Symbol('lib_id'), f"{library_name}:{symbol_name}"], - [Symbol('at'), -100, -100 - (len(schematic.symbol) * 10), 0], - [Symbol('unit'), 1], - [Symbol('in_bom'), Symbol('no')], - [Symbol('on_board'), Symbol('no')], - [Symbol('dnp'), Symbol('yes')], - [Symbol('uuid'), str(uuid.uuid4())], - [Symbol('property'), "Reference", template_ref, ...], - # ... more properties - ] - - # Inject into schematic and reload - # ... (similar to inject_symbol_into_schematic) - - return template_ref -``` - -### Phase 4: User-Facing API - -**Goal:** Simple interface for users to add any KiCad symbol - -**New MCP Tool: `add_schematic_component_dynamic`** - -```python -def add_schematic_component_dynamic(params): - """ - Add component by library:symbol notation - - Example: - { - "library": "Device", - "symbol": "R", - "reference": "R1", - "value": "10k", - "x": 100, - "y": 100 - } - - OR using full notation: - { - "lib_symbol": "Device:R", # Full notation - "reference": "R1", - ... - } - """ - lib_symbol = params.get('lib_symbol') or f"{params['library']}:{params['symbol']}" - - # 1. Check if symbol is already in schematic's lib_symbols - # 2. If not, inject it from library file - # 3. Create template instance if needed - # 4. Clone template and set properties - - return {"success": True, "reference": params['reference']} -``` - ---- - -## Advantages Over Template Approach - -### ✅ Unlimited Symbol Access -- Access to ~10,000+ standard KiCad symbols -- Support for custom user libraries -- Support for 3rd-party libraries (JLCPCB, Espressif, etc.) - -### ✅ No Maintenance Required -- Template doesn't need updates for new component types -- Automatically supports new KiCad library additions -- Works with custom symbol libraries - -### ✅ Better User Experience -``` -User: "Add an STM32F103C8T6 microcontroller at position 100,100" -AI: *Searches symbol index* - *Finds MCU_ST_STM32F1:STM32F103C8Tx* - *Loads from library* - *Injects into schematic* - *Places component* - ✓ Done! -``` - -### ✅ Flexible Symbol Search -```python -# Find all resistors -symbols = lib_manager.search_symbols(query="resistor") -# Returns: ["Device:R", "Device:R_Small", "Device:R_Network", ...] - -# Find all STM32 MCUs -symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1") -``` - ---- - -## Challenges & Mitigations - -### Challenge 1: S-expression Manipulation Complexity - -**Problem:** Directly manipulating S-expression data is error-prone - -**Mitigation:** -- Use `sexpdata` library (already a dependency) -- Create helper functions for common operations -- Add comprehensive validation and error handling -- Extensive testing with various symbol types - -### Challenge 2: Performance - -**Problem:** Loading/reloading schematics after injection could be slow - -**Mitigation:** -- **Cache loaded symbols**: Once injected, symbol stays in schematic -- **Batch injection**: Inject multiple symbols at once -- **Lazy loading**: Only inject symbols when first used - -### Challenge 3: Symbol Compatibility - -**Problem:** Some symbols may have complex pin configurations or multiple units - -**Mitigation:** -- Start with simple 2-pin passives (R, C, L) -- Gradually add support for multi-pin ICs -- Handle multi-unit symbols (gates, OpAmp sections) explicitly -- Document supported symbol types - -### Challenge 4: Library Version Compatibility - -**Problem:** KiCad symbol format may change between versions - -**Mitigation:** -- Parse KiCad version from library files -- Version-specific handling if needed -- Fallback to template approach for unsupported formats - ---- - -## Implementation Phases - -### Phase A: Proof of Concept (1-2 weeks) -- [ ] Create `SymbolLibraryManager` class -- [ ] Implement library discovery (Linux paths only) -- [ ] Implement symbol indexing -- [ ] Test with Device.kicad_sym (R, C, L) -- [ ] Implement basic S-expression injection -- [ ] Test end-to-end with simple components - -### Phase B: Core Functionality (2-3 weeks) -- [ ] Cross-platform library discovery (Windows, macOS) -- [ ] Symbol search functionality -- [ ] Template instance creation automation -- [ ] Multi-pin component support -- [ ] Error handling and validation -- [ ] Unit tests for all operations - -### Phase C: MCP Integration (1 week) -- [ ] Create `add_schematic_component_dynamic` tool -- [ ] Update `search_symbols` to use library index -- [ ] Add `list_available_symbols` tool -- [ ] Add `list_symbol_libraries` tool -- [ ] Documentation and examples - -### Phase D: Advanced Features (2-3 weeks) -- [ ] Multi-unit symbol support (e.g., quad OpAmps) -- [ ] Custom library registration -- [ ] Symbol caching and optimization -- [ ] 3rd-party library support (JLCPCB, etc.) -- [ ] Symbol preview generation - ---- - -## Migration Strategy - -### Backward Compatibility - -Keep template-based approach as fallback: - -```python -def add_schematic_component(params): - """Smart component addition with fallback""" - # Try dynamic loading first - try: - if 'library' in params or 'lib_symbol' in params: - return add_schematic_component_dynamic(params) - except Exception as e: - logger.warning(f"Dynamic loading failed: {e}, falling back to template") - - # Fallback to template-based - return add_schematic_component_template(params) -``` - -### Gradual Rollout - -1. **Week 1-2:** Implement basic dynamic loading -2. **Week 3-4:** Test with power users, gather feedback -3. **Week 5-6:** Make dynamic loading the default -4. **Week 7+:** Deprecate template-only approach (keep as fallback) - ---- - -## Success Criteria - -### Must Have -- [ ] Load symbols from Device.kicad_sym (passives) -- [ ] Support R, C, L, D, LED (5 core types) -- [ ] Cross-platform library discovery -- [ ] Proper error handling - -### Should Have -- [ ] Support for all Device.kicad_sym symbols (~50 symbols) -- [ ] Support for Connector.kicad_sym symbols -- [ ] Symbol search by name/keyword -- [ ] Performance: < 1 second per symbol injection - -### Nice to Have -- [ ] Support for all standard libraries (~10,000 symbols) -- [ ] Multi-unit symbol support -- [ ] Custom library registration -- [ ] Symbol preview/documentation - ---- - -## Risk Assessment - -| Risk | Probability | Impact | Mitigation | -|------|-------------|--------|------------| -| S-expression parsing complexity | High | High | Use proven `sexpdata` library, extensive testing | -| Performance degradation | Medium | Medium | Implement caching, lazy loading | -| KiCad version incompatibility | Low | High | Version detection, format validation | -| Template fallback breaks | Low | Medium | Maintain template approach in parallel | -| User confusion | Medium | Low | Clear documentation, gradual rollout | - ---- - -## Conclusion - -Dynamic library loading is **feasible and highly beneficial** for the schematic workflow. While the template-based approach (Option 1) provides immediate value with 13 component types, Option 2 would: - -1. **Eliminate the 13-component limitation** -2. **Provide access to 10,000+ KiCad symbols** -3. **Remove manual template maintenance** -4. **Enable true "natural language PCB design"** - -**Recommendation:** -- ✅ **Keep Option 1 (expanded template) for immediate use** -- ✅ **Implement Option 2 (dynamic loading) over 6-8 weeks** -- ✅ **Maintain template fallback for compatibility** - -This gives users immediate value while we build the robust long-term solution. - ---- - -## References - -- [KiCad File Formats Documentation](https://dev-docs.kicad.org/en/file-formats/) -- [kicad-skip GitHub](https://github.com/mvnmgrx/kicad-skip) -- [sexpdata Python Library](https://github.com/jd-boyd/sexpdata) -- [KiCad Symbol Library Format Spec](https://dev-docs.kicad.org/en/file-formats/sexpr-intro/) +# Option 2: Dynamic Library Loading Plan + +## Executive Summary + +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):** + +- ✅ Template-based approach working +- ✅ 13 component types supported +- ❌ Limited symbol variety +- ❌ Requires manual template updates for new types + +**Proposed (Option 2):** + +- 🎯 Dynamic loading from `.kicad_sym` library files +- 🎯 Access to ~10,000+ KiCad symbols +- 🎯 No template maintenance required +- 🎯 User can specify any library/symbol combination + +--- + +## Problem Analysis + +### kicad-skip Library Limitation + +**Core Issue:** kicad-skip **cannot create symbols from scratch**. It can only: + +1. Clone existing symbols from a loaded schematic +2. Modify properties of cloned symbols + +**Current Workaround:** Pre-load template symbols in schematic file + +**Proposed Solution:** Load symbols from KiCad's `.kicad_sym` library files, inject them into the schematic's `lib_symbols` section, then clone from there. + +--- + +## KiCad Symbol Library Architecture + +### Symbol Library File Format (`.kicad_sym`) + +KiCad symbol libraries are S-expression files containing symbol definitions: + +```lisp +(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor) + (symbol "Device:R" + (pin_numbers hide) + (pin_names (offset 0)) + (in_bom yes) + (on_board yes) + (property "Reference" "R" ...) + (property "Value" "R" ...) + ;; Graphics definitions + (symbol "R_0_1" ...) + (symbol "R_1_1" + (pin passive line ...) + ) + ) + (symbol "Device:C" ...) + (symbol "Device:L" ...) + ;; ... thousands more +) +``` + +### Standard KiCad Library Locations + +**Linux:** + +- System libraries: `/usr/share/kicad/symbols/` +- User libraries: `~/.local/share/kicad/8.0/symbols/` or `~/.config/kicad/8.0/symbols/` + +**Windows:** + +- System libraries: `C:\Program Files\KiCad\9.0\share\kicad\symbols\` +- User libraries: `%APPDATA%\kicad\8.0\symbols\` + +**macOS:** + +- System libraries: `/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/` +- User libraries: `~/Library/Preferences/kicad/8.0/symbols/` + +### Standard Library Files + +Common libraries (each containing 50-500 symbols): + +- `Device.kicad_sym` - Passives (R, C, L, D, LED, Crystal, etc.) +- `Connector.kicad_sym` - Connectors (headers, USB, etc.) +- `Connector_Generic.kicad_sym` - Generic connectors +- `Transistor_BJT.kicad_sym` - Bipolar transistors +- `Transistor_FET.kicad_sym` - MOSFETs +- `Amplifier_Operational.kicad_sym` - Op-amps +- `Regulator_Linear.kicad_sym` - Voltage regulators +- `MCU_*.kicad_sym` - Microcontrollers +- `Interface_*.kicad_sym` - Interface ICs +- ... 100+ more libraries + +--- + +## Implementation Strategy + +### Phase 1: Library Discovery & Indexing + +**Goal:** Build an index of all available symbols and their locations + +**Implementation:** + +```python +class SymbolLibraryManager: + def __init__(self): + self.library_paths = [] + self.symbol_index = {} # {"Device:R": "/path/to/Device.kicad_sym", ...} + + def discover_libraries(self): + """Find all KiCad symbol libraries on the system""" + search_paths = [ + "/usr/share/kicad/symbols/", + os.path.expanduser("~/.local/share/kicad/8.0/symbols/"), + os.path.expanduser("~/.config/kicad/8.0/symbols/"), + ] + + for search_path in search_paths: + if os.path.exists(search_path): + for lib_file in os.listdir(search_path): + if lib_file.endswith('.kicad_sym'): + self.library_paths.append(os.path.join(search_path, lib_file)) + + def index_symbols(self): + """Parse all libraries and build symbol index""" + for lib_path in self.library_paths: + lib_name = os.path.basename(lib_path).replace('.kicad_sym', '') + symbols = self._parse_library(lib_path) + + for symbol_name in symbols: + full_name = f"{lib_name}:{symbol_name}" + self.symbol_index[full_name] = { + 'library': lib_name, + 'library_path': lib_path, + 'symbol_name': symbol_name + } + + def _parse_library(self, lib_path): + """Parse .kicad_sym file and extract symbol names""" + # Use sexpdata (already a dependency of kicad-skip) + import sexpdata + + with open(lib_path, 'r') as f: + data = sexpdata.load(f) + + symbols = [] + for item in data[2:]: # Skip header + if isinstance(item, list) and item[0] == Symbol('symbol'): + symbol_name = item[1] # e.g., "Device:R" + # Extract just the symbol part after ':' + if ':' in symbol_name: + symbol_name = symbol_name.split(':')[1] + symbols.append(symbol_name) + + return symbols +``` + +### Phase 2: Dynamic Symbol Injection + +**Goal:** Load symbol definition from library file and inject into schematic + +**Challenge:** kicad-skip works with loaded schematics, but we need to dynamically add symbols to the `lib_symbols` section. + +**Solution:** Modify the schematic's S-expression data directly before loading with kicad-skip: + +```python +def inject_symbol_into_schematic(schematic_path, library_path, symbol_name): + """ + 1. Read schematic S-expression + 2. Read library S-expression + 3. Extract symbol definition from library + 4. Inject into schematic's lib_symbols section + 5. Save modified schematic + 6. Reload with kicad-skip + """ + import sexpdata + + # Load schematic + with open(schematic_path, 'r') as f: + sch_data = sexpdata.load(f) + + # Load library + with open(library_path, 'r') as f: + lib_data = sexpdata.load(f) + + # Find symbol definition in library + symbol_def = None + for item in lib_data[2:]: + if isinstance(item, list) and item[0] == Symbol('symbol'): + if symbol_name in str(item[1]): + symbol_def = item + break + + if not symbol_def: + raise ValueError(f"Symbol {symbol_name} not found in {library_path}") + + # Find lib_symbols section in schematic + lib_symbols_index = None + for i, item in enumerate(sch_data): + if isinstance(item, list) and item[0] == Symbol('lib_symbols'): + lib_symbols_index = i + break + + # Inject symbol definition + if lib_symbols_index: + sch_data[lib_symbols_index].append(symbol_def) + + # Save modified schematic + with open(schematic_path, 'w') as f: + sexpdata.dump(sch_data, f) + + # Reload with kicad-skip + return Schematic(schematic_path) +``` + +### Phase 3: Template Instance Creation + +**Goal:** Create offscreen template instances that can be cloned + +**After injection:** Symbol definition is in `lib_symbols`, but we need an instance to clone from: + +```python +def create_template_instance(schematic, library_name, symbol_name): + """ + Create an offscreen template instance that can be cloned + Similar to our current _TEMPLATE_R approach + """ + # This requires directly manipulating the S-expression + # Add a symbol instance at offscreen position with special reference + + template_ref = f"_TEMPLATE_{library_name}_{symbol_name}" + + # Create symbol instance (S-expression) + symbol_instance = [ + Symbol('symbol'), + [Symbol('lib_id'), f"{library_name}:{symbol_name}"], + [Symbol('at'), -100, -100 - (len(schematic.symbol) * 10), 0], + [Symbol('unit'), 1], + [Symbol('in_bom'), Symbol('no')], + [Symbol('on_board'), Symbol('no')], + [Symbol('dnp'), Symbol('yes')], + [Symbol('uuid'), str(uuid.uuid4())], + [Symbol('property'), "Reference", template_ref, ...], + # ... more properties + ] + + # Inject into schematic and reload + # ... (similar to inject_symbol_into_schematic) + + return template_ref +``` + +### Phase 4: User-Facing API + +**Goal:** Simple interface for users to add any KiCad symbol + +**New MCP Tool: `add_schematic_component_dynamic`** + +```python +def add_schematic_component_dynamic(params): + """ + Add component by library:symbol notation + + Example: + { + "library": "Device", + "symbol": "R", + "reference": "R1", + "value": "10k", + "x": 100, + "y": 100 + } + + OR using full notation: + { + "lib_symbol": "Device:R", # Full notation + "reference": "R1", + ... + } + """ + lib_symbol = params.get('lib_symbol') or f"{params['library']}:{params['symbol']}" + + # 1. Check if symbol is already in schematic's lib_symbols + # 2. If not, inject it from library file + # 3. Create template instance if needed + # 4. Clone template and set properties + + return {"success": True, "reference": params['reference']} +``` + +--- + +## Advantages Over Template Approach + +### ✅ Unlimited Symbol Access + +- Access to ~10,000+ standard KiCad symbols +- Support for custom user libraries +- Support for 3rd-party libraries (JLCPCB, Espressif, etc.) + +### ✅ No Maintenance Required + +- Template doesn't need updates for new component types +- Automatically supports new KiCad library additions +- Works with custom symbol libraries + +### ✅ Better User Experience + +``` +User: "Add an STM32F103C8T6 microcontroller at position 100,100" +AI: *Searches symbol index* + *Finds MCU_ST_STM32F1:STM32F103C8Tx* + *Loads from library* + *Injects into schematic* + *Places component* + ✓ Done! +``` + +### ✅ Flexible Symbol Search + +```python +# Find all resistors +symbols = lib_manager.search_symbols(query="resistor") +# Returns: ["Device:R", "Device:R_Small", "Device:R_Network", ...] + +# Find all STM32 MCUs +symbols = lib_manager.search_symbols(query="STM32", library="MCU_ST_STM32F1") +``` + +--- + +## Challenges & Mitigations + +### Challenge 1: S-expression Manipulation Complexity + +**Problem:** Directly manipulating S-expression data is error-prone + +**Mitigation:** + +- Use `sexpdata` library (already a dependency) +- Create helper functions for common operations +- Add comprehensive validation and error handling +- Extensive testing with various symbol types + +### Challenge 2: Performance + +**Problem:** Loading/reloading schematics after injection could be slow + +**Mitigation:** + +- **Cache loaded symbols**: Once injected, symbol stays in schematic +- **Batch injection**: Inject multiple symbols at once +- **Lazy loading**: Only inject symbols when first used + +### Challenge 3: Symbol Compatibility + +**Problem:** Some symbols may have complex pin configurations or multiple units + +**Mitigation:** + +- Start with simple 2-pin passives (R, C, L) +- Gradually add support for multi-pin ICs +- Handle multi-unit symbols (gates, OpAmp sections) explicitly +- Document supported symbol types + +### Challenge 4: Library Version Compatibility + +**Problem:** KiCad symbol format may change between versions + +**Mitigation:** + +- Parse KiCad version from library files +- Version-specific handling if needed +- Fallback to template approach for unsupported formats + +--- + +## Implementation Phases + +### Phase A: Proof of Concept (1-2 weeks) + +- [ ] Create `SymbolLibraryManager` class +- [ ] Implement library discovery (Linux paths only) +- [ ] Implement symbol indexing +- [ ] Test with Device.kicad_sym (R, C, L) +- [ ] Implement basic S-expression injection +- [ ] Test end-to-end with simple components + +### Phase B: Core Functionality (2-3 weeks) + +- [ ] Cross-platform library discovery (Windows, macOS) +- [ ] Symbol search functionality +- [ ] Template instance creation automation +- [ ] Multi-pin component support +- [ ] Error handling and validation +- [ ] Unit tests for all operations + +### Phase C: MCP Integration (1 week) + +- [ ] Create `add_schematic_component_dynamic` tool +- [ ] Update `search_symbols` to use library index +- [ ] Add `list_available_symbols` tool +- [ ] Add `list_symbol_libraries` tool +- [ ] Documentation and examples + +### Phase D: Advanced Features (2-3 weeks) + +- [ ] Multi-unit symbol support (e.g., quad OpAmps) +- [ ] Custom library registration +- [ ] Symbol caching and optimization +- [ ] 3rd-party library support (JLCPCB, etc.) +- [ ] Symbol preview generation + +--- + +## Migration Strategy + +### Backward Compatibility + +Keep template-based approach as fallback: + +```python +def add_schematic_component(params): + """Smart component addition with fallback""" + # Try dynamic loading first + try: + if 'library' in params or 'lib_symbol' in params: + return add_schematic_component_dynamic(params) + except Exception as e: + logger.warning(f"Dynamic loading failed: {e}, falling back to template") + + # Fallback to template-based + return add_schematic_component_template(params) +``` + +### Gradual Rollout + +1. **Week 1-2:** Implement basic dynamic loading +2. **Week 3-4:** Test with power users, gather feedback +3. **Week 5-6:** Make dynamic loading the default +4. **Week 7+:** Deprecate template-only approach (keep as fallback) + +--- + +## Success Criteria + +### Must Have + +- [ ] Load symbols from Device.kicad_sym (passives) +- [ ] Support R, C, L, D, LED (5 core types) +- [ ] Cross-platform library discovery +- [ ] Proper error handling + +### Should Have + +- [ ] Support for all Device.kicad_sym symbols (~50 symbols) +- [ ] Support for Connector.kicad_sym symbols +- [ ] Symbol search by name/keyword +- [ ] Performance: < 1 second per symbol injection + +### Nice to Have + +- [ ] Support for all standard libraries (~10,000 symbols) +- [ ] Multi-unit symbol support +- [ ] Custom library registration +- [ ] Symbol preview/documentation + +--- + +## Risk Assessment + +| Risk | Probability | Impact | Mitigation | +| ------------------------------- | ----------- | ------ | ------------------------------------------------ | +| S-expression parsing complexity | High | High | Use proven `sexpdata` library, extensive testing | +| Performance degradation | Medium | Medium | Implement caching, lazy loading | +| KiCad version incompatibility | Low | High | Version detection, format validation | +| Template fallback breaks | Low | Medium | Maintain template approach in parallel | +| User confusion | Medium | Low | Clear documentation, gradual rollout | + +--- + +## Conclusion + +Dynamic library loading is **feasible and highly beneficial** for the schematic workflow. While the template-based approach (Option 1) provides immediate value with 13 component types, Option 2 would: + +1. **Eliminate the 13-component limitation** +2. **Provide access to 10,000+ KiCad symbols** +3. **Remove manual template maintenance** +4. **Enable true "natural language PCB design"** + +**Recommendation:** + +- ✅ **Keep Option 1 (expanded template) for immediate use** +- ✅ **Implement Option 2 (dynamic loading) over 6-8 weeks** +- ✅ **Maintain template fallback for compatibility** + +This gives users immediate value while we build the robust long-term solution. + +--- + +## References + +- [KiCad File Formats Documentation](https://dev-docs.kicad.org/en/file-formats/) +- [kicad-skip GitHub](https://github.com/mvnmgrx/kicad-skip) +- [sexpdata Python Library](https://github.com/jd-boyd/sexpdata) +- [KiCad Symbol Library Format Spec](https://dev-docs.kicad.org/en/file-formats/sexpr-intro/) diff --git a/docs/archive/DYNAMIC_LOADING_STATUS.md b/docs/archive/DYNAMIC_LOADING_STATUS.md index 3daa7f4..5890fe0 100644 --- a/docs/archive/DYNAMIC_LOADING_STATUS.md +++ b/docs/archive/DYNAMIC_LOADING_STATUS.md @@ -1,390 +1,413 @@ -# Dynamic Symbol Loading - Implementation Status - -**Date:** 2026-01-10 -**Status:** Phase A-C - ✅ **COMPLETE AND PRODUCTION-READY!** - -## 🚀 BREAKTHROUGH: Full MCP Integration Complete! - -We went from **planning** to **full production integration** in a single session! - -**Phase A** (Proof of Concept): ✅ Complete - Core dynamic loading works -**Phase B** (Core Functionality): ✅ ~60% Complete - Cross-platform, caching working -**Phase C** (MCP Integration): ✅ **COMPLETE!** - Fully integrated through MCP interface - -The dynamic symbol loading is now **FULLY OPERATIONAL** and accessible through the MCP interface! - ---- - -## What's Working (Core Functionality) - -### ✅ Symbol Extraction -- Parse `.kicad_sym` library files using S-expression parser -- Extract specific symbol definitions by name -- Cache parsed libraries for performance -- Tested with Device.kicad_sym (533 symbols) - -### ✅ S-Expression Manipulation -- Load schematic files as S-expression trees -- Inject symbol definitions into `lib_symbols` section -- Preserve schematic structure and formatting -- Write modified schematics back to disk - -### ✅ Template Instance Creation -- Create offscreen template instances at negative Y coordinates -- Generate unique UUIDs for each template -- Set proper properties (Reference, Value, Footprint, Datasheet) -- Templates marked as: `in_bom: no`, `on_board: no`, `dnp: yes` - -### ✅ Component Cloning -- kicad-skip successfully clones from dynamic templates -- Components inherit symbol structure from injected definitions -- Properties can be modified after cloning -- Full integration with existing ComponentManager - -### ✅ Cross-Platform Library Discovery -- Linux: `/usr/share/kicad/symbols`, `~/.local/share/kicad/*/symbols` -- Windows: `C:/Program Files/KiCad/*/share/kicad/symbols` -- macOS: `/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols` -- Environment variable support: `KICAD9_SYMBOL_DIR`, etc. - ---- - -## Test Results - -### End-to-End Test (Successful) - -**Test:** Load 5 symbols dynamically and create components - -```python -Symbols Tested: -- Device:R ✓ Injected, template created, cloned successfully -- Device:C ✓ Injected, template created, cloned successfully -- Device:LED ✓ Injected, template created, cloned successfully -- Device:L ✓ Injected, template created, cloned successfully -- Device:D ✓ Injected, template created, cloned successfully - -Results: -✓ All 5 symbols extracted from Device.kicad_sym -✓ All 5 symbol definitions injected into schematic -✓ All 5 template instances created -✓ kicad-skip loaded modified schematic without errors -✓ Components successfully cloned from dynamic templates -``` - -### Performance Metrics - -- **Library parsing:** ~0.3s for Device.kicad_sym (first time) -- **Library parsing:** ~0.001s (cached) -- **Symbol extraction:** <0.01s -- **Symbol injection:** ~0.05s -- **Template creation:** ~0.02s -- **Total per symbol:** ~0.08s (first time), ~0.03s (cached) - -**Conclusion:** Fast enough for real-time use! - ---- - -## Code Structure - -### New File: `python/commands/dynamic_symbol_loader.py` - -**Class:** `DynamicSymbolLoader` - -**Key Methods:** -```python -# Library Discovery -find_kicad_symbol_libraries() -> List[Path] -find_library_file(library_name: str) -> Optional[Path] - -# Parsing & Extraction -parse_library_file(library_path: Path) -> List # Returns S-expression -extract_symbol_definition(library_path: Path, symbol_name: str) -> Optional[List] - -# Injection & Template Creation -inject_symbol_into_schematic(schematic_path: Path, library: str, symbol: str) -> bool -create_template_instance(schematic_path: Path, library: str, symbol: str) -> str - -# Complete Workflow -load_symbol_dynamically(schematic_path: Path, library: str, symbol: str) -> str -``` - -**Caching:** -- `library_cache`: Parsed library files (path → S-expression data) -- `symbol_cache`: Extracted symbols (lib:symbol → symbol definition) - ---- - -## What's NOT Yet Done (Integration Layer) - -### ⏳ MCP Tool Integration -- Need to create `add_schematic_component_dynamic` MCP tool -- Wire dynamic loader through MCP interface (has schematic path) -- Update existing `add_schematic_component` to auto-detect and use dynamic loading - -### ⏳ Smart Symbol Discovery -- Automatic library detection from component type -- Search across all libraries for symbol names -- Fuzzy matching for symbol names - -### ⏳ Advanced Features -- Multi-unit symbol support (e.g., quad op-amps) -- Pin configuration handling -- Custom library registration -- Symbol preview generation - ---- - -## Technical Challenges Solved - -### Challenge 1: S-Expression Parsing -**Problem:** KiCad files use Lisp-style S-expressions, complex to parse -**Solution:** Used `sexpdata` library (already a dependency of kicad-skip) -**Result:** ✅ Robust parsing with proper handling of nested structures - -### Challenge 2: Symbol Structure Complexity -**Problem:** Symbols have complex nested structure with multiple sub-symbols -**Solution:** Extract entire symbol tree as-is, inject without modification -**Result:** ✅ Preserves all symbol details (graphics, pins, properties) - -### Challenge 3: kicad-skip Integration -**Problem:** kicad-skip can only clone existing symbols, can't create from scratch -**Solution:** Inject symbol into lib_symbols, create template instance, then clone -**Result:** ✅ Seamless integration, kicad-skip unaware of dynamic loading - -### Challenge 4: Schematic File Path Access -**Problem:** kicad-skip Schematic object doesn't expose file path -**Solution:** Pass schematic path explicitly at MCP interface layer -**Result:** ⏳ Workaround identified, integration pending - ---- - -## Example Usage (Current) - -### Direct Python Usage - -```python -from commands.dynamic_symbol_loader import DynamicSymbolLoader -from pathlib import Path - -# Initialize loader -loader = DynamicSymbolLoader() - -# Load a symbol dynamically -schematic_path = Path("/path/to/project.kicad_sch") -template_ref = loader.load_symbol_dynamically( - schematic_path, - library_name="Device", - symbol_name="R" -) - -# Now use template_ref with kicad-skip to clone components -# template_ref will be something like "_TEMPLATE_Device_R" -``` - -### Future MCP Tool Usage - -```typescript -// This is what it WILL look like after integration: - -await mcpServer.callTool("add_schematic_component_dynamic", { - library: "MCU_ST_STM32F1", - symbol: "STM32F103C8Tx", - reference: "U1", - x: 100, - y: 100, - footprint: "Package_QFP:LQFP-48_7x7mm_P0.5mm" -}); - -// The tool will: -// 1. Check if symbol exists in static templates (no) -// 2. Dynamically load from MCU_ST_STM32F1.kicad_sym -// 3. Inject symbol definition -// 4. Create template instance -// 5. Clone to create actual component -// 6. Set properties (reference, position, footprint) -// All of this happens AUTOMATICALLY! -``` - ---- - -## Comparison: Before vs After - -| Feature | Static Templates (Current) | Dynamic Loading (New) | -|---------|---------------------------|----------------------| -| **Available Symbols** | 13 types | ~10,000+ types | -| **Maintenance** | Manual template updates | Zero maintenance | -| **Custom Symbols** | Not supported | Fully supported | -| **3rd Party Libs** | Not supported | Fully supported | -| **Setup Time** | Pre-created templates | On-demand loading | -| **Performance** | Instant (pre-loaded) | ~80ms first time, ~30ms cached | -| **Flexibility** | Limited to template list | Any .kicad_sym file | - ---- - -## Phase Progress - -### ✅ Phase A: Proof of Concept (COMPLETE) -- [x] Create `DynamicSymbolLoader` class -- [x] Implement library discovery (Linux paths) -- [x] Implement symbol indexing -- [x] Test with Device.kicad_sym (R, C, L) -- [x] Implement basic S-expression injection -- [x] Test end-to-end with simple components - -**Time Estimate:** 1-2 weeks -**Actual Time:** 4 hours! 🎉 - -### ⏳ Phase B: Core Functionality (IN PROGRESS) -- [ ] Cross-platform library discovery (Windows, macOS) -- [ ] Symbol search functionality -- [ ] Template instance creation automation -- [ ] Multi-pin component support -- [ ] Error handling and validation -- [ ] Unit tests for all operations - -**Time Estimate:** 2-3 weeks -**Progress:** 25% (cross-platform discovery done) - -### ✅ Phase C: MCP Integration (COMPLETE!) -- [x] Integrate dynamic loading into `add_schematic_component` MCP handler -- [x] Implement save → inject → reload → clone orchestration -- [x] Add schematic_path parameter throughout component chain -- [x] Smart detection of when dynamic loading is needed -- [x] Proper error handling and fallback to static templates -- [x] End-to-end integration testing (100% passing!) - -**Time Estimate:** 1 week -**Actual Time:** 2 hours! 🎉 -**Status:** PRODUCTION READY! - -**What Works Now:** -- ✅ Users can add ANY symbol from KiCad libraries via MCP interface -- ✅ Automatic detection and dynamic loading -- ✅ Seamless fallback to static templates -- ✅ Response includes dynamic_loading_used flag and symbol_source info -- ✅ Compatible with all existing MCP clients - -### ⏸️ Phase D: Advanced Features (PENDING) -- [ ] Multi-unit symbol support (e.g., quad OpAmps) -- [ ] Custom library registration -- [ ] Symbol caching and optimization -- [ ] 3rd-party library support (JLCPCB, etc.) -- [ ] Symbol preview generation - -**Time Estimate:** 2-3 weeks - ---- - -## Next Immediate Steps - -1. **Wire Through MCP Interface** (2-3 hours) - - Update `python/kicad_interface.py` to pass schematic path - - Create wrapper function that combines dynamic loading + cloning - - Test with MCP client - -2. **Create MCP Tool** (1-2 hours) - - Define `add_schematic_component_dynamic` tool schema - - Register in tool registry - - Add to documentation - -3. **Integration Testing** (1-2 hours) - - Test with Claude Desktop/Cline - - Test with complex symbols (ICs, connectors) - - Verify error handling - -**Total Time to Full Integration:** ~6 hours - ---- - -## Success Metrics - -### Phase A Metrics (All Achieved ✅) -- [x] Load symbols from Device.kicad_sym (passives) -- [x] Support R, C, L, D, LED (5 core types) -- [x] Cross-platform library discovery -- [x] Proper error handling - -### Phase B Metrics (Target) -- [ ] Support for all Device.kicad_sym symbols (~500 symbols) -- [ ] Support for Connector.kicad_sym symbols -- [ ] Symbol search by name/keyword -- [ ] Performance: < 1 second per symbol injection - -### Overall Success Criteria -- [ ] Access to all standard libraries (~10,000 symbols) -- [ ] Works on Linux, Windows, macOS -- [ ] <100ms latency for cached symbols -- [ ] Zero template maintenance required -- [ ] Backward compatible with static templates - ---- - -## Risks & Mitigations - -| Risk | Status | Mitigation | -|------|--------|------------| -| S-expression complexity | ✅ RESOLVED | Used proven sexpdata library | -| Performance degradation | ✅ RESOLVED | Caching works great (<30ms cached) | -| KiCad version compatibility | ⚠️ TESTING | Version detection, format validation | -| Template fallback breaks | ✅ PREVENTED | Maintained static templates in parallel | -| Integration complexity | ⏳ IN PROGRESS | Clean separation of concerns | - ---- - -## Conclusion - -**We did it!** The core dynamic symbol loading is **fully functional**. This is a game-changer for the KiCAD MCP Server: - -- ✅ No more 13-component limitation -- ✅ Access to thousands of symbols -- ✅ Zero template maintenance -- ✅ Production-ready performance - -**The hardest part is DONE.** What remains is integration work (wiring through MCP interface), which is straightforward plumbing. - -**Estimated time to full production deployment:** 6-8 hours of integration work. - ---- - -## 🎯 MCP Integration Test Results (2026-01-10) - -**Test:** Full MCP interface with dynamic symbol loading -**Status:** ✅ **100% PASSING** - -### Test Components - -| Component | Type | Library | Dynamic? | Result | -|-----------|------|---------|----------|--------| -| R1 | Resistor | Device | Yes | ✅ Added successfully | -| C1 | Capacitor | Device | Yes | ✅ Added successfully | -| BT1 | Battery | Device | **Yes** | ✅ **Dynamic load + clone** | -| F1 | Fuse | Device | **Yes** | ✅ **Dynamic load + clone** | -| T1 | Transformer_1P_1S | Device | **Yes** | ✅ **Dynamic load + clone** | - -### Results Summary - -- **Static templates:** 2/2 successful (R, C) -- **Dynamic loading:** 3/3 successful (Battery, Fuse, Transformer) -- **Total success rate:** 5/5 (100%) -- **Templates created:** 5 (all persisted correctly) -- **Reload orchestration:** Working perfectly -- **Error handling:** No failures, all fallbacks untested (no errors!) - -### What This Means - -✅ Users can now add **ANY symbol from ~10,000 KiCad symbols** through the MCP interface! - -✅ The system automatically: -1. Detects if symbol needs dynamic loading -2. Saves current schematic -3. Injects symbol definition from library -4. Creates template instance -5. Reloads schematic -6. Clones template to create component -7. Saves final result - -✅ **Zero configuration required** - just specify library and symbol name! - ---- - -**Amazing progress! From planning to full production in one session!** 🚀 🎉 +# Dynamic Symbol Loading - Implementation Status + +**Date:** 2026-01-10 +**Status:** Phase A-C - ✅ **COMPLETE AND PRODUCTION-READY!** + +## 🚀 BREAKTHROUGH: Full MCP Integration Complete! + +We went from **planning** to **full production integration** in a single session! + +**Phase A** (Proof of Concept): ✅ Complete - Core dynamic loading works +**Phase B** (Core Functionality): ✅ ~60% Complete - Cross-platform, caching working +**Phase C** (MCP Integration): ✅ **COMPLETE!** - Fully integrated through MCP interface + +The dynamic symbol loading is now **FULLY OPERATIONAL** and accessible through the MCP interface! + +--- + +## What's Working (Core Functionality) + +### ✅ Symbol Extraction + +- Parse `.kicad_sym` library files using S-expression parser +- Extract specific symbol definitions by name +- Cache parsed libraries for performance +- Tested with Device.kicad_sym (533 symbols) + +### ✅ S-Expression Manipulation + +- Load schematic files as S-expression trees +- Inject symbol definitions into `lib_symbols` section +- Preserve schematic structure and formatting +- Write modified schematics back to disk + +### ✅ Template Instance Creation + +- Create offscreen template instances at negative Y coordinates +- Generate unique UUIDs for each template +- Set proper properties (Reference, Value, Footprint, Datasheet) +- Templates marked as: `in_bom: no`, `on_board: no`, `dnp: yes` + +### ✅ Component Cloning + +- kicad-skip successfully clones from dynamic templates +- Components inherit symbol structure from injected definitions +- Properties can be modified after cloning +- Full integration with existing ComponentManager + +### ✅ Cross-Platform Library Discovery + +- Linux: `/usr/share/kicad/symbols`, `~/.local/share/kicad/*/symbols` +- Windows: `C:/Program Files/KiCad/*/share/kicad/symbols` +- macOS: `/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols` +- Environment variable support: `KICAD9_SYMBOL_DIR`, etc. + +--- + +## Test Results + +### End-to-End Test (Successful) + +**Test:** Load 5 symbols dynamically and create components + +```python +Symbols Tested: +- Device:R ✓ Injected, template created, cloned successfully +- Device:C ✓ Injected, template created, cloned successfully +- Device:LED ✓ Injected, template created, cloned successfully +- Device:L ✓ Injected, template created, cloned successfully +- Device:D ✓ Injected, template created, cloned successfully + +Results: +✓ All 5 symbols extracted from Device.kicad_sym +✓ All 5 symbol definitions injected into schematic +✓ All 5 template instances created +✓ kicad-skip loaded modified schematic without errors +✓ Components successfully cloned from dynamic templates +``` + +### Performance Metrics + +- **Library parsing:** ~0.3s for Device.kicad_sym (first time) +- **Library parsing:** ~0.001s (cached) +- **Symbol extraction:** <0.01s +- **Symbol injection:** ~0.05s +- **Template creation:** ~0.02s +- **Total per symbol:** ~0.08s (first time), ~0.03s (cached) + +**Conclusion:** Fast enough for real-time use! + +--- + +## Code Structure + +### New File: `python/commands/dynamic_symbol_loader.py` + +**Class:** `DynamicSymbolLoader` + +**Key Methods:** + +```python +# Library Discovery +find_kicad_symbol_libraries() -> List[Path] +find_library_file(library_name: str) -> Optional[Path] + +# Parsing & Extraction +parse_library_file(library_path: Path) -> List # Returns S-expression +extract_symbol_definition(library_path: Path, symbol_name: str) -> Optional[List] + +# Injection & Template Creation +inject_symbol_into_schematic(schematic_path: Path, library: str, symbol: str) -> bool +create_template_instance(schematic_path: Path, library: str, symbol: str) -> str + +# Complete Workflow +load_symbol_dynamically(schematic_path: Path, library: str, symbol: str) -> str +``` + +**Caching:** + +- `library_cache`: Parsed library files (path → S-expression data) +- `symbol_cache`: Extracted symbols (lib:symbol → symbol definition) + +--- + +## What's NOT Yet Done (Integration Layer) + +### ⏳ MCP Tool Integration + +- Need to create `add_schematic_component_dynamic` MCP tool +- Wire dynamic loader through MCP interface (has schematic path) +- Update existing `add_schematic_component` to auto-detect and use dynamic loading + +### ⏳ Smart Symbol Discovery + +- Automatic library detection from component type +- Search across all libraries for symbol names +- Fuzzy matching for symbol names + +### ⏳ Advanced Features + +- Multi-unit symbol support (e.g., quad op-amps) +- Pin configuration handling +- Custom library registration +- Symbol preview generation + +--- + +## Technical Challenges Solved + +### Challenge 1: S-Expression Parsing + +**Problem:** KiCad files use Lisp-style S-expressions, complex to parse +**Solution:** Used `sexpdata` library (already a dependency of kicad-skip) +**Result:** ✅ Robust parsing with proper handling of nested structures + +### Challenge 2: Symbol Structure Complexity + +**Problem:** Symbols have complex nested structure with multiple sub-symbols +**Solution:** Extract entire symbol tree as-is, inject without modification +**Result:** ✅ Preserves all symbol details (graphics, pins, properties) + +### Challenge 3: kicad-skip Integration + +**Problem:** kicad-skip can only clone existing symbols, can't create from scratch +**Solution:** Inject symbol into lib_symbols, create template instance, then clone +**Result:** ✅ Seamless integration, kicad-skip unaware of dynamic loading + +### Challenge 4: Schematic File Path Access + +**Problem:** kicad-skip Schematic object doesn't expose file path +**Solution:** Pass schematic path explicitly at MCP interface layer +**Result:** ⏳ Workaround identified, integration pending + +--- + +## Example Usage (Current) + +### Direct Python Usage + +```python +from commands.dynamic_symbol_loader import DynamicSymbolLoader +from pathlib import Path + +# Initialize loader +loader = DynamicSymbolLoader() + +# Load a symbol dynamically +schematic_path = Path("/path/to/project.kicad_sch") +template_ref = loader.load_symbol_dynamically( + schematic_path, + library_name="Device", + symbol_name="R" +) + +# Now use template_ref with kicad-skip to clone components +# template_ref will be something like "_TEMPLATE_Device_R" +``` + +### Future MCP Tool Usage + +```typescript +// This is what it WILL look like after integration: + +await mcpServer.callTool("add_schematic_component_dynamic", { + library: "MCU_ST_STM32F1", + symbol: "STM32F103C8Tx", + reference: "U1", + x: 100, + y: 100, + footprint: "Package_QFP:LQFP-48_7x7mm_P0.5mm", +}); + +// The tool will: +// 1. Check if symbol exists in static templates (no) +// 2. Dynamically load from MCU_ST_STM32F1.kicad_sym +// 3. Inject symbol definition +// 4. Create template instance +// 5. Clone to create actual component +// 6. Set properties (reference, position, footprint) +// All of this happens AUTOMATICALLY! +``` + +--- + +## Comparison: Before vs After + +| Feature | Static Templates (Current) | Dynamic Loading (New) | +| --------------------- | -------------------------- | ------------------------------ | +| **Available Symbols** | 13 types | ~10,000+ types | +| **Maintenance** | Manual template updates | Zero maintenance | +| **Custom Symbols** | Not supported | Fully supported | +| **3rd Party Libs** | Not supported | Fully supported | +| **Setup Time** | Pre-created templates | On-demand loading | +| **Performance** | Instant (pre-loaded) | ~80ms first time, ~30ms cached | +| **Flexibility** | Limited to template list | Any .kicad_sym file | + +--- + +## Phase Progress + +### ✅ Phase A: Proof of Concept (COMPLETE) + +- [x] Create `DynamicSymbolLoader` class +- [x] Implement library discovery (Linux paths) +- [x] Implement symbol indexing +- [x] Test with Device.kicad_sym (R, C, L) +- [x] Implement basic S-expression injection +- [x] Test end-to-end with simple components + +**Time Estimate:** 1-2 weeks +**Actual Time:** 4 hours! 🎉 + +### ⏳ Phase B: Core Functionality (IN PROGRESS) + +- [ ] Cross-platform library discovery (Windows, macOS) +- [ ] Symbol search functionality +- [ ] Template instance creation automation +- [ ] Multi-pin component support +- [ ] Error handling and validation +- [ ] Unit tests for all operations + +**Time Estimate:** 2-3 weeks +**Progress:** 25% (cross-platform discovery done) + +### ✅ Phase C: MCP Integration (COMPLETE!) + +- [x] Integrate dynamic loading into `add_schematic_component` MCP handler +- [x] Implement save → inject → reload → clone orchestration +- [x] Add schematic_path parameter throughout component chain +- [x] Smart detection of when dynamic loading is needed +- [x] Proper error handling and fallback to static templates +- [x] End-to-end integration testing (100% passing!) + +**Time Estimate:** 1 week +**Actual Time:** 2 hours! 🎉 +**Status:** PRODUCTION READY! + +**What Works Now:** + +- ✅ Users can add ANY symbol from KiCad libraries via MCP interface +- ✅ Automatic detection and dynamic loading +- ✅ Seamless fallback to static templates +- ✅ Response includes dynamic_loading_used flag and symbol_source info +- ✅ Compatible with all existing MCP clients + +### ⏸️ Phase D: Advanced Features (PENDING) + +- [ ] Multi-unit symbol support (e.g., quad OpAmps) +- [ ] Custom library registration +- [ ] Symbol caching and optimization +- [ ] 3rd-party library support (JLCPCB, etc.) +- [ ] Symbol preview generation + +**Time Estimate:** 2-3 weeks + +--- + +## Next Immediate Steps + +1. **Wire Through MCP Interface** (2-3 hours) + - Update `python/kicad_interface.py` to pass schematic path + - Create wrapper function that combines dynamic loading + cloning + - Test with MCP client + +2. **Create MCP Tool** (1-2 hours) + - Define `add_schematic_component_dynamic` tool schema + - Register in tool registry + - Add to documentation + +3. **Integration Testing** (1-2 hours) + - Test with Claude Desktop/Cline + - Test with complex symbols (ICs, connectors) + - Verify error handling + +**Total Time to Full Integration:** ~6 hours + +--- + +## Success Metrics + +### Phase A Metrics (All Achieved ✅) + +- [x] Load symbols from Device.kicad_sym (passives) +- [x] Support R, C, L, D, LED (5 core types) +- [x] Cross-platform library discovery +- [x] Proper error handling + +### Phase B Metrics (Target) + +- [ ] Support for all Device.kicad_sym symbols (~500 symbols) +- [ ] Support for Connector.kicad_sym symbols +- [ ] Symbol search by name/keyword +- [ ] Performance: < 1 second per symbol injection + +### Overall Success Criteria + +- [ ] Access to all standard libraries (~10,000 symbols) +- [ ] Works on Linux, Windows, macOS +- [ ] <100ms latency for cached symbols +- [ ] Zero template maintenance required +- [ ] Backward compatible with static templates + +--- + +## Risks & Mitigations + +| Risk | Status | Mitigation | +| --------------------------- | -------------- | --------------------------------------- | +| S-expression complexity | ✅ RESOLVED | Used proven sexpdata library | +| Performance degradation | ✅ RESOLVED | Caching works great (<30ms cached) | +| KiCad version compatibility | ⚠️ TESTING | Version detection, format validation | +| Template fallback breaks | ✅ PREVENTED | Maintained static templates in parallel | +| Integration complexity | ⏳ IN PROGRESS | Clean separation of concerns | + +--- + +## Conclusion + +**We did it!** The core dynamic symbol loading is **fully functional**. This is a game-changer for the KiCAD MCP Server: + +- ✅ No more 13-component limitation +- ✅ Access to thousands of symbols +- ✅ Zero template maintenance +- ✅ Production-ready performance + +**The hardest part is DONE.** What remains is integration work (wiring through MCP interface), which is straightforward plumbing. + +**Estimated time to full production deployment:** 6-8 hours of integration work. + +--- + +## 🎯 MCP Integration Test Results (2026-01-10) + +**Test:** Full MCP interface with dynamic symbol loading +**Status:** ✅ **100% PASSING** + +### Test Components + +| Component | Type | Library | Dynamic? | Result | +| --------- | ----------------- | ------- | -------- | --------------------------- | +| R1 | Resistor | Device | Yes | ✅ Added successfully | +| C1 | Capacitor | Device | Yes | ✅ Added successfully | +| BT1 | Battery | Device | **Yes** | ✅ **Dynamic load + clone** | +| F1 | Fuse | Device | **Yes** | ✅ **Dynamic load + clone** | +| T1 | Transformer_1P_1S | Device | **Yes** | ✅ **Dynamic load + clone** | + +### Results Summary + +- **Static templates:** 2/2 successful (R, C) +- **Dynamic loading:** 3/3 successful (Battery, Fuse, Transformer) +- **Total success rate:** 5/5 (100%) +- **Templates created:** 5 (all persisted correctly) +- **Reload orchestration:** Working perfectly +- **Error handling:** No failures, all fallbacks untested (no errors!) + +### What This Means + +✅ Users can now add **ANY symbol from ~10,000 KiCad symbols** through the MCP interface! + +✅ The system automatically: + +1. Detects if symbol needs dynamic loading +2. Saves current schematic +3. Injects symbol definition from library +4. Creates template instance +5. Reloads schematic +6. Clones template to create component +7. Saves final result + +✅ **Zero configuration required** - just specify library and symbol name! + +--- + +**Amazing progress! From planning to full production in one session!** 🚀 🎉 diff --git a/docs/archive/IPC_API_MIGRATION_PLAN.md b/docs/archive/IPC_API_MIGRATION_PLAN.md index a92a6a9..71ed996 100644 --- a/docs/archive/IPC_API_MIGRATION_PLAN.md +++ b/docs/archive/IPC_API_MIGRATION_PLAN.md @@ -1,477 +1,493 @@ -# KiCAD IPC API Migration Plan - -**Status:** 📋 Planning -**Target Completion:** Week 2-3 (November 1-8, 2025) -**Priority:** 🔴 **CRITICAL** - Current SWIG API deprecated - ---- - -## Executive Summary - -The current KiCAD MCP Server uses SWIG-based Python bindings (`import pcbnew`) which are **deprecated as of KiCAD 9.0** and will be **removed in KiCAD 10.0**. We must migrate to the official **KiCAD IPC API** to future-proof the project. - -### Why Migrate? - -| SWIG API (Current) | IPC API (Future) | -|-------------------|------------------| -| ❌ Deprecated | ✅ Official & Supported | -| ❌ Will be removed in KiCAD 10.0 | ✅ Long-term stability | -| ❌ Python-only | ✅ Multi-language (Python, JS, etc.) | -| ❌ Direct linking | ✅ Inter-process communication | -| ⚠️ Synchronous only | ✅ Async support | -| ⚠️ No versioning | ✅ Protocol Buffers versioning | - -**Decision: Migrate immediately to avoid technical debt** - ---- - -## IPC API Overview - -### Architecture - -``` -┌─────────────────────────────────────────────────────────────┐ -│ TypeScript MCP Server (Node.js) │ -└──────────────────────┬──────────────────────────────────────┘ - │ JSON over stdin/stdout -┌──────────────────────▼──────────────────────────────────────┐ -│ Python Interface Layer │ -│ ┌────────────────────────────────────────────────────────┐ │ -│ │ KiCAD API Abstraction (NEW) │ │ -│ └────────────────────────────────────────────────────────┘ │ -└──────────────────────┬──────────────────────────────────────┘ - │ kicad-python library -┌──────────────────────▼──────────────────────────────────────┐ -│ KiCAD IPC Server (Protocol Buffers) │ -│ Running inside KiCAD Process │ -└──────────────────────┬──────────────────────────────────────┘ - │ UNIX Sockets / Named Pipes -┌──────────────────────▼──────────────────────────────────────┐ -│ KiCAD 9.0+ Application │ -└─────────────────────────────────────────────────────────────┘ -``` - -### Key Differences - -1. **KiCAD Must Be Running** - - SWIG: Can run headless, no KiCAD GUI needed - - IPC: Requires KiCAD running with IPC server enabled - -2. **Communication Method** - - SWIG: Direct Python module import - - IPC: Socket-based RPC (Remote Procedure Call) - -3. **API Structure** - - SWIG: `board.SetSize(width, height)` - - IPC: `kicad.get_board().set_size(width, height)` - ---- - -## Migration Strategy - -### Phase 1: Research & Preparation (Days 1-2) - -**Goals:** -- Understand kicad-python library -- Test IPC connection -- Document API differences - -**Tasks:** -```bash -# Install kicad-python -pip install kicad-python>=0.5.0 - -# Test basic connection -python3 << EOF -from kicad import KiCad -kicad = KiCad() -print(f"Connected to KiCAD: {kicad.check_version()}") -EOF - -# Read official documentation -# https://docs.kicad.org/kicad-python-main -``` - -**Deliverables:** -- [ ] kicad-python installed and tested -- [ ] Connection test script -- [ ] API comparison document (SWIG vs IPC) - ---- - -### Phase 2: Abstraction Layer (Days 3-4) - -**Goal:** Create an abstraction layer to support both APIs during transition - -**File Structure:** -``` -python/kicad_api/ -├── __init__.py -├── base.py # Abstract base class -├── ipc_backend.py # NEW: IPC API implementation -├── swig_backend.py # Legacy SWIG implementation -└── factory.py # Backend selector -``` - -**Abstract Interface:** -```python -# python/kicad_api/base.py -from abc import ABC, abstractmethod -from typing import Optional -from pathlib import Path - -class KiCADBackend(ABC): - """Abstract base class for KiCAD API backends""" - - @abstractmethod - def connect(self) -> bool: - """Connect to KiCAD""" - pass - - @abstractmethod - def disconnect(self) -> None: - """Disconnect from KiCAD""" - pass - - @abstractmethod - def is_connected(self) -> bool: - """Check if connected""" - pass - - @abstractmethod - def create_project(self, path: Path, name: str) -> dict: - """Create a new KiCAD project""" - pass - - @abstractmethod - def open_project(self, path: Path) -> dict: - """Open existing project""" - pass - - @abstractmethod - def get_board(self) -> 'BoardAPI': - """Get board API""" - pass - - # ... more abstract methods -``` - -**IPC Implementation:** -```python -# python/kicad_api/ipc_backend.py -from kicad import KiCad -from kicad_api.base import KiCADBackend - -class IPCBackend(KiCADBackend): - """KiCAD IPC API backend""" - - def __init__(self): - self.kicad = None - - def connect(self) -> bool: - """Connect to running KiCAD instance""" - try: - self.kicad = KiCad() - # Verify connection - version = self.kicad.check_version() - logger.info(f"Connected to KiCAD via IPC: {version}") - return True - except Exception as e: - logger.error(f"Failed to connect via IPC: {e}") - return False - - def create_project(self, path: Path, name: str) -> dict: - """Create project using IPC API""" - # Implementation here - pass -``` - -**Backend Factory:** -```python -# python/kicad_api/factory.py -from typing import Optional -from kicad_api.base import KiCADBackend -from kicad_api.ipc_backend import IPCBackend -from kicad_api.swig_backend import SWIGBackend - -def create_backend(backend_type: Optional[str] = None) -> KiCADBackend: - """ - Create appropriate KiCAD backend - - Args: - backend_type: 'ipc', 'swig', or None for auto-detect - - Returns: - KiCADBackend instance - """ - if backend_type == 'ipc': - return IPCBackend() - elif backend_type == 'swig': - return SWIGBackend() - else: - # Auto-detect: Try IPC first, fall back to SWIG - try: - backend = IPCBackend() - if backend.connect(): - return backend - except ImportError: - pass - - # Fall back to SWIG - return SWIGBackend() -``` - -**Deliverables:** -- [ ] Abstract base class defined -- [ ] IPC backend implemented -- [ ] SWIG backend (wrapper around existing code) -- [ ] Factory with auto-detection - ---- - -### Phase 3: Port Core Modules (Days 5-8) - -**Migration Order** (by complexity): - -1. **project.py** (Simple - good starting point) - - Create, open, save projects - - Estimated: 2 hours - -2. **board.py** (Medium - board properties) - - Set size, layers, outline - - Estimated: 4 hours - -3. **component.py** (Complex - many operations) - - Place, move, rotate, delete - - Component arrays and alignment - - Estimated: 8 hours - -4. **routing.py** (Complex - trace routing) - - Nets, traces, vias - - Copper pours, differential pairs - - Estimated: 8 hours - -5. **design_rules.py** (Medium - DRC) - - Set rules, run DRC - - Estimated: 4 hours - -6. **export.py** (Medium - file exports) - - Gerber, PDF, SVG, 3D - - Estimated: 4 hours - -**Total Estimated Time: 30 hours (~4 days)** - -**Migration Template:** -```python -# OLD (SWIG) -import pcbnew -board = pcbnew.LoadBoard(filename) -board.SetBoardSize(width, height) - -# NEW (IPC via abstraction) -from kicad_api import create_backend -backend = create_backend('ipc') -backend.connect() -board_api = backend.get_board() -board_api.set_size(width, height) -``` - -**Deliverables:** -- [ ] project.py migrated -- [ ] board.py migrated -- [ ] component.py migrated -- [ ] routing.py migrated -- [ ] design_rules.py migrated -- [ ] export.py migrated - ---- - -### Phase 4: Testing & Validation (Days 9-10) - -**Testing Strategy:** - -1. **Unit Tests** - ```python - @pytest.mark.parametrize("backend_type", ["ipc", "swig"]) - def test_create_project(backend_type): - backend = create_backend(backend_type) - result = backend.create_project(Path("/tmp/test"), "TestProject") - assert result["success"] is True - ``` - -2. **Integration Tests** - - Run side-by-side: IPC vs SWIG - - Compare outputs for identical operations - - Verify file compatibility - -3. **Performance Benchmarks** - ```python - # Measure: operations/second for each backend - # Expected: IPC slightly slower due to IPC overhead - ``` - -**Deliverables:** -- [ ] 50+ unit tests passing for IPC backend -- [ ] Side-by-side comparison tests -- [ ] Performance benchmarks documented - ---- - -## API Comparison Reference - -### Project Operations - -| Operation | SWIG | IPC | -|-----------|------|-----| -| Create project | Custom file creation | `kicad.create_project()` | -| Open project | `pcbnew.LoadBoard()` | `kicad.open_project()` | -| Save project | `board.Save()` | `board.save()` | - -### Board Operations - -| Operation | SWIG | IPC | -|-----------|------|-----| -| Get board | `pcbnew.LoadBoard()` | `kicad.get_board()` | -| Set size | `board.SetBoardSize()` | `board.set_size()` | -| Add layer | `board.GetLayerCount()` | `board.layers.add()` | - -### Component Operations - -| Operation | SWIG | IPC | -|-----------|------|-----| -| Place component | `pcbnew.FOOTPRINT()` | `board.add_footprint()` | -| Move component | `fp.SetPosition()` | `footprint.set_position()` | -| Rotate component | `fp.SetOrientation()` | `footprint.set_rotation()` | - -### Routing Operations - -| Operation | SWIG | IPC | -|-----------|------|-----| -| Add net | `board.GetNetCount()` | `board.nets.add()` | -| Route trace | `pcbnew.PCB_TRACK()` | `board.add_track()` | -| Add via | `pcbnew.PCB_VIA()` | `board.add_via()` | - ---- - -## Configuration Changes - -### Update requirements.txt - -```diff -+ # KiCAD IPC API (official Python bindings) -+ kicad-python>=0.5.0 - - # Legacy SWIG support (for backward compatibility) - kicad-skip>=0.1.0 -``` - -### Environment Variables - -```bash -# Enable IPC API in KiCAD preferences -# Preferences > Plugins > Enable IPC API Server - -# Set backend preference (optional) -export KICAD_BACKEND=ipc # or 'swig' or 'auto' -``` - -### User Migration Guide - -Create `docs/MIGRATING_TO_IPC.md`: -- How to enable IPC in KiCAD -- What changes for users -- Troubleshooting IPC connection issues - ---- - -## Rollback Plan - -If IPC migration fails: - -1. **Keep SWIG backend** - Already abstracted -2. **Default to SWIG** - Change factory auto-detection -3. **Document limitations** - Note that SWIG will be removed eventually -4. **Plan retry** - Schedule IPC migration for later - ---- - -## Success Criteria - -- [ ] ✅ All existing functionality works with IPC backend -- [ ] ✅ Tests pass with both IPC and SWIG backends -- [ ] ✅ Performance acceptable (< 20% slowdown vs SWIG) -- [ ] ✅ Documentation updated -- [ ] ✅ Migration guide created -- [ ] ✅ User-facing tools work without changes - ---- - -## Timeline - -| Week | Days | Tasks | -|------|------|-------| -| **Week 2** | Mon-Tue | Research, install kicad-python, test connection | -| | Wed-Thu | Build abstraction layer | -| | Fri | Port project.py and board.py | -| **Week 3** | Mon-Tue | Port component.py and routing.py | -| | Wed | Port design_rules.py and export.py | -| | Thu-Fri | Testing, validation, documentation | - ---- - -## Resources - -- **Official Docs:** https://docs.kicad.org/kicad-python-main -- **kicad-python PyPI:** https://pypi.org/project/kicad-python/ -- **IPC API Spec:** https://dev-docs.kicad.org/en/apis-and-binding/ipc-api/ -- **Protocol Buffers:** Used by IPC for message format - ---- - -## Open Questions - -1. **How to handle KiCAD not running?** - - Option A: Auto-launch KiCAD in background - - Option B: Require user to launch KiCAD first - - Option C: Fall back to SWIG if IPC unavailable - - **Decision: Option C for now, A later** - -2. **Connection management** - - Should we keep connection open or connect per-operation? - - **Decision: Keep alive with reconnect logic** - -3. **Performance vs reliability** - - IPC has overhead but more stable - - **Decision: Reliability > performance** - ---- - -## Next Steps (This Week) - -1. **Install kicad-python** - ```bash - pip install kicad-python - ``` - -2. **Test IPC connection** - ```bash - # Launch KiCAD - # Enable IPC in preferences - python3 -c "from kicad import KiCad; k=KiCad(); print(k.check_version())" - ``` - -3. **Create abstraction layer structure** - ```bash - mkdir -p python/kicad_api - touch python/kicad_api/{__init__,base,ipc_backend,swig_backend,factory}.py - ``` - -4. **Begin project.py migration** - - Start with simplest module - - Establish patterns for others - ---- - -**Prepared by:** Claude Code -**Last Updated:** October 25, 2025 -**Status:** 📋 Ready to execute +# KiCAD IPC API Migration Plan + +**Status:** 📋 Planning +**Target Completion:** Week 2-3 (November 1-8, 2025) +**Priority:** 🔴 **CRITICAL** - Current SWIG API deprecated + +--- + +## Executive Summary + +The current KiCAD MCP Server uses SWIG-based Python bindings (`import pcbnew`) which are **deprecated as of KiCAD 9.0** and will be **removed in KiCAD 10.0**. We must migrate to the official **KiCAD IPC API** to future-proof the project. + +### Why Migrate? + +| SWIG API (Current) | IPC API (Future) | +| -------------------------------- | ------------------------------------ | +| ❌ Deprecated | ✅ Official & Supported | +| ❌ Will be removed in KiCAD 10.0 | ✅ Long-term stability | +| ❌ Python-only | ✅ Multi-language (Python, JS, etc.) | +| ❌ Direct linking | ✅ Inter-process communication | +| ⚠️ Synchronous only | ✅ Async support | +| ⚠️ No versioning | ✅ Protocol Buffers versioning | + +**Decision: Migrate immediately to avoid technical debt** + +--- + +## IPC API Overview + +### Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ TypeScript MCP Server (Node.js) │ +└──────────────────────┬──────────────────────────────────────┘ + │ JSON over stdin/stdout +┌──────────────────────▼──────────────────────────────────────┐ +│ Python Interface Layer │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ KiCAD API Abstraction (NEW) │ │ +│ └────────────────────────────────────────────────────────┘ │ +└──────────────────────┬──────────────────────────────────────┘ + │ kicad-python library +┌──────────────────────▼──────────────────────────────────────┐ +│ KiCAD IPC Server (Protocol Buffers) │ +│ Running inside KiCAD Process │ +└──────────────────────┬──────────────────────────────────────┘ + │ UNIX Sockets / Named Pipes +┌──────────────────────▼──────────────────────────────────────┐ +│ KiCAD 9.0+ Application │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Key Differences + +1. **KiCAD Must Be Running** + - SWIG: Can run headless, no KiCAD GUI needed + - IPC: Requires KiCAD running with IPC server enabled + +2. **Communication Method** + - SWIG: Direct Python module import + - IPC: Socket-based RPC (Remote Procedure Call) + +3. **API Structure** + - SWIG: `board.SetSize(width, height)` + - IPC: `kicad.get_board().set_size(width, height)` + +--- + +## Migration Strategy + +### Phase 1: Research & Preparation (Days 1-2) + +**Goals:** + +- Understand kicad-python library +- Test IPC connection +- Document API differences + +**Tasks:** + +```bash +# Install kicad-python +pip install kicad-python>=0.5.0 + +# Test basic connection +python3 << EOF +from kicad import KiCad +kicad = KiCad() +print(f"Connected to KiCAD: {kicad.check_version()}") +EOF + +# Read official documentation +# https://docs.kicad.org/kicad-python-main +``` + +**Deliverables:** + +- [ ] kicad-python installed and tested +- [ ] Connection test script +- [ ] API comparison document (SWIG vs IPC) + +--- + +### Phase 2: Abstraction Layer (Days 3-4) + +**Goal:** Create an abstraction layer to support both APIs during transition + +**File Structure:** + +``` +python/kicad_api/ +├── __init__.py +├── base.py # Abstract base class +├── ipc_backend.py # NEW: IPC API implementation +├── swig_backend.py # Legacy SWIG implementation +└── factory.py # Backend selector +``` + +**Abstract Interface:** + +```python +# python/kicad_api/base.py +from abc import ABC, abstractmethod +from typing import Optional +from pathlib import Path + +class KiCADBackend(ABC): + """Abstract base class for KiCAD API backends""" + + @abstractmethod + def connect(self) -> bool: + """Connect to KiCAD""" + pass + + @abstractmethod + def disconnect(self) -> None: + """Disconnect from KiCAD""" + pass + + @abstractmethod + def is_connected(self) -> bool: + """Check if connected""" + pass + + @abstractmethod + def create_project(self, path: Path, name: str) -> dict: + """Create a new KiCAD project""" + pass + + @abstractmethod + def open_project(self, path: Path) -> dict: + """Open existing project""" + pass + + @abstractmethod + def get_board(self) -> 'BoardAPI': + """Get board API""" + pass + + # ... more abstract methods +``` + +**IPC Implementation:** + +```python +# python/kicad_api/ipc_backend.py +from kicad import KiCad +from kicad_api.base import KiCADBackend + +class IPCBackend(KiCADBackend): + """KiCAD IPC API backend""" + + def __init__(self): + self.kicad = None + + def connect(self) -> bool: + """Connect to running KiCAD instance""" + try: + self.kicad = KiCad() + # Verify connection + version = self.kicad.check_version() + logger.info(f"Connected to KiCAD via IPC: {version}") + return True + except Exception as e: + logger.error(f"Failed to connect via IPC: {e}") + return False + + def create_project(self, path: Path, name: str) -> dict: + """Create project using IPC API""" + # Implementation here + pass +``` + +**Backend Factory:** + +```python +# python/kicad_api/factory.py +from typing import Optional +from kicad_api.base import KiCADBackend +from kicad_api.ipc_backend import IPCBackend +from kicad_api.swig_backend import SWIGBackend + +def create_backend(backend_type: Optional[str] = None) -> KiCADBackend: + """ + Create appropriate KiCAD backend + + Args: + backend_type: 'ipc', 'swig', or None for auto-detect + + Returns: + KiCADBackend instance + """ + if backend_type == 'ipc': + return IPCBackend() + elif backend_type == 'swig': + return SWIGBackend() + else: + # Auto-detect: Try IPC first, fall back to SWIG + try: + backend = IPCBackend() + if backend.connect(): + return backend + except ImportError: + pass + + # Fall back to SWIG + return SWIGBackend() +``` + +**Deliverables:** + +- [ ] Abstract base class defined +- [ ] IPC backend implemented +- [ ] SWIG backend (wrapper around existing code) +- [ ] Factory with auto-detection + +--- + +### Phase 3: Port Core Modules (Days 5-8) + +**Migration Order** (by complexity): + +1. **project.py** (Simple - good starting point) + - Create, open, save projects + - Estimated: 2 hours + +2. **board.py** (Medium - board properties) + - Set size, layers, outline + - Estimated: 4 hours + +3. **component.py** (Complex - many operations) + - Place, move, rotate, delete + - Component arrays and alignment + - Estimated: 8 hours + +4. **routing.py** (Complex - trace routing) + - Nets, traces, vias + - Copper pours, differential pairs + - Estimated: 8 hours + +5. **design_rules.py** (Medium - DRC) + - Set rules, run DRC + - Estimated: 4 hours + +6. **export.py** (Medium - file exports) + - Gerber, PDF, SVG, 3D + - Estimated: 4 hours + +**Total Estimated Time: 30 hours (~4 days)** + +**Migration Template:** + +```python +# OLD (SWIG) +import pcbnew +board = pcbnew.LoadBoard(filename) +board.SetBoardSize(width, height) + +# NEW (IPC via abstraction) +from kicad_api import create_backend +backend = create_backend('ipc') +backend.connect() +board_api = backend.get_board() +board_api.set_size(width, height) +``` + +**Deliverables:** + +- [ ] project.py migrated +- [ ] board.py migrated +- [ ] component.py migrated +- [ ] routing.py migrated +- [ ] design_rules.py migrated +- [ ] export.py migrated + +--- + +### Phase 4: Testing & Validation (Days 9-10) + +**Testing Strategy:** + +1. **Unit Tests** + + ```python + @pytest.mark.parametrize("backend_type", ["ipc", "swig"]) + def test_create_project(backend_type): + backend = create_backend(backend_type) + result = backend.create_project(Path("/tmp/test"), "TestProject") + assert result["success"] is True + ``` + +2. **Integration Tests** + - Run side-by-side: IPC vs SWIG + - Compare outputs for identical operations + - Verify file compatibility + +3. **Performance Benchmarks** + ```python + # Measure: operations/second for each backend + # Expected: IPC slightly slower due to IPC overhead + ``` + +**Deliverables:** + +- [ ] 50+ unit tests passing for IPC backend +- [ ] Side-by-side comparison tests +- [ ] Performance benchmarks documented + +--- + +## API Comparison Reference + +### Project Operations + +| Operation | SWIG | IPC | +| -------------- | -------------------- | ------------------------ | +| Create project | Custom file creation | `kicad.create_project()` | +| Open project | `pcbnew.LoadBoard()` | `kicad.open_project()` | +| Save project | `board.Save()` | `board.save()` | + +### Board Operations + +| Operation | SWIG | IPC | +| --------- | ----------------------- | -------------------- | +| Get board | `pcbnew.LoadBoard()` | `kicad.get_board()` | +| Set size | `board.SetBoardSize()` | `board.set_size()` | +| Add layer | `board.GetLayerCount()` | `board.layers.add()` | + +### Component Operations + +| Operation | SWIG | IPC | +| ---------------- | --------------------- | -------------------------- | +| Place component | `pcbnew.FOOTPRINT()` | `board.add_footprint()` | +| Move component | `fp.SetPosition()` | `footprint.set_position()` | +| Rotate component | `fp.SetOrientation()` | `footprint.set_rotation()` | + +### Routing Operations + +| Operation | SWIG | IPC | +| ----------- | --------------------- | ------------------- | +| Add net | `board.GetNetCount()` | `board.nets.add()` | +| Route trace | `pcbnew.PCB_TRACK()` | `board.add_track()` | +| Add via | `pcbnew.PCB_VIA()` | `board.add_via()` | + +--- + +## Configuration Changes + +### Update requirements.txt + +```diff ++ # KiCAD IPC API (official Python bindings) ++ kicad-python>=0.5.0 + + # Legacy SWIG support (for backward compatibility) + kicad-skip>=0.1.0 +``` + +### Environment Variables + +```bash +# Enable IPC API in KiCAD preferences +# Preferences > Plugins > Enable IPC API Server + +# Set backend preference (optional) +export KICAD_BACKEND=ipc # or 'swig' or 'auto' +``` + +### User Migration Guide + +Create `docs/MIGRATING_TO_IPC.md`: + +- How to enable IPC in KiCAD +- What changes for users +- Troubleshooting IPC connection issues + +--- + +## Rollback Plan + +If IPC migration fails: + +1. **Keep SWIG backend** - Already abstracted +2. **Default to SWIG** - Change factory auto-detection +3. **Document limitations** - Note that SWIG will be removed eventually +4. **Plan retry** - Schedule IPC migration for later + +--- + +## Success Criteria + +- [ ] ✅ All existing functionality works with IPC backend +- [ ] ✅ Tests pass with both IPC and SWIG backends +- [ ] ✅ Performance acceptable (< 20% slowdown vs SWIG) +- [ ] ✅ Documentation updated +- [ ] ✅ Migration guide created +- [ ] ✅ User-facing tools work without changes + +--- + +## Timeline + +| Week | Days | Tasks | +| ---------- | ------- | ----------------------------------------------- | +| **Week 2** | Mon-Tue | Research, install kicad-python, test connection | +| | Wed-Thu | Build abstraction layer | +| | Fri | Port project.py and board.py | +| **Week 3** | Mon-Tue | Port component.py and routing.py | +| | Wed | Port design_rules.py and export.py | +| | Thu-Fri | Testing, validation, documentation | + +--- + +## Resources + +- **Official Docs:** https://docs.kicad.org/kicad-python-main +- **kicad-python PyPI:** https://pypi.org/project/kicad-python/ +- **IPC API Spec:** https://dev-docs.kicad.org/en/apis-and-binding/ipc-api/ +- **Protocol Buffers:** Used by IPC for message format + +--- + +## Open Questions + +1. **How to handle KiCAD not running?** + - Option A: Auto-launch KiCAD in background + - Option B: Require user to launch KiCAD first + - Option C: Fall back to SWIG if IPC unavailable + - **Decision: Option C for now, A later** + +2. **Connection management** + - Should we keep connection open or connect per-operation? + - **Decision: Keep alive with reconnect logic** + +3. **Performance vs reliability** + - IPC has overhead but more stable + - **Decision: Reliability > performance** + +--- + +## Next Steps (This Week) + +1. **Install kicad-python** + + ```bash + pip install kicad-python + ``` + +2. **Test IPC connection** + + ```bash + # Launch KiCAD + # Enable IPC in preferences + python3 -c "from kicad import KiCad; k=KiCad(); print(k.check_version())" + ``` + +3. **Create abstraction layer structure** + + ```bash + mkdir -p python/kicad_api + touch python/kicad_api/{__init__,base,ipc_backend,swig_backend,factory}.py + ``` + +4. **Begin project.py migration** + - Start with simplest module + - Establish patterns for others + +--- + +**Prepared by:** Claude Code +**Last Updated:** October 25, 2025 +**Status:** 📋 Ready to execute diff --git a/docs/archive/JLCPCB_INTEGRATION_PLAN.md b/docs/archive/JLCPCB_INTEGRATION_PLAN.md index 5fe7237..dc62a1e 100644 --- a/docs/archive/JLCPCB_INTEGRATION_PLAN.md +++ b/docs/archive/JLCPCB_INTEGRATION_PLAN.md @@ -1,610 +1,628 @@ -# JLCPCB Parts Integration Plan - -**Goal:** Enable AI-driven component selection using JLCPCB's assembly parts library with real pricing and availability - -**Status:** Planning Phase -**Estimated Effort:** 3-4 days -**Priority:** Week 2 Priority 3 (after Component Libraries + Routing) - ---- - -## Overview - -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%") -- Automatic part selection optimized for cost (prefer Basic parts) -- Real stock and pricing information -- Mapping JLCPCB parts to KiCAD footprints - ---- - -## Architecture - -### Data Flow - -``` -┌──────────────────────────────────────────────────┐ -│ JLCPCB API (https://jlcpcb.com/external/...) │ -│ - Requires API key/secret │ -│ - Returns: ~100k parts with specs/pricing │ -└───────────────────┬──────────────────────────────┘ - │ Download (once, then updates) - ▼ -┌──────────────────────────────────────────────────┐ -│ SQLite Database (local cache) │ -│ - components table │ -│ - manufacturers table │ -│ - categories table │ -│ - Fast parametric search │ -└───────────────────┬──────────────────────────────┘ - │ Search/query - ▼ -┌──────────────────────────────────────────────────┐ -│ JLCPCB Parts Manager (Python) │ -│ - search_parts(specs) │ -│ - get_part_info(lcsc_number) │ -│ - map_to_footprint(package) │ -│ - suggest_alternatives(part) │ -└───────────────────┬──────────────────────────────┘ - │ MCP Tools - ▼ -┌──────────────────────────────────────────────────┐ -│ MCP Tools (TypeScript) │ -│ - search_jlcpcb_parts │ -│ - get_jlcpcb_part │ -│ - place_component (enhanced) │ -└──────────────────────────────────────────────────┘ -``` - -### File Structure - -``` -python/commands/ -├── jlcpcb.py # JLCPCB API client -└── jlcpcb_parts.py # Parts database manager - -data/ -├── jlcpcb_parts.db # SQLite cache (gitignored) -└── footprint_mappings.json # Package → KiCAD footprint mapping - -src/tools/ -└── jlcpcb.ts # MCP tool definitions - -docs/ -└── JLCPCB_INTEGRATION.md # User documentation -``` - ---- - -## Implementation Phases - -### Phase 1: JLCPCB API Client (Day 1) - -**File:** `python/commands/jlcpcb.py` - -**Features:** -- Authenticate with JLCPCB API (requires user-provided key/secret) -- Download parts database (paginated, ~100k parts) -- Handle rate limiting and retries -- Save to SQLite database - -**API Endpoints:** -```python -# Get auth token -POST https://jlcpcb.com/external/genToken -{ - "appKey": "YOUR_KEY", - "appSecret": "YOUR_SECRET" -} - -# Fetch parts (paginated) -POST https://jlcpcb.com/external/component/getComponentInfos -Headers: { "externalApiToken": "TOKEN" } -Body: { "lastKey": "PAGINATION_KEY" } # Optional, for next page -``` - -**Database Schema:** -```sql -CREATE TABLE components ( - lcsc TEXT PRIMARY KEY, -- "C12345" - category TEXT, -- "Resistors" - subcategory TEXT, -- "Chip Resistor - Surface Mount" - mfr_part TEXT, -- "RC0603FR-0710KL" - package TEXT, -- "0603" - solder_joints INTEGER, -- 2 - manufacturer TEXT, -- "YAGEO" - library_type TEXT, -- "Basic" or "Extended" - description TEXT, -- "10kΩ ±1% 0.1W" - datasheet TEXT, -- URL - stock INTEGER, -- 15000 - price_json TEXT, -- JSON array of price breaks - last_updated INTEGER -- Unix timestamp -); - -CREATE INDEX idx_category ON components(category, subcategory); -CREATE INDEX idx_package ON components(package); -CREATE INDEX idx_manufacturer ON components(manufacturer); -CREATE INDEX idx_library_type ON components(library_type); -``` - -**Environment Variables:** -```bash -# ~/.bashrc or .env -export JLCPCB_API_KEY="your_key_here" -export JLCPCB_API_SECRET="your_secret_here" -``` - -**Python Implementation Outline:** -```python -class JLCPCBClient: - def __init__(self, api_key: str, api_secret: str): - self.api_key = api_key - self.api_secret = api_secret - self.token = None - - def authenticate(self) -> str: - """Get auth token from JLCPCB API""" - - def fetch_parts_page(self, last_key: Optional[str] = None) -> dict: - """Fetch one page of parts (paginated)""" - - def download_full_database(self, db_path: str, progress_callback=None): - """Download entire parts library to SQLite""" - - def update_database(self, db_path: str): - """Incremental update (fetch only new/changed parts)""" -``` - ---- - -### Phase 2: Parts Database Manager (Day 2) - -**File:** `python/commands/jlcpcb_parts.py` - -**Features:** -- Initialize/load SQLite database -- Parametric search (resistance, capacitance, voltage, etc.) -- Filter by library type (Basic/Extended) -- Sort by price, stock, or popularity -- Map package names to KiCAD footprints - -**Python Implementation Outline:** -```python -class JLCPCBPartsManager: - def __init__(self, db_path: str = "data/jlcpcb_parts.db"): - self.conn = sqlite3.connect(db_path) - - def search_parts( - self, - query: str = None, # Free-text search - category: str = None, # "Resistors" - package: str = None, # "0603" - library_type: str = None, # "Basic" only - manufacturer: str = None, # "YAGEO" - in_stock: bool = True, # Only parts with stock > 0 - limit: int = 20 - ) -> List[dict]: - """Search parts with filters""" - - def get_part_info(self, lcsc_number: str) -> dict: - """Get detailed info for specific part""" - - def map_package_to_footprint(self, package: str) -> List[str]: - """Map JLCPCB package name to KiCAD footprint(s)""" - # Example: "0603" → ["Resistor_SMD:R_0603_1608Metric", - # "Capacitor_SMD:C_0603_1608Metric"] - - def parse_description(self, description: str, category: str) -> dict: - """Extract parameters from description text""" - # Example: "10kΩ ±1% 0.1W" → {resistance: "10k", tolerance: "1%", power: "0.1W"} - - def suggest_alternatives(self, lcsc_number: str, limit: int = 5) -> List[dict]: - """Find similar parts (cheaper, more stock, Basic instead of Extended)""" -``` - -**Package to Footprint Mapping:** -```json -{ - "0402": [ - "Resistor_SMD:R_0402_1005Metric", - "Capacitor_SMD:C_0402_1005Metric", - "LED_SMD:LED_0402_1005Metric" - ], - "0603": [ - "Resistor_SMD:R_0603_1608Metric", - "Capacitor_SMD:C_0603_1608Metric", - "LED_SMD:LED_0603_1608Metric" - ], - "0805": [ - "Resistor_SMD:R_0805_2012Metric", - "Capacitor_SMD:C_0805_2012Metric" - ], - "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" - ] -} -``` - ---- - -### Phase 3: MCP Tools Integration (Day 3) - -**File:** `src/tools/jlcpcb.ts` - -**New MCP Tools:** - -#### 1. `search_jlcpcb_parts` -Search JLCPCB parts library by specifications. - -```typescript -{ - name: "search_jlcpcb_parts", - description: "Search JLCPCB assembly parts by specifications", - inputSchema: { - type: "object", - properties: { - query: { - type: "string", - description: "Free-text search (e.g., '10k resistor 0603')" - }, - category: { - type: "string", - description: "Category filter (e.g., 'Resistors', 'Capacitors')" - }, - package: { - type: "string", - description: "Package filter (e.g., '0603', 'SOT-23')" - }, - library_type: { - type: "string", - enum: ["Basic", "Extended", "All"], - description: "Filter by library type (Basic = free assembly)" - }, - in_stock: { - type: "boolean", - default: true, - description: "Only show parts with available stock" - }, - limit: { - type: "number", - default: 20, - description: "Maximum results to return" - } - } - } -} -``` - -**Example Usage:** -``` -User: "Find me a 10k resistor, 0603 package, JLCPCB basic part" -Claude: [uses search_jlcpcb_parts] -Found 15 parts: -1. C25804 - YAGEO RC0603FR-0710KL - 10kΩ ±1% 0.1W - Basic - $0.002 (15k in stock) -2. C58972 - UNI-ROYAL 0603WAF1002T5E - 10kΩ ±1% 0.1W - Basic - $0.001 (50k in stock) -... -Recommended: C58972 (cheapest Basic part with high stock) -``` - -#### 2. `get_jlcpcb_part` -Get detailed information about a specific JLCPCB part. - -```typescript -{ - name: "get_jlcpcb_part", - description: "Get detailed info for a specific JLCPCB part", - inputSchema: { - type: "object", - properties: { - lcsc_number: { - type: "string", - description: "LCSC part number (e.g., 'C25804')" - } - }, - required: ["lcsc_number"] - } -} -``` - -**Returns:** -```json -{ - "lcsc": "C25804", - "mfr_part": "RC0603FR-0710KL", - "manufacturer": "YAGEO", - "category": "Resistors / Chip Resistor - Surface Mount", - "package": "0603", - "description": "10kΩ ±1% 0.1W Thick Film Resistors", - "library_type": "Basic", - "stock": 15000, - "price_breaks": [ - {"qty": 1, "price": "$0.002"}, - {"qty": 10, "price": "$0.0018"}, - {"qty": 100, "price": "$0.0015"} - ], - "datasheet": "https://datasheet.lcsc.com/...", - "kicad_footprints": [ - "Resistor_SMD:R_0603_1608Metric" - ] -} -``` - -#### 3. Enhanced `place_component` -Add JLCPCB integration to existing component placement. - -```typescript -// Add new optional parameter to place_component: -{ - jlcpcb_part: { - type: "string", - description: "JLCPCB LCSC part number (e.g., 'C25804'). If provided, will use JLCPCB specs." - } -} -``` - -**Example:** -``` -User: "Place a 10k resistor at 50, 40mm using JLCPCB part C25804" -Claude: [uses place_component with jlcpcb_part="C25804"] - - Looks up C25804 → finds package "0603" - - Maps "0603" → "Resistor_SMD:R_0603_1608Metric" - - Places component with: - - Reference: R1 - - Value: 10k (C25804) - - Footprint: Resistor_SMD:R_0603_1608Metric - - Attribute: LCSC part C25804 stored in component properties -``` - ---- - -### Phase 4: Testing & Documentation (Day 4) - -**Testing:** -1. Download JLCPCB database (verify ~100k parts loaded) -2. Test parametric search (resistors, capacitors, ICs) -3. Test package mapping (0603 → correct footprints) -4. Test component placement with JLCPCB parts -5. Verify BOM export includes LCSC part numbers - -**Documentation:** -- User guide: How to get JLCPCB API key -- Usage examples for each MCP tool -- Best practices (prefer Basic parts, check stock) -- BOM generation for JLCPCB assembly - ---- - -## User Workflow Examples - -### Example 1: Find and Place a Resistor -``` -User: "I need a 10k pull-up resistor, 0603 size, cheapest JLCPCB basic part" - -Claude: [uses search_jlcpcb_parts] - query: "10k resistor" - package: "0603" - library_type: "Basic" - -Found: C58972 - UNI-ROYAL 0603WAF1002T5E - - 10kΩ ±1% 0.1W - - Basic part (free assembly!) - - $0.001 each - - 50,000 in stock - -User: "Perfect, place it at position 45, 30mm" - -Claude: [uses place_component] - componentId: "Resistor_SMD:R_0603_1608Metric" - position: {x: 45, y: 30} - reference: "R1" - value: "10k (C58972)" - jlcpcb_part: "C58972" - - ✅ Placed R1: 10k at (45, 30) mm - JLCPCB: C58972 (Basic part, $0.001) -``` - -### Example 2: Design a Cost-Optimized LED Circuit -``` -User: "Design an LED circuit with current-limiting resistor, use only JLCPCB basic parts" - -Claude: [searches for LED] - Found: C2286 - Everlight 19-217/BHC-ZL1M2RY/3T (Red LED, 0603) - Basic - $0.015 - - [searches for resistor] - Calculated: 330Ω for 5V → 20mA - Found: C23138 - UNI-ROYAL 0603WAF3300T5E (330Ω, 0603) - Basic - $0.001 - - [places components] - R1: 330Ω (C23138) at (40, 30) mm - D1: Red LED (C2286) at (50, 30) mm - - Total BOM cost: $0.016 - Both are Basic parts → Free assembly! 🎉 -``` - -### Example 3: Check Stock Before Ordering -``` -User: "I need 100 of part C25804, is there enough stock?" - -Claude: [uses get_jlcpcb_part lcsc_number="C25804"] - Stock: 15,000 units - ✅ Plenty of stock for 100 units - - Price for 100: $0.0015 each = $0.15 total -``` - ---- - -## API Key Setup - -**How to Get JLCPCB API Key:** - -1. Visit JLCPCB website: https://jlcpcb.com/ -2. Log in to your account -3. Go to: Account → API Management -4. Click "Create API Key" -5. Save your `appKey` and `appSecret` - -**Configure in MCP:** - -Option A: Environment variables (recommended) -```bash -export JLCPCB_API_KEY="your_app_key" -export JLCPCB_API_SECRET="your_app_secret" -``` - -Option B: Config file -```json -{ - "jlcpcb": { - "api_key": "your_app_key", - "api_secret": "your_app_secret", - "cache_db": "~/.kicad-mcp/jlcpcb_parts.db" - } -} -``` - -**Initial Setup:** -``` -User: "Download the JLCPCB parts database" - -Claude: [runs JLCPCB database download] - Authenticating... ✅ - Fetching parts... (page 1/500) - Fetching parts... (page 2/500) - ... - ✅ Downloaded 108,523 parts - ✅ Saved to ~/.kicad-mcp/jlcpcb_parts.db (42 MB) - - Database ready! You can now search JLCPCB parts. -``` - ---- - -## Cost Optimization Features - -### Prefer Basic Parts - -```python -def search_parts_optimized(self, specs: dict) -> List[dict]: - """ - Search with automatic Basic part preference. - Returns Basic parts first, Extended parts only if no Basic match. - """ - basic_parts = self.search_parts(**specs, library_type="Basic") - if basic_parts: - return basic_parts - return self.search_parts(**specs, library_type="Extended") -``` - -### Calculate BOM Cost - -```python -def calculate_bom_cost(self, board: pcbnew.BOARD) -> dict: - """ - Calculate total cost for JLCPCB assembly. - - Returns: - { - "total_parts_cost": 12.50, - "basic_parts_count": 15, - "extended_parts_count": 2, - "extended_setup_fee": 6.00, # $3 per unique extended part - "total_assembly_cost": 18.50 - } - """ -``` - ---- - -## Integration with Existing Features - -### BOM Export Enhancement - -Update `export_bom` to include JLCPCB columns: - -```csv -Reference,Value,Footprint,LCSC Part,Library Type,Manufacturer,MFR Part,Stock -R1,10k,Resistor_SMD:R_0603_1608Metric,C58972,Basic,UNI-ROYAL,0603WAF1002T5E,50000 -D1,Red,LED_SMD:LED_0603_1608Metric,C2286,Basic,Everlight,19-217/BHC-ZL1M2RY/3T,8000 -``` - -This BOM can be directly uploaded to JLCPCB for assembly! - ---- - -## Database Update Strategy - -**Initial Download:** ~5-10 minutes (108k parts) - -**Incremental Updates:** -- Run daily via cron/scheduled task -- Only fetch parts modified since last update -- Much faster (~30 seconds) - -**Update Command:** -```python -# In Python -jlcpcb_client.update_database(db_path) - -# Via MCP tool -update_jlcpcb_database(force=False) # Incremental -update_jlcpcb_database(force=True) # Full re-download -``` - ---- - -## Success Metrics - -**Implementation Complete When:** -- ✅ Can download/cache full JLCPCB parts database -- ✅ Parametric search works (resistors, capacitors, ICs) -- ✅ Package → footprint mapping covers 90%+ of common parts -- ✅ MCP tools integrated and tested end-to-end -- ✅ BOM export includes LCSC part numbers -- ✅ Documentation complete with examples - -**User Experience Goal:** -``` -User: "Design a board with an ESP32, USB-C connector, and LED, - use only JLCPCB basic parts under $10 BOM" - -Claude: [searches JLCPCB database] - [places all components with real parts] - [exports BOM ready for manufacturing] - - ✅ Board designed with 23 components - 💰 Total cost: $8.45 - 🎉 All Basic parts (free assembly!) -``` - ---- - -## Future Enhancements - -**Post-MVP (v2.1+):** -- LCSC API integration for extended parametric data -- Digikey/Mouser fallback for non-JLCPCB parts -- Part substitution suggestions (out of stock → alternatives) -- Price history and trend analysis -- Community-contributed package mappings -- Visual part selection UI (if web interface added) - ---- - -## Related Documentation - -- [LIBRARY_INTEGRATION.md](./LIBRARY_INTEGRATION.md) - KiCAD footprint libraries -- [REALTIME_WORKFLOW.md](./REALTIME_WORKFLOW.md) - MCP ↔ UI collaboration -- [ROADMAP.md](./ROADMAP.md) - Overall project plan -- [API.md](./API.md) - MCP API reference - ---- - -**Status:** Ready to implement! 🚀 -**Next Step:** Get JLCPCB API credentials and start Phase 1 +# JLCPCB Parts Integration Plan + +**Goal:** Enable AI-driven component selection using JLCPCB's assembly parts library with real pricing and availability + +**Status:** Planning Phase +**Estimated Effort:** 3-4 days +**Priority:** Week 2 Priority 3 (after Component Libraries + Routing) + +--- + +## Overview + +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%") +- Automatic part selection optimized for cost (prefer Basic parts) +- Real stock and pricing information +- Mapping JLCPCB parts to KiCAD footprints + +--- + +## Architecture + +### Data Flow + +``` +┌──────────────────────────────────────────────────┐ +│ JLCPCB API (https://jlcpcb.com/external/...) │ +│ - Requires API key/secret │ +│ - Returns: ~100k parts with specs/pricing │ +└───────────────────┬──────────────────────────────┘ + │ Download (once, then updates) + ▼ +┌──────────────────────────────────────────────────┐ +│ SQLite Database (local cache) │ +│ - components table │ +│ - manufacturers table │ +│ - categories table │ +│ - Fast parametric search │ +└───────────────────┬──────────────────────────────┘ + │ Search/query + ▼ +┌──────────────────────────────────────────────────┐ +│ JLCPCB Parts Manager (Python) │ +│ - search_parts(specs) │ +│ - get_part_info(lcsc_number) │ +│ - map_to_footprint(package) │ +│ - suggest_alternatives(part) │ +└───────────────────┬──────────────────────────────┘ + │ MCP Tools + ▼ +┌──────────────────────────────────────────────────┐ +│ MCP Tools (TypeScript) │ +│ - search_jlcpcb_parts │ +│ - get_jlcpcb_part │ +│ - place_component (enhanced) │ +└──────────────────────────────────────────────────┘ +``` + +### File Structure + +``` +python/commands/ +├── jlcpcb.py # JLCPCB API client +└── jlcpcb_parts.py # Parts database manager + +data/ +├── jlcpcb_parts.db # SQLite cache (gitignored) +└── footprint_mappings.json # Package → KiCAD footprint mapping + +src/tools/ +└── jlcpcb.ts # MCP tool definitions + +docs/ +└── JLCPCB_INTEGRATION.md # User documentation +``` + +--- + +## Implementation Phases + +### Phase 1: JLCPCB API Client (Day 1) + +**File:** `python/commands/jlcpcb.py` + +**Features:** + +- Authenticate with JLCPCB API (requires user-provided key/secret) +- Download parts database (paginated, ~100k parts) +- Handle rate limiting and retries +- Save to SQLite database + +**API Endpoints:** + +```python +# Get auth token +POST https://jlcpcb.com/external/genToken +{ + "appKey": "YOUR_KEY", + "appSecret": "YOUR_SECRET" +} + +# Fetch parts (paginated) +POST https://jlcpcb.com/external/component/getComponentInfos +Headers: { "externalApiToken": "TOKEN" } +Body: { "lastKey": "PAGINATION_KEY" } # Optional, for next page +``` + +**Database Schema:** + +```sql +CREATE TABLE components ( + lcsc TEXT PRIMARY KEY, -- "C12345" + category TEXT, -- "Resistors" + subcategory TEXT, -- "Chip Resistor - Surface Mount" + mfr_part TEXT, -- "RC0603FR-0710KL" + package TEXT, -- "0603" + solder_joints INTEGER, -- 2 + manufacturer TEXT, -- "YAGEO" + library_type TEXT, -- "Basic" or "Extended" + description TEXT, -- "10kΩ ±1% 0.1W" + datasheet TEXT, -- URL + stock INTEGER, -- 15000 + price_json TEXT, -- JSON array of price breaks + last_updated INTEGER -- Unix timestamp +); + +CREATE INDEX idx_category ON components(category, subcategory); +CREATE INDEX idx_package ON components(package); +CREATE INDEX idx_manufacturer ON components(manufacturer); +CREATE INDEX idx_library_type ON components(library_type); +``` + +**Environment Variables:** + +```bash +# ~/.bashrc or .env +export JLCPCB_API_KEY="your_key_here" +export JLCPCB_API_SECRET="your_secret_here" +``` + +**Python Implementation Outline:** + +```python +class JLCPCBClient: + def __init__(self, api_key: str, api_secret: str): + self.api_key = api_key + self.api_secret = api_secret + self.token = None + + def authenticate(self) -> str: + """Get auth token from JLCPCB API""" + + def fetch_parts_page(self, last_key: Optional[str] = None) -> dict: + """Fetch one page of parts (paginated)""" + + def download_full_database(self, db_path: str, progress_callback=None): + """Download entire parts library to SQLite""" + + def update_database(self, db_path: str): + """Incremental update (fetch only new/changed parts)""" +``` + +--- + +### Phase 2: Parts Database Manager (Day 2) + +**File:** `python/commands/jlcpcb_parts.py` + +**Features:** + +- Initialize/load SQLite database +- Parametric search (resistance, capacitance, voltage, etc.) +- Filter by library type (Basic/Extended) +- Sort by price, stock, or popularity +- Map package names to KiCAD footprints + +**Python Implementation Outline:** + +```python +class JLCPCBPartsManager: + def __init__(self, db_path: str = "data/jlcpcb_parts.db"): + self.conn = sqlite3.connect(db_path) + + def search_parts( + self, + query: str = None, # Free-text search + category: str = None, # "Resistors" + package: str = None, # "0603" + library_type: str = None, # "Basic" only + manufacturer: str = None, # "YAGEO" + in_stock: bool = True, # Only parts with stock > 0 + limit: int = 20 + ) -> List[dict]: + """Search parts with filters""" + + def get_part_info(self, lcsc_number: str) -> dict: + """Get detailed info for specific part""" + + def map_package_to_footprint(self, package: str) -> List[str]: + """Map JLCPCB package name to KiCAD footprint(s)""" + # Example: "0603" → ["Resistor_SMD:R_0603_1608Metric", + # "Capacitor_SMD:C_0603_1608Metric"] + + def parse_description(self, description: str, category: str) -> dict: + """Extract parameters from description text""" + # Example: "10kΩ ±1% 0.1W" → {resistance: "10k", tolerance: "1%", power: "0.1W"} + + def suggest_alternatives(self, lcsc_number: str, limit: int = 5) -> List[dict]: + """Find similar parts (cheaper, more stock, Basic instead of Extended)""" +``` + +**Package to Footprint Mapping:** + +```json +{ + "0402": [ + "Resistor_SMD:R_0402_1005Metric", + "Capacitor_SMD:C_0402_1005Metric", + "LED_SMD:LED_0402_1005Metric" + ], + "0603": [ + "Resistor_SMD:R_0603_1608Metric", + "Capacitor_SMD:C_0603_1608Metric", + "LED_SMD:LED_0603_1608Metric" + ], + "0805": ["Resistor_SMD:R_0805_2012Metric", "Capacitor_SMD:C_0805_2012Metric"], + "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"] +} +``` + +--- + +### Phase 3: MCP Tools Integration (Day 3) + +**File:** `src/tools/jlcpcb.ts` + +**New MCP Tools:** + +#### 1. `search_jlcpcb_parts` + +Search JLCPCB parts library by specifications. + +```typescript +{ + name: "search_jlcpcb_parts", + description: "Search JLCPCB assembly parts by specifications", + inputSchema: { + type: "object", + properties: { + query: { + type: "string", + description: "Free-text search (e.g., '10k resistor 0603')" + }, + category: { + type: "string", + description: "Category filter (e.g., 'Resistors', 'Capacitors')" + }, + package: { + type: "string", + description: "Package filter (e.g., '0603', 'SOT-23')" + }, + library_type: { + type: "string", + enum: ["Basic", "Extended", "All"], + description: "Filter by library type (Basic = free assembly)" + }, + in_stock: { + type: "boolean", + default: true, + description: "Only show parts with available stock" + }, + limit: { + type: "number", + default: 20, + description: "Maximum results to return" + } + } + } +} +``` + +**Example Usage:** + +``` +User: "Find me a 10k resistor, 0603 package, JLCPCB basic part" +Claude: [uses search_jlcpcb_parts] +Found 15 parts: +1. C25804 - YAGEO RC0603FR-0710KL - 10kΩ ±1% 0.1W - Basic - $0.002 (15k in stock) +2. C58972 - UNI-ROYAL 0603WAF1002T5E - 10kΩ ±1% 0.1W - Basic - $0.001 (50k in stock) +... +Recommended: C58972 (cheapest Basic part with high stock) +``` + +#### 2. `get_jlcpcb_part` + +Get detailed information about a specific JLCPCB part. + +```typescript +{ + name: "get_jlcpcb_part", + description: "Get detailed info for a specific JLCPCB part", + inputSchema: { + type: "object", + properties: { + lcsc_number: { + type: "string", + description: "LCSC part number (e.g., 'C25804')" + } + }, + required: ["lcsc_number"] + } +} +``` + +**Returns:** + +```json +{ + "lcsc": "C25804", + "mfr_part": "RC0603FR-0710KL", + "manufacturer": "YAGEO", + "category": "Resistors / Chip Resistor - Surface Mount", + "package": "0603", + "description": "10kΩ ±1% 0.1W Thick Film Resistors", + "library_type": "Basic", + "stock": 15000, + "price_breaks": [ + { "qty": 1, "price": "$0.002" }, + { "qty": 10, "price": "$0.0018" }, + { "qty": 100, "price": "$0.0015" } + ], + "datasheet": "https://datasheet.lcsc.com/...", + "kicad_footprints": ["Resistor_SMD:R_0603_1608Metric"] +} +``` + +#### 3. Enhanced `place_component` + +Add JLCPCB integration to existing component placement. + +```typescript +// Add new optional parameter to place_component: +{ + jlcpcb_part: { + type: "string", + description: "JLCPCB LCSC part number (e.g., 'C25804'). If provided, will use JLCPCB specs." + } +} +``` + +**Example:** + +``` +User: "Place a 10k resistor at 50, 40mm using JLCPCB part C25804" +Claude: [uses place_component with jlcpcb_part="C25804"] + - Looks up C25804 → finds package "0603" + - Maps "0603" → "Resistor_SMD:R_0603_1608Metric" + - Places component with: + - Reference: R1 + - Value: 10k (C25804) + - Footprint: Resistor_SMD:R_0603_1608Metric + - Attribute: LCSC part C25804 stored in component properties +``` + +--- + +### Phase 4: Testing & Documentation (Day 4) + +**Testing:** + +1. Download JLCPCB database (verify ~100k parts loaded) +2. Test parametric search (resistors, capacitors, ICs) +3. Test package mapping (0603 → correct footprints) +4. Test component placement with JLCPCB parts +5. Verify BOM export includes LCSC part numbers + +**Documentation:** + +- User guide: How to get JLCPCB API key +- Usage examples for each MCP tool +- Best practices (prefer Basic parts, check stock) +- BOM generation for JLCPCB assembly + +--- + +## User Workflow Examples + +### Example 1: Find and Place a Resistor + +``` +User: "I need a 10k pull-up resistor, 0603 size, cheapest JLCPCB basic part" + +Claude: [uses search_jlcpcb_parts] + query: "10k resistor" + package: "0603" + library_type: "Basic" + +Found: C58972 - UNI-ROYAL 0603WAF1002T5E + - 10kΩ ±1% 0.1W + - Basic part (free assembly!) + - $0.001 each + - 50,000 in stock + +User: "Perfect, place it at position 45, 30mm" + +Claude: [uses place_component] + componentId: "Resistor_SMD:R_0603_1608Metric" + position: {x: 45, y: 30} + reference: "R1" + value: "10k (C58972)" + jlcpcb_part: "C58972" + + ✅ Placed R1: 10k at (45, 30) mm + JLCPCB: C58972 (Basic part, $0.001) +``` + +### Example 2: Design a Cost-Optimized LED Circuit + +``` +User: "Design an LED circuit with current-limiting resistor, use only JLCPCB basic parts" + +Claude: [searches for LED] + Found: C2286 - Everlight 19-217/BHC-ZL1M2RY/3T (Red LED, 0603) - Basic - $0.015 + + [searches for resistor] + Calculated: 330Ω for 5V → 20mA + Found: C23138 - UNI-ROYAL 0603WAF3300T5E (330Ω, 0603) - Basic - $0.001 + + [places components] + R1: 330Ω (C23138) at (40, 30) mm + D1: Red LED (C2286) at (50, 30) mm + + Total BOM cost: $0.016 + Both are Basic parts → Free assembly! 🎉 +``` + +### Example 3: Check Stock Before Ordering + +``` +User: "I need 100 of part C25804, is there enough stock?" + +Claude: [uses get_jlcpcb_part lcsc_number="C25804"] + Stock: 15,000 units + ✅ Plenty of stock for 100 units + + Price for 100: $0.0015 each = $0.15 total +``` + +--- + +## API Key Setup + +**How to Get JLCPCB API Key:** + +1. Visit JLCPCB website: https://jlcpcb.com/ +2. Log in to your account +3. Go to: Account → API Management +4. Click "Create API Key" +5. Save your `appKey` and `appSecret` + +**Configure in MCP:** + +Option A: Environment variables (recommended) + +```bash +export JLCPCB_API_KEY="your_app_key" +export JLCPCB_API_SECRET="your_app_secret" +``` + +Option B: Config file + +```json +{ + "jlcpcb": { + "api_key": "your_app_key", + "api_secret": "your_app_secret", + "cache_db": "~/.kicad-mcp/jlcpcb_parts.db" + } +} +``` + +**Initial Setup:** + +``` +User: "Download the JLCPCB parts database" + +Claude: [runs JLCPCB database download] + Authenticating... ✅ + Fetching parts... (page 1/500) + Fetching parts... (page 2/500) + ... + ✅ Downloaded 108,523 parts + ✅ Saved to ~/.kicad-mcp/jlcpcb_parts.db (42 MB) + + Database ready! You can now search JLCPCB parts. +``` + +--- + +## Cost Optimization Features + +### Prefer Basic Parts + +```python +def search_parts_optimized(self, specs: dict) -> List[dict]: + """ + Search with automatic Basic part preference. + Returns Basic parts first, Extended parts only if no Basic match. + """ + basic_parts = self.search_parts(**specs, library_type="Basic") + if basic_parts: + return basic_parts + return self.search_parts(**specs, library_type="Extended") +``` + +### Calculate BOM Cost + +```python +def calculate_bom_cost(self, board: pcbnew.BOARD) -> dict: + """ + Calculate total cost for JLCPCB assembly. + + Returns: + { + "total_parts_cost": 12.50, + "basic_parts_count": 15, + "extended_parts_count": 2, + "extended_setup_fee": 6.00, # $3 per unique extended part + "total_assembly_cost": 18.50 + } + """ +``` + +--- + +## Integration with Existing Features + +### BOM Export Enhancement + +Update `export_bom` to include JLCPCB columns: + +```csv +Reference,Value,Footprint,LCSC Part,Library Type,Manufacturer,MFR Part,Stock +R1,10k,Resistor_SMD:R_0603_1608Metric,C58972,Basic,UNI-ROYAL,0603WAF1002T5E,50000 +D1,Red,LED_SMD:LED_0603_1608Metric,C2286,Basic,Everlight,19-217/BHC-ZL1M2RY/3T,8000 +``` + +This BOM can be directly uploaded to JLCPCB for assembly! + +--- + +## Database Update Strategy + +**Initial Download:** ~5-10 minutes (108k parts) + +**Incremental Updates:** + +- Run daily via cron/scheduled task +- Only fetch parts modified since last update +- Much faster (~30 seconds) + +**Update Command:** + +```python +# In Python +jlcpcb_client.update_database(db_path) + +# Via MCP tool +update_jlcpcb_database(force=False) # Incremental +update_jlcpcb_database(force=True) # Full re-download +``` + +--- + +## Success Metrics + +**Implementation Complete When:** + +- ✅ Can download/cache full JLCPCB parts database +- ✅ Parametric search works (resistors, capacitors, ICs) +- ✅ Package → footprint mapping covers 90%+ of common parts +- ✅ MCP tools integrated and tested end-to-end +- ✅ BOM export includes LCSC part numbers +- ✅ Documentation complete with examples + +**User Experience Goal:** + +``` +User: "Design a board with an ESP32, USB-C connector, and LED, + use only JLCPCB basic parts under $10 BOM" + +Claude: [searches JLCPCB database] + [places all components with real parts] + [exports BOM ready for manufacturing] + + ✅ Board designed with 23 components + 💰 Total cost: $8.45 + 🎉 All Basic parts (free assembly!) +``` + +--- + +## Future Enhancements + +**Post-MVP (v2.1+):** + +- LCSC API integration for extended parametric data +- Digikey/Mouser fallback for non-JLCPCB parts +- Part substitution suggestions (out of stock → alternatives) +- Price history and trend analysis +- Community-contributed package mappings +- Visual part selection UI (if web interface added) + +--- + +## Related Documentation + +- [LIBRARY_INTEGRATION.md](./LIBRARY_INTEGRATION.md) - KiCAD footprint libraries +- [REALTIME_WORKFLOW.md](./REALTIME_WORKFLOW.md) - MCP ↔ UI collaboration +- [ROADMAP.md](./ROADMAP.md) - Overall project plan +- [API.md](./API.md) - MCP API reference + +--- + +**Status:** Ready to implement! 🚀 +**Next Step:** Get JLCPCB API credentials and start Phase 1 diff --git a/docs/archive/ROUTER_IMPLEMENTATION_STATUS.md b/docs/archive/ROUTER_IMPLEMENTATION_STATUS.md index 412721a..11dd453 100644 --- a/docs/archive/ROUTER_IMPLEMENTATION_STATUS.md +++ b/docs/archive/ROUTER_IMPLEMENTATION_STATUS.md @@ -1,222 +1,241 @@ -# Router Implementation Status - -## ✅ Phase 1 Complete: Foundation & Infrastructure - -**Date:** December 28, 2025 - -### What Was Implemented - -#### 1. Tool Registry (`src/tools/registry.ts`) -- ✅ Complete tool categorization (59 tools → 7 categories) -- ✅ Direct tools list (12 high-frequency tools) -- ✅ Category lookup maps for O(1) access -- ✅ Tool search functionality -- ✅ Registry statistics and metadata - -#### 2. Router Tools (`src/tools/router.ts`) -- ✅ `list_tool_categories` - Browse all categories -- ✅ `get_category_tools` - View tools in a category -- ✅ `execute_tool` - Execute any routed tool -- ✅ `search_tools` - Search tools by keyword - -#### 3. Server Integration (`src/server.ts`) -- ✅ Router tools registered at server startup -- ✅ All tools remain functional (backwards compatible) -- ✅ Logging added for router pattern status - -#### 4. Documentation -- ✅ `TOOL_INVENTORY.md` - Complete tool catalog -- ✅ `ROUTER_ARCHITECTURE.md` - Design specification -- ✅ `ROUTER_IMPLEMENTATION_STATUS.md` - This file - -### Current State - -**Status:** ✅ **Router Infrastructure Complete** - -**Build:** ✅ Compiles successfully (`npm run build`) - -**Tool Count:** -- Total Tools: 59 (ALL still registered and visible) -- Direct Tools: 12 -- Routed Tools: 47 -- Router Tools: 4 -- **Currently Visible to Claude:** 63 tools (59 + 4 router) - -**Token Impact:** -- **Current:** ~42K tokens (still showing all tools) -- **Target:** ~12K tokens (Phase 2 optimization) -- **Potential Savings:** ~30K tokens (71% reduction) - -## 🔄 Phase 2: Token Optimization (Next Step) - -### Objective -Hide routed tools from Claude's context while keeping them accessible via `execute_tool`. - -### Two Approaches - -#### Option A: Registration Filtering (Recommended) -Modify tool registration to conditionally register tools based on whether they're in the direct list. - -**Changes needed:** -1. Update each `register*Tools` function to check `isDirectTool()` -2. Only call `server.tool()` for direct tools -3. Routed tools remain accessible via `execute_tool` calling `callKicadScript` - -**Pros:** -- Clean separation -- True token savings -- No behavior changes - -**Cons:** -- Requires modifying 9 tool files - -#### Option B: MCP Filter (If Supported) -If MCP SDK supports tool filtering/hiding, use that instead. - -**Pros:** -- No tool file changes -- Centralized control - -**Cons:** -- May not be supported by SDK -- Needs investigation - -### Implementation Plan for Phase 2 - -1. **Create Helper Function** (`src/tools/conditional-register.ts`) - ```typescript - export function registerToolConditionally( - server: McpServer, - toolName: string, - definition: ToolDefinition, - handler: Function - ) { - if (isDirectTool(toolName)) { - // Register with MCP (visible to Claude) - server.tool(toolName, definition, handler); - } else { - // Register handler for execute_tool (hidden from Claude) - registerToolHandler(toolName, handler); - } - } - ``` - -2. **Update Tool Registration Functions** - Modify each `register*Tools` function to use conditional registration. - -3. **Test** - - Verify direct tools work normally - - Verify routed tools work via `execute_tool` - - Verify token count reduction - -4. **Measure Impact** - Count tools visible to Claude before/after. - -## 📊 Categories & Distribution - -| Category | Tools | Description | -|----------|-------|-------------| -| **board** | 9 | Board configuration, layers, zones, visualization | -| **component** | 8 | Advanced component operations | -| **export** | 8 | Manufacturing file generation | -| **drc** | 9 | Design rule checking & validation | -| **schematic** | 9 | Schematic editor operations | -| **library** | 4 | Footprint library access | -| **routing** | 3 | Advanced routing (vias, copper pours) | -| **TOTAL** | **47** | **Routed tools** | -| **direct** | **12** | **Always visible tools** | -| **router** | **4** | **Discovery tools** | - -## 🧪 Testing the Router - -### Test 1: List Categories -``` -User: "What tool categories are available?" - -Expected: Claude calls list_tool_categories -Result: Returns 7 categories with descriptions -``` - -### Test 2: Browse Category -``` -User: "What export tools are available?" - -Expected: Claude calls get_category_tools({ category: "export" }) -Result: Returns 8 export tools -``` - -### Test 3: Search Tools -``` -User: "How do I export gerber files?" - -Expected: Claude calls search_tools({ query: "gerber" }) -Result: Finds export_gerber in export category -``` - -### Test 4: Execute Tool -``` -User: "Export gerbers to ./output" - -Expected: Claude calls execute_tool({ - tool_name: "export_gerber", - params: { outputDir: "./output" } -}) -Result: Executes via router, returns gerber export result -``` - -## 📝 Benefits Achieved (Phase 1) - -1. ✅ **Foundation Ready**: All infrastructure in place -2. ✅ **Organized**: 59 tools categorized into logical groups -3. ✅ **Discoverable**: Tools easily found via search/browse -4. ✅ **Backwards Compatible**: All existing tools still work -5. ✅ **Extensible**: Easy to add new tools and categories -6. ✅ **Documented**: Complete architecture and usage docs - -## 🚀 Next Actions - -1. **Optional: Complete Phase 2** (Token Optimization) - - Implement conditional registration - - Hide routed tools from context - - Achieve 71% token reduction - -2. **Or: Ship Phase 1 As-Is** - - Router tools work perfectly now - - Users can discover and execute tools - - Optimization can be done later - - No breaking changes - -## 📚 Related Files - -- `src/tools/registry.ts` - Tool registry and categories -- `src/tools/router.ts` - Router tool implementations -- `src/server.ts` - Server integration -- `docs/TOOL_INVENTORY.md` - Complete tool list -- `docs/ROUTER_ARCHITECTURE.md` - Design specification -- `docs/mcp-router-guide.md` - Original implementation guide - -## 💡 Usage Example - -```typescript -// User: "I need to export gerber files" - -// Claude's interaction: -// 1. Sees "export" and "gerber" keywords -// 2. Calls search_tools({ query: "gerber" }) -// → Returns: { category: "export", tool: "export_gerber", ... } -// 3. Calls execute_tool({ -// tool_name: "export_gerber", -// params: { outputDir: "./gerbers" } -// }) -// → Executes and returns result -// 4. "I've exported your Gerber files to ./gerbers/" -``` - -## Status Summary - -✅ **Router Pattern: IMPLEMENTED** -✅ **Build: PASSING** -✅ **Backwards Compatible: YES** -⏳ **Token Optimization: PENDING (Phase 2)** - -The router infrastructure is complete and functional. The system now supports tool discovery and organized access to all 59 tools. Phase 2 optimization (hiding routed tools) can be implemented when ready for maximum token savings. +# Router Implementation Status + +## ✅ Phase 1 Complete: Foundation & Infrastructure + +**Date:** December 28, 2025 + +### What Was Implemented + +#### 1. Tool Registry (`src/tools/registry.ts`) + +- ✅ Complete tool categorization (59 tools → 7 categories) +- ✅ Direct tools list (12 high-frequency tools) +- ✅ Category lookup maps for O(1) access +- ✅ Tool search functionality +- ✅ Registry statistics and metadata + +#### 2. Router Tools (`src/tools/router.ts`) + +- ✅ `list_tool_categories` - Browse all categories +- ✅ `get_category_tools` - View tools in a category +- ✅ `execute_tool` - Execute any routed tool +- ✅ `search_tools` - Search tools by keyword + +#### 3. Server Integration (`src/server.ts`) + +- ✅ Router tools registered at server startup +- ✅ All tools remain functional (backwards compatible) +- ✅ Logging added for router pattern status + +#### 4. Documentation + +- ✅ `TOOL_INVENTORY.md` - Complete tool catalog +- ✅ `ROUTER_ARCHITECTURE.md` - Design specification +- ✅ `ROUTER_IMPLEMENTATION_STATUS.md` - This file + +### Current State + +**Status:** ✅ **Router Infrastructure Complete** + +**Build:** ✅ Compiles successfully (`npm run build`) + +**Tool Count:** + +- Total Tools: 59 (ALL still registered and visible) +- Direct Tools: 12 +- Routed Tools: 47 +- Router Tools: 4 +- **Currently Visible to Claude:** 63 tools (59 + 4 router) + +**Token Impact:** + +- **Current:** ~42K tokens (still showing all tools) +- **Target:** ~12K tokens (Phase 2 optimization) +- **Potential Savings:** ~30K tokens (71% reduction) + +## 🔄 Phase 2: Token Optimization (Next Step) + +### Objective + +Hide routed tools from Claude's context while keeping them accessible via `execute_tool`. + +### Two Approaches + +#### Option A: Registration Filtering (Recommended) + +Modify tool registration to conditionally register tools based on whether they're in the direct list. + +**Changes needed:** + +1. Update each `register*Tools` function to check `isDirectTool()` +2. Only call `server.tool()` for direct tools +3. Routed tools remain accessible via `execute_tool` calling `callKicadScript` + +**Pros:** + +- Clean separation +- True token savings +- No behavior changes + +**Cons:** + +- Requires modifying 9 tool files + +#### Option B: MCP Filter (If Supported) + +If MCP SDK supports tool filtering/hiding, use that instead. + +**Pros:** + +- No tool file changes +- Centralized control + +**Cons:** + +- May not be supported by SDK +- Needs investigation + +### Implementation Plan for Phase 2 + +1. **Create Helper Function** (`src/tools/conditional-register.ts`) + + ```typescript + export function registerToolConditionally( + server: McpServer, + toolName: string, + definition: ToolDefinition, + handler: Function, + ) { + if (isDirectTool(toolName)) { + // Register with MCP (visible to Claude) + server.tool(toolName, definition, handler); + } else { + // Register handler for execute_tool (hidden from Claude) + registerToolHandler(toolName, handler); + } + } + ``` + +2. **Update Tool Registration Functions** + Modify each `register*Tools` function to use conditional registration. + +3. **Test** + - Verify direct tools work normally + - Verify routed tools work via `execute_tool` + - Verify token count reduction + +4. **Measure Impact** + Count tools visible to Claude before/after. + +## 📊 Categories & Distribution + +| Category | Tools | Description | +| ------------- | ------ | ------------------------------------------------- | +| **board** | 9 | Board configuration, layers, zones, visualization | +| **component** | 8 | Advanced component operations | +| **export** | 8 | Manufacturing file generation | +| **drc** | 9 | Design rule checking & validation | +| **schematic** | 9 | Schematic editor operations | +| **library** | 4 | Footprint library access | +| **routing** | 3 | Advanced routing (vias, copper pours) | +| **TOTAL** | **47** | **Routed tools** | +| **direct** | **12** | **Always visible tools** | +| **router** | **4** | **Discovery tools** | + +## 🧪 Testing the Router + +### Test 1: List Categories + +``` +User: "What tool categories are available?" + +Expected: Claude calls list_tool_categories +Result: Returns 7 categories with descriptions +``` + +### Test 2: Browse Category + +``` +User: "What export tools are available?" + +Expected: Claude calls get_category_tools({ category: "export" }) +Result: Returns 8 export tools +``` + +### Test 3: Search Tools + +``` +User: "How do I export gerber files?" + +Expected: Claude calls search_tools({ query: "gerber" }) +Result: Finds export_gerber in export category +``` + +### Test 4: Execute Tool + +``` +User: "Export gerbers to ./output" + +Expected: Claude calls execute_tool({ + tool_name: "export_gerber", + params: { outputDir: "./output" } +}) +Result: Executes via router, returns gerber export result +``` + +## 📝 Benefits Achieved (Phase 1) + +1. ✅ **Foundation Ready**: All infrastructure in place +2. ✅ **Organized**: 59 tools categorized into logical groups +3. ✅ **Discoverable**: Tools easily found via search/browse +4. ✅ **Backwards Compatible**: All existing tools still work +5. ✅ **Extensible**: Easy to add new tools and categories +6. ✅ **Documented**: Complete architecture and usage docs + +## 🚀 Next Actions + +1. **Optional: Complete Phase 2** (Token Optimization) + - Implement conditional registration + - Hide routed tools from context + - Achieve 71% token reduction + +2. **Or: Ship Phase 1 As-Is** + - Router tools work perfectly now + - Users can discover and execute tools + - Optimization can be done later + - No breaking changes + +## 📚 Related Files + +- `src/tools/registry.ts` - Tool registry and categories +- `src/tools/router.ts` - Router tool implementations +- `src/server.ts` - Server integration +- `docs/TOOL_INVENTORY.md` - Complete tool list +- `docs/ROUTER_ARCHITECTURE.md` - Design specification +- `docs/mcp-router-guide.md` - Original implementation guide + +## 💡 Usage Example + +```typescript +// User: "I need to export gerber files" + +// Claude's interaction: +// 1. Sees "export" and "gerber" keywords +// 2. Calls search_tools({ query: "gerber" }) +// → Returns: { category: "export", tool: "export_gerber", ... } +// 3. Calls execute_tool({ +// tool_name: "export_gerber", +// params: { outputDir: "./gerbers" } +// }) +// → Executes and returns result +// 4. "I've exported your Gerber files to ./gerbers/" +``` + +## Status Summary + +✅ **Router Pattern: IMPLEMENTED** +✅ **Build: PASSING** +✅ **Backwards Compatible: YES** +⏳ **Token Optimization: PENDING (Phase 2)** + +The router infrastructure is complete and functional. The system now supports tool discovery and organized access to all 59 tools. Phase 2 optimization (hiding routed tools) can be implemented when ready for maximum token savings. diff --git a/docs/archive/SCHEMATIC_WIRING_PLAN.md b/docs/archive/SCHEMATIC_WIRING_PLAN.md index b929b6b..e99b148 100644 --- a/docs/archive/SCHEMATIC_WIRING_PLAN.md +++ b/docs/archive/SCHEMATIC_WIRING_PLAN.md @@ -1,670 +1,711 @@ -# Schematic Wiring Implementation Plan - -**Date:** 2026-01-10 -**Status:** Planning Phase -**Priority:** HIGH (User-requested feature for Issue #26) - ---- - -## Executive Summary - -This plan outlines the implementation of complete schematic wiring functionality for the KiCAD MCP Server. Currently, component placement works perfectly with dynamic symbol loading, but wire/connection tools are incomplete or non-functional. - -**Goal:** Enable users to create complete, functional schematics with wired connections between components through the MCP interface. - ---- - -## Current State Analysis - -### What Exists ✅ - -**Files:** -- `python/commands/connection_schematic.py` - ConnectionManager class with wire/label methods -- MCP handlers in `kicad_interface.py` for 6 connection-related tools - -**MCP Tools (Registered):** -1. `add_schematic_wire` - Add wire between two points -2. `add_schematic_connection` - Connect two component pins -3. `add_schematic_net_label` - Add net label -4. `connect_to_net` - Connect pin to named net -5. `get_net_connections` - Query net connections -6. `generate_netlist` - Generate netlist from schematic - -**ConnectionManager Methods:** -- `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_net_label(schematic, net_name, position)` - Add label -- `connect_to_net(schematic, component_ref, pin_name, net_name)` - Pin to net -- `get_pin_location(symbol, pin_name)` - Get pin coordinates -- `get_net_connections(schematic, net_name)` - Query connections -- `generate_netlist(schematic)` - Generate netlist - -### What's Broken/Missing ❌ - -**Problem 1: kicad-skip API Uncertainty** -- Code assumes `schematic.wire.append()` exists -- Code assumes `schematic.label.append()` exists -- Code assumes pins have `.name` and `.location` attributes -- **Need to verify what kicad-skip actually supports** - -**Problem 2: Pin Location Calculation** -- Current implementation tries to calculate absolute pin positions -- May not account for symbol rotation -- May not work with multi-unit symbols -- Pin numbering vs pin naming confusion - -**Problem 3: No Visual Feedback** -- No way to verify wires were created correctly -- No validation of wire endpoints -- No checks for overlapping wires or junctions - -**Problem 4: Limited Testing** -- No integration tests for wiring functionality -- No validation with real KiCad schematics -- User reported `add_schematic_wire` fails - -**Problem 5: Missing Features** -- No junction (wire intersection) support -- No bus support (multi-bit signals) -- No no-connect flags -- No power symbols (VCC, GND graphical symbols) -- No hierarchical labels - ---- - -## Technical Challenges - -### Challenge 1: kicad-skip Wire API - -**Issue:** The kicad-skip library documentation is sparse. We need to determine: -- Does `schematic.wire` exist? -- What's the correct API to add wires? -- How are wires stored in .kicad_sch files? - -**S-Expression Format (KiCad 8/9):** -```lisp -(wire (pts (xy 100 100) (xy 200 100)) - (stroke (width 0) (type default)) - (uuid "12345678-1234-1234-1234-123456789012") -) -``` - -**Approach:** -1. Examine kicad-skip source code -2. Test wire creation manually with kicad-skip -3. Fall back to S-expression manipulation if necessary (similar to dynamic symbol loading) - -### Challenge 2: Pin Location Discovery - -**Issue:** Need to find exact pin coordinates for automatic wiring. - -**Pin Data in Symbols:** -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:** -- Symbol position (x, y) -- Symbol rotation angle -- Pin offset from symbol origin -- Pin number/name mapping - -**Solution:** -1. Parse symbol definition to find pin definitions -2. Apply transformation matrix (position + rotation) to pin coordinates -3. Return absolute pin position in schematic space - -### Challenge 3: Smart Wire Routing - -**Issue:** Users don't want to manually specify every wire segment. - -**Desired Behavior:** -``` -User: "Connect R1 pin 1 to C1 pin 1" -System: - - Calculate R1 pin 1 location: (100, 100) - - Calculate C1 pin 1 location: (150, 120) - - Create wire path (orthogonal routing preferred): - - (100, 100) → (100, 120) → (150, 120) - - Or simple direct: (100, 100) → (150, 120) -``` - -**Auto-Routing Options:** -1. **Direct** - Single wire segment (diagonal if needed) -2. **Orthogonal** - Only horizontal/vertical segments (2 segments) -3. **Manhattan** - Complex path avoiding components (3+ segments) - -**Phase 1 Approach:** Start with direct wiring, add orthogonal later. - -### Challenge 4: Net Label Integration - -**Issue:** Labels need to attach to wires, not float in space. - -**KiCad Behavior:** -- Labels must touch a wire or pin -- Labels create electrical connections at their attachment point -- Multiple labels with same name = connected net - -**Implementation:** -- When adding label, find nearest wire endpoint -- Attach label to that coordinate -- Or create short wire stub for label attachment - ---- - -## Implementation Phases - -### Phase 1: Core Wire Functionality (Week 1) - -**Goal:** Get basic wiring working with kicad-skip API - -**Tasks:** - -1. **Research kicad-skip Wire API** (4 hours) - - Read kicad-skip source code - - Test wire creation with Python REPL - - Document actual API methods - - Create test schematic with manual wires - -2. **Fix Wire Creation** (6 hours) - - Update ConnectionManager.add_wire() with correct API - - Handle S-expression manipulation if needed - - Add UUID generation for wires - - Test with simple wire (100,100) → (200,100) - -3. **Implement Pin Discovery** (8 hours) - - Parse symbol definitions to extract pin data - - Handle pin coordinates relative to symbol - - Apply rotation transformation - - Test with R, C, LED from dynamic symbols - -4. **Fix add_schematic_connection** (4 hours) - - Use correct pin discovery - - Create direct wire between pins - - Handle error cases (pin not found, etc.) - - Test with R1 pin 2 → C1 pin 1 - -5. **Integration Testing** (4 hours) - - Create test schematic with R, C, LED - - Wire R to C - - Wire C to LED - - Verify schematic opens in KiCad - - Verify electrical connectivity - -**Deliverables:** -- Working `add_schematic_wire` tool -- Working `add_schematic_connection` tool -- Pin location discovery working -- Integration test passing -- Documentation updated - -**Success Criteria:** -- User can connect two resistor pins with MCP command -- Wire appears in KiCad schematic viewer -- Netlist shows electrical connection - ---- - -### Phase 2: Net Labels & Named Nets (Week 1-2) - -**Goal:** Enable named net connections (VCC, GND, etc.) - -**Tasks:** - -1. **Fix Net Label Creation** (4 hours) - - Update ConnectionManager.add_net_label() - - Use correct kicad-skip API or S-expression - - Position labels correctly - - Test label creation - -2. **Implement connect_to_net** (6 hours) - - Create wire stub from pin - - Attach label to wire endpoint - - Support common nets (VCC, GND, 3V3, etc.) - - Test with multiple components on same net - -3. **Net Connection Discovery** (6 hours) - - Parse wires and labels in schematic - - Build connectivity graph - - Implement get_net_connections() - - Return all pins on a net - -4. **Power Symbol Support** (8 hours) - - Add power symbols to templates (VCC, GND, 3V3, 5V) - - Or dynamically load from power library - - Connect power pins to power nets - - Test complete circuit with power - -5. **Testing** (4 hours) - - Create circuit with VCC, GND nets - - Connect multiple components to each net - - Verify net connectivity - - Generate and validate netlist - -**Deliverables:** -- Working `add_schematic_net_label` tool -- Working `connect_to_net` tool -- Working `get_net_connections` tool -- Power symbol support -- Netlist generation working - -**Success Criteria:** -- User can label nets VCC, GND -- Multiple components connect to same net -- Netlist correctly shows net membership - ---- - -### Phase 3: Advanced Features (Week 2-3) - -**Goal:** Professional schematic features - -**Tasks:** - -1. **Junction Support** (4 hours) - - Detect wire intersections - - Add junction dots at T-junctions - - S-expression: `(junction (at x y) (diameter 0) (uuid ...))` - -2. **No-Connect Flags** (2 hours) - - Add "X" marks on unused pins - - S-expression: `(no_connect (at x y) (uuid ...))` - -3. **Orthogonal Routing** (6 hours) - - Implement 2-segment wire routing - - Horizontal-then-vertical or vertical-then-horizontal - - Choose best path based on pin positions - -4. **Bus Support** (8 hours) - - Multi-bit signal buses - - Bus labels (e.g., "D[0..7]") - - Bus entries for individual signals - -5. **Hierarchical Labels** (8 hours) - - Labels for hierarchical sheets - - Input/Output/Bidirectional types - - Sheet connections - -**Deliverables:** -- Junction creation -- No-connect support -- Smart orthogonal routing -- Bus and hierarchical label support - -**Success Criteria:** -- Wires route cleanly around components -- Junctions appear at wire intersections -- Unused pins marked with no-connect - ---- - -### Phase 4: Validation & Polish (Week 3-4) - -**Goal:** Production-ready reliability - -**Tasks:** - -1. **ERC Integration** (6 hours) - - Electrical Rule Check - - Detect floating nets - - Detect unconnected pins - - Detect short circuits - -2. **Visual Validation** (4 hours) - - Export schematic to PDF after wiring - - Verify wire appearance - - Check net label placement - -3. **Comprehensive Testing** (8 hours) - - Test with Device library components - - Test with IC components (multi-pin) - - Test with connectors - - Test complex circuits (10+ components) - -4. **Error Handling** (4 hours) - - Graceful failures - - Clear error messages - - Validation of coordinates - - Duplicate net label detection - -5. **Documentation** (6 hours) - - Update MCP tool descriptions - - Add usage examples to README - - Create wiring tutorial - - Add to CHANGELOG - -**Deliverables:** -- ERC validation -- Comprehensive test suite -- Error handling -- Complete documentation - -**Success Criteria:** -- 95%+ test pass rate -- Users can create functional circuits -- Clear error messages on failures - ---- - -## Technical Approach - -### Option A: Use kicad-skip Native API (Preferred) - -**If kicad-skip supports wires natively:** - -```python -# Add wire using native API -wire = schematic.wire.new( - start=[100, 100], - end=[200, 100] -) - -# Add label -label = schematic.label.new( - text="VCC", - at=[150, 100] -) -``` - -**Pros:** -- Clean, maintainable code -- Follows library patterns -- Less likely to break - -**Cons:** -- Depends on kicad-skip having these features -- May be limited in functionality - -### Option B: S-Expression Manipulation (Fallback) - -**If kicad-skip doesn't support wires:** - -Use the same approach as dynamic symbol loading: - -```python -import sexpdata -from sexpdata import Symbol - -# Read schematic -with open(schematic_path, 'r') as f: - sch_data = sexpdata.loads(f.read()) - -# Create wire S-expression -wire_sexp = [ - Symbol('wire'), - [Symbol('pts'), - [Symbol('xy'), 100, 100], - [Symbol('xy'), 200, 100] - ], - [Symbol('stroke'), [Symbol('width'), 0], [Symbol('type'), Symbol('default')]], - [Symbol('uuid'), str(uuid.uuid4())] -] - -# Insert into schematic -sch_data.append(wire_sexp) - -# Write back -with open(schematic_path, 'w') as f: - f.write(sexpdata.dumps(sch_data)) -``` - -**Pros:** -- Complete control -- Can implement any feature -- Works around library limitations - -**Cons:** -- More complex -- Requires deep KiCad format knowledge -- More maintenance - -### Hybrid Approach (Recommended) - -1. Try kicad-skip native API first -2. Fall back to S-expression if needed -3. Use S-expression for advanced features (junctions, buses) - ---- - -## Pin Discovery Algorithm - -### Step 1: Get Symbol Definition - -Symbols are stored in `lib_symbols` section: - -```lisp -(lib_symbols - (symbol "Device:R" - (symbol "R_0_1" - (rectangle (start -1 -2.54) (end 1 2.54) ...)) - (symbol "R_1_1" - (pin passive line (at 0 3.81 270) (length 1.27) - (name "~" (effects (font (size 1.27 1.27)))) - (number "1" (effects (font (size 1.27 1.27))))) - (pin passive line (at 0 -3.81 90) (length 1.27) - (name "~" (effects (font (size 1.27 1.27)))) - (number "2" (effects (font (size 1.27 1.27))))))) -``` - -### Step 2: Extract Pin Information - -For each pin: -- Number (e.g., "1", "2") -- Name (e.g., "GND", "VCC", "~" for unnamed) -- Position relative to symbol origin: `(at x y angle)` -- Length (distance from symbol body to connection point) - -### Step 3: Get Symbol Instance Position - -From symbol instance in schematic: - -```lisp -(symbol (lib_id "Device:R") (at 100 100 0) (unit 1) - (property "Reference" "R1" ...)) -``` - -Extract: -- Position: `(at 100 100 0)` = x=100, y=100, rotation=0° -- Reference: "R1" - -### Step 4: Calculate Absolute Pin Position - -```python -def get_absolute_pin_position(symbol_instance, pin_definition): - # Symbol position - symbol_x, symbol_y, symbol_rotation = symbol_instance.at.value - - # Pin position relative to symbol - pin_x, pin_y, pin_angle = pin_definition.at.value - - # Apply rotation transformation - if symbol_rotation != 0: - # Rotate pin coordinates around origin - rad = math.radians(symbol_rotation) - rotated_x = pin_x * math.cos(rad) - pin_y * math.sin(rad) - rotated_y = pin_x * math.sin(rad) + pin_y * math.cos(rad) - pin_x, pin_y = rotated_x, rotated_y - - # Translate to absolute position - abs_x = symbol_x + pin_x - abs_y = symbol_y + pin_y - - return [abs_x, abs_y] -``` - ---- - -## Wire Routing Strategies - -### Strategy 1: Direct Wire (Phase 1) - -Simplest: single wire segment from pin A to pin B. - -``` -R1 pin 2 C1 pin 1 - o-------------o -``` - -**Pros:** Simple, fast -**Cons:** Diagonal wires (not standard practice) - -### Strategy 2: Orthogonal 2-Segment (Phase 3) - -Two segments: horizontal then vertical, or vertical then horizontal. - -``` -R1 pin 2 C1 pin 1 - o-----┐ - │ - └------o -``` - -**Algorithm:** -1. Calculate midpoint -2. Route horizontal to midpoint -3. Route vertical to target -4. Or vice versa based on direction - -**Pros:** Standard practice, cleaner schematics -**Cons:** Slightly more complex - -### Strategy 3: Manhattan Routing (Future) - -Complex multi-segment paths avoiding components. - -**Pros:** Professional appearance -**Cons:** Requires collision detection, path planning - ---- - -## Testing Strategy - -### Unit Tests - -Test individual functions: -- `test_add_wire()` - Wire creation -- `test_get_pin_location()` - Pin discovery -- `test_add_net_label()` - Label creation -- `test_calculate_pin_position()` - Coordinate math - -### Integration Tests - -Test complete workflows: -- `test_connect_two_resistors()` - Wire R1 to R2 -- `test_connect_to_vcc_net()` - Multiple components to VCC -- `test_generate_netlist()` - Netlist accuracy -- `test_schematic_opens_in_kicad()` - File validity - -### Manual Validation - -- Create test schematic in KiCad manually -- Add same connections via MCP -- Compare results -- Verify electrical connectivity in KiCad - ---- - -## Success Metrics - -### Phase 1 Success: -- [ ] `add_schematic_wire` works (coordinates) -- [ ] `add_schematic_connection` works (pin to pin) -- [ ] Wires appear in KiCad schematic -- [ ] Netlist shows connections -- [ ] 3+ integration tests passing - -### Phase 2 Success: -- [ ] Net labels work (VCC, GND, etc.) -- [ ] Multiple components on same net -- [ ] `get_net_connections` returns correct results -- [ ] Netlist includes named nets -- [ ] 5+ integration tests passing - -### Phase 3 Success: -- [ ] Junctions at wire intersections -- [ ] Orthogonal routing preferred -- [ ] No-connect flags on unused pins -- [ ] 10+ integration tests passing - -### Phase 4 Success: -- [ ] ERC detects errors -- [ ] 95%+ test coverage -- [ ] Complete documentation -- [ ] User can create functional circuits without errors - ---- - -## Risk Assessment - -| Risk | Probability | Impact | Mitigation | -|------|------------|--------|------------| -| kicad-skip lacks wire API | High | High | Use S-expression fallback | -| Pin discovery complex | Medium | Medium | Test with multiple symbol types | -| Rotation math errors | Medium | High | Extensive testing, validation | -| Performance issues | Low | Medium | Optimize S-expression parsing | -| KiCad format changes | Low | High | Version detection, compatibility | - ---- - -## Dependencies - -**Required:** -- kicad-skip >= 0.1.0 (or compatible) -- sexpdata (already dependency for dynamic loading) -- Python 3.8+ - -**Optional:** -- KiCad CLI for validation (`kicad-cli sch export netlist`) - ---- - -## Timeline Estimate - -**Phase 1:** 1 week (26 hours) -**Phase 2:** 1 week (28 hours) -**Phase 3:** 1.5 weeks (28 hours) -**Phase 4:** 1.5 weeks (28 hours) - -**Total:** 5 weeks (110 hours) - -**Accelerated path (core features only):** 2-3 weeks (Phases 1-2) - ---- - -## Next Immediate Steps - -1. **Research kicad-skip Wire API** (TODAY) - - Test with Python REPL - - Document findings - - Choose implementation approach - -2. **Create Test Environment** (TOMORROW) - - Set up test schematic - - Manual wire creation in KiCad - - Export for comparison - -3. **Implement Basic Wire** (THIS WEEK) - - Update ConnectionManager.add_wire() - - Test with simple coordinates - - Verify in KiCad - -4. **Fix Pin Discovery** (THIS WEEK) - - Parse symbol definitions - - Calculate absolute positions - - Test with rotated symbols - ---- - -## User Communication - -**For Issue #26:** - -Update users that: -- ✅ Component placement is DONE (with 10,000+ symbols) -- ⏳ Wire/connection tools are IN PROGRESS -- 📅 Estimated completion: 2-3 weeks for core functionality -- 🎯 Goal: Complete functional schematics with wiring - ---- - -**Status:** Ready for implementation -**Owner:** TBD -**Priority:** HIGH (user-blocking feature) +# Schematic Wiring Implementation Plan + +**Date:** 2026-01-10 +**Status:** Planning Phase +**Priority:** HIGH (User-requested feature for Issue #26) + +--- + +## Executive Summary + +This plan outlines the implementation of complete schematic wiring functionality for the KiCAD MCP Server. Currently, component placement works perfectly with dynamic symbol loading, but wire/connection tools are incomplete or non-functional. + +**Goal:** Enable users to create complete, functional schematics with wired connections between components through the MCP interface. + +--- + +## Current State Analysis + +### What Exists ✅ + +**Files:** + +- `python/commands/connection_schematic.py` - ConnectionManager class with wire/label methods +- MCP handlers in `kicad_interface.py` for 6 connection-related tools + +**MCP Tools (Registered):** + +1. `add_schematic_wire` - Add wire between two points +2. `add_schematic_connection` - Connect two component pins +3. `add_schematic_net_label` - Add net label +4. `connect_to_net` - Connect pin to named net +5. `get_net_connections` - Query net connections +6. `generate_netlist` - Generate netlist from schematic + +**ConnectionManager Methods:** + +- `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_net_label(schematic, net_name, position)` - Add label +- `connect_to_net(schematic, component_ref, pin_name, net_name)` - Pin to net +- `get_pin_location(symbol, pin_name)` - Get pin coordinates +- `get_net_connections(schematic, net_name)` - Query connections +- `generate_netlist(schematic)` - Generate netlist + +### What's Broken/Missing ❌ + +**Problem 1: kicad-skip API Uncertainty** + +- Code assumes `schematic.wire.append()` exists +- Code assumes `schematic.label.append()` exists +- Code assumes pins have `.name` and `.location` attributes +- **Need to verify what kicad-skip actually supports** + +**Problem 2: Pin Location Calculation** + +- Current implementation tries to calculate absolute pin positions +- May not account for symbol rotation +- May not work with multi-unit symbols +- Pin numbering vs pin naming confusion + +**Problem 3: No Visual Feedback** + +- No way to verify wires were created correctly +- No validation of wire endpoints +- No checks for overlapping wires or junctions + +**Problem 4: Limited Testing** + +- No integration tests for wiring functionality +- No validation with real KiCad schematics +- User reported `add_schematic_wire` fails + +**Problem 5: Missing Features** + +- No junction (wire intersection) support +- No bus support (multi-bit signals) +- No no-connect flags +- No power symbols (VCC, GND graphical symbols) +- No hierarchical labels + +--- + +## Technical Challenges + +### Challenge 1: kicad-skip Wire API + +**Issue:** The kicad-skip library documentation is sparse. We need to determine: + +- Does `schematic.wire` exist? +- What's the correct API to add wires? +- How are wires stored in .kicad_sch files? + +**S-Expression Format (KiCad 8/9):** + +```lisp +(wire (pts (xy 100 100) (xy 200 100)) + (stroke (width 0) (type default)) + (uuid "12345678-1234-1234-1234-123456789012") +) +``` + +**Approach:** + +1. Examine kicad-skip source code +2. Test wire creation manually with kicad-skip +3. Fall back to S-expression manipulation if necessary (similar to dynamic symbol loading) + +### Challenge 2: Pin Location Discovery + +**Issue:** Need to find exact pin coordinates for automatic wiring. + +**Pin Data in Symbols:** +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:** + +- Symbol position (x, y) +- Symbol rotation angle +- Pin offset from symbol origin +- Pin number/name mapping + +**Solution:** + +1. Parse symbol definition to find pin definitions +2. Apply transformation matrix (position + rotation) to pin coordinates +3. Return absolute pin position in schematic space + +### Challenge 3: Smart Wire Routing + +**Issue:** Users don't want to manually specify every wire segment. + +**Desired Behavior:** + +``` +User: "Connect R1 pin 1 to C1 pin 1" +System: + - Calculate R1 pin 1 location: (100, 100) + - Calculate C1 pin 1 location: (150, 120) + - Create wire path (orthogonal routing preferred): + - (100, 100) → (100, 120) → (150, 120) + - Or simple direct: (100, 100) → (150, 120) +``` + +**Auto-Routing Options:** + +1. **Direct** - Single wire segment (diagonal if needed) +2. **Orthogonal** - Only horizontal/vertical segments (2 segments) +3. **Manhattan** - Complex path avoiding components (3+ segments) + +**Phase 1 Approach:** Start with direct wiring, add orthogonal later. + +### Challenge 4: Net Label Integration + +**Issue:** Labels need to attach to wires, not float in space. + +**KiCad Behavior:** + +- Labels must touch a wire or pin +- Labels create electrical connections at their attachment point +- Multiple labels with same name = connected net + +**Implementation:** + +- When adding label, find nearest wire endpoint +- Attach label to that coordinate +- Or create short wire stub for label attachment + +--- + +## Implementation Phases + +### Phase 1: Core Wire Functionality (Week 1) + +**Goal:** Get basic wiring working with kicad-skip API + +**Tasks:** + +1. **Research kicad-skip Wire API** (4 hours) + - Read kicad-skip source code + - Test wire creation with Python REPL + - Document actual API methods + - Create test schematic with manual wires + +2. **Fix Wire Creation** (6 hours) + - Update ConnectionManager.add_wire() with correct API + - Handle S-expression manipulation if needed + - Add UUID generation for wires + - Test with simple wire (100,100) → (200,100) + +3. **Implement Pin Discovery** (8 hours) + - Parse symbol definitions to extract pin data + - Handle pin coordinates relative to symbol + - Apply rotation transformation + - Test with R, C, LED from dynamic symbols + +4. **Fix add_schematic_connection** (4 hours) + - Use correct pin discovery + - Create direct wire between pins + - Handle error cases (pin not found, etc.) + - Test with R1 pin 2 → C1 pin 1 + +5. **Integration Testing** (4 hours) + - Create test schematic with R, C, LED + - Wire R to C + - Wire C to LED + - Verify schematic opens in KiCad + - Verify electrical connectivity + +**Deliverables:** + +- Working `add_schematic_wire` tool +- Working `add_schematic_connection` tool +- Pin location discovery working +- Integration test passing +- Documentation updated + +**Success Criteria:** + +- User can connect two resistor pins with MCP command +- Wire appears in KiCad schematic viewer +- Netlist shows electrical connection + +--- + +### Phase 2: Net Labels & Named Nets (Week 1-2) + +**Goal:** Enable named net connections (VCC, GND, etc.) + +**Tasks:** + +1. **Fix Net Label Creation** (4 hours) + - Update ConnectionManager.add_net_label() + - Use correct kicad-skip API or S-expression + - Position labels correctly + - Test label creation + +2. **Implement connect_to_net** (6 hours) + - Create wire stub from pin + - Attach label to wire endpoint + - Support common nets (VCC, GND, 3V3, etc.) + - Test with multiple components on same net + +3. **Net Connection Discovery** (6 hours) + - Parse wires and labels in schematic + - Build connectivity graph + - Implement get_net_connections() + - Return all pins on a net + +4. **Power Symbol Support** (8 hours) + - Add power symbols to templates (VCC, GND, 3V3, 5V) + - Or dynamically load from power library + - Connect power pins to power nets + - Test complete circuit with power + +5. **Testing** (4 hours) + - Create circuit with VCC, GND nets + - Connect multiple components to each net + - Verify net connectivity + - Generate and validate netlist + +**Deliverables:** + +- Working `add_schematic_net_label` tool +- Working `connect_to_net` tool +- Working `get_net_connections` tool +- Power symbol support +- Netlist generation working + +**Success Criteria:** + +- User can label nets VCC, GND +- Multiple components connect to same net +- Netlist correctly shows net membership + +--- + +### Phase 3: Advanced Features (Week 2-3) + +**Goal:** Professional schematic features + +**Tasks:** + +1. **Junction Support** (4 hours) + - Detect wire intersections + - Add junction dots at T-junctions + - S-expression: `(junction (at x y) (diameter 0) (uuid ...))` + +2. **No-Connect Flags** (2 hours) + - Add "X" marks on unused pins + - S-expression: `(no_connect (at x y) (uuid ...))` + +3. **Orthogonal Routing** (6 hours) + - Implement 2-segment wire routing + - Horizontal-then-vertical or vertical-then-horizontal + - Choose best path based on pin positions + +4. **Bus Support** (8 hours) + - Multi-bit signal buses + - Bus labels (e.g., "D[0..7]") + - Bus entries for individual signals + +5. **Hierarchical Labels** (8 hours) + - Labels for hierarchical sheets + - Input/Output/Bidirectional types + - Sheet connections + +**Deliverables:** + +- Junction creation +- No-connect support +- Smart orthogonal routing +- Bus and hierarchical label support + +**Success Criteria:** + +- Wires route cleanly around components +- Junctions appear at wire intersections +- Unused pins marked with no-connect + +--- + +### Phase 4: Validation & Polish (Week 3-4) + +**Goal:** Production-ready reliability + +**Tasks:** + +1. **ERC Integration** (6 hours) + - Electrical Rule Check + - Detect floating nets + - Detect unconnected pins + - Detect short circuits + +2. **Visual Validation** (4 hours) + - Export schematic to PDF after wiring + - Verify wire appearance + - Check net label placement + +3. **Comprehensive Testing** (8 hours) + - Test with Device library components + - Test with IC components (multi-pin) + - Test with connectors + - Test complex circuits (10+ components) + +4. **Error Handling** (4 hours) + - Graceful failures + - Clear error messages + - Validation of coordinates + - Duplicate net label detection + +5. **Documentation** (6 hours) + - Update MCP tool descriptions + - Add usage examples to README + - Create wiring tutorial + - Add to CHANGELOG + +**Deliverables:** + +- ERC validation +- Comprehensive test suite +- Error handling +- Complete documentation + +**Success Criteria:** + +- 95%+ test pass rate +- Users can create functional circuits +- Clear error messages on failures + +--- + +## Technical Approach + +### Option A: Use kicad-skip Native API (Preferred) + +**If kicad-skip supports wires natively:** + +```python +# Add wire using native API +wire = schematic.wire.new( + start=[100, 100], + end=[200, 100] +) + +# Add label +label = schematic.label.new( + text="VCC", + at=[150, 100] +) +``` + +**Pros:** + +- Clean, maintainable code +- Follows library patterns +- Less likely to break + +**Cons:** + +- Depends on kicad-skip having these features +- May be limited in functionality + +### Option B: S-Expression Manipulation (Fallback) + +**If kicad-skip doesn't support wires:** + +Use the same approach as dynamic symbol loading: + +```python +import sexpdata +from sexpdata import Symbol + +# Read schematic +with open(schematic_path, 'r') as f: + sch_data = sexpdata.loads(f.read()) + +# Create wire S-expression +wire_sexp = [ + Symbol('wire'), + [Symbol('pts'), + [Symbol('xy'), 100, 100], + [Symbol('xy'), 200, 100] + ], + [Symbol('stroke'), [Symbol('width'), 0], [Symbol('type'), Symbol('default')]], + [Symbol('uuid'), str(uuid.uuid4())] +] + +# Insert into schematic +sch_data.append(wire_sexp) + +# Write back +with open(schematic_path, 'w') as f: + f.write(sexpdata.dumps(sch_data)) +``` + +**Pros:** + +- Complete control +- Can implement any feature +- Works around library limitations + +**Cons:** + +- More complex +- Requires deep KiCad format knowledge +- More maintenance + +### Hybrid Approach (Recommended) + +1. Try kicad-skip native API first +2. Fall back to S-expression if needed +3. Use S-expression for advanced features (junctions, buses) + +--- + +## Pin Discovery Algorithm + +### Step 1: Get Symbol Definition + +Symbols are stored in `lib_symbols` section: + +```lisp +(lib_symbols + (symbol "Device:R" + (symbol "R_0_1" + (rectangle (start -1 -2.54) (end 1 2.54) ...)) + (symbol "R_1_1" + (pin passive line (at 0 3.81 270) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27))))) + (pin passive line (at 0 -3.81 90) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27))))))) +``` + +### Step 2: Extract Pin Information + +For each pin: + +- Number (e.g., "1", "2") +- Name (e.g., "GND", "VCC", "~" for unnamed) +- Position relative to symbol origin: `(at x y angle)` +- Length (distance from symbol body to connection point) + +### Step 3: Get Symbol Instance Position + +From symbol instance in schematic: + +```lisp +(symbol (lib_id "Device:R") (at 100 100 0) (unit 1) + (property "Reference" "R1" ...)) +``` + +Extract: + +- Position: `(at 100 100 0)` = x=100, y=100, rotation=0° +- Reference: "R1" + +### Step 4: Calculate Absolute Pin Position + +```python +def get_absolute_pin_position(symbol_instance, pin_definition): + # Symbol position + symbol_x, symbol_y, symbol_rotation = symbol_instance.at.value + + # Pin position relative to symbol + pin_x, pin_y, pin_angle = pin_definition.at.value + + # Apply rotation transformation + if symbol_rotation != 0: + # Rotate pin coordinates around origin + rad = math.radians(symbol_rotation) + rotated_x = pin_x * math.cos(rad) - pin_y * math.sin(rad) + rotated_y = pin_x * math.sin(rad) + pin_y * math.cos(rad) + pin_x, pin_y = rotated_x, rotated_y + + # Translate to absolute position + abs_x = symbol_x + pin_x + abs_y = symbol_y + pin_y + + return [abs_x, abs_y] +``` + +--- + +## Wire Routing Strategies + +### Strategy 1: Direct Wire (Phase 1) + +Simplest: single wire segment from pin A to pin B. + +``` +R1 pin 2 C1 pin 1 + o-------------o +``` + +**Pros:** Simple, fast +**Cons:** Diagonal wires (not standard practice) + +### Strategy 2: Orthogonal 2-Segment (Phase 3) + +Two segments: horizontal then vertical, or vertical then horizontal. + +``` +R1 pin 2 C1 pin 1 + o-----┐ + │ + └------o +``` + +**Algorithm:** + +1. Calculate midpoint +2. Route horizontal to midpoint +3. Route vertical to target +4. Or vice versa based on direction + +**Pros:** Standard practice, cleaner schematics +**Cons:** Slightly more complex + +### Strategy 3: Manhattan Routing (Future) + +Complex multi-segment paths avoiding components. + +**Pros:** Professional appearance +**Cons:** Requires collision detection, path planning + +--- + +## Testing Strategy + +### Unit Tests + +Test individual functions: + +- `test_add_wire()` - Wire creation +- `test_get_pin_location()` - Pin discovery +- `test_add_net_label()` - Label creation +- `test_calculate_pin_position()` - Coordinate math + +### Integration Tests + +Test complete workflows: + +- `test_connect_two_resistors()` - Wire R1 to R2 +- `test_connect_to_vcc_net()` - Multiple components to VCC +- `test_generate_netlist()` - Netlist accuracy +- `test_schematic_opens_in_kicad()` - File validity + +### Manual Validation + +- Create test schematic in KiCad manually +- Add same connections via MCP +- Compare results +- Verify electrical connectivity in KiCad + +--- + +## Success Metrics + +### Phase 1 Success: + +- [ ] `add_schematic_wire` works (coordinates) +- [ ] `add_schematic_connection` works (pin to pin) +- [ ] Wires appear in KiCad schematic +- [ ] Netlist shows connections +- [ ] 3+ integration tests passing + +### Phase 2 Success: + +- [ ] Net labels work (VCC, GND, etc.) +- [ ] Multiple components on same net +- [ ] `get_net_connections` returns correct results +- [ ] Netlist includes named nets +- [ ] 5+ integration tests passing + +### Phase 3 Success: + +- [ ] Junctions at wire intersections +- [ ] Orthogonal routing preferred +- [ ] No-connect flags on unused pins +- [ ] 10+ integration tests passing + +### Phase 4 Success: + +- [ ] ERC detects errors +- [ ] 95%+ test coverage +- [ ] Complete documentation +- [ ] User can create functional circuits without errors + +--- + +## Risk Assessment + +| Risk | Probability | Impact | Mitigation | +| ------------------------- | ----------- | ------ | -------------------------------- | +| kicad-skip lacks wire API | High | High | Use S-expression fallback | +| Pin discovery complex | Medium | Medium | Test with multiple symbol types | +| Rotation math errors | Medium | High | Extensive testing, validation | +| Performance issues | Low | Medium | Optimize S-expression parsing | +| KiCad format changes | Low | High | Version detection, compatibility | + +--- + +## Dependencies + +**Required:** + +- kicad-skip >= 0.1.0 (or compatible) +- sexpdata (already dependency for dynamic loading) +- Python 3.8+ + +**Optional:** + +- KiCad CLI for validation (`kicad-cli sch export netlist`) + +--- + +## Timeline Estimate + +**Phase 1:** 1 week (26 hours) +**Phase 2:** 1 week (28 hours) +**Phase 3:** 1.5 weeks (28 hours) +**Phase 4:** 1.5 weeks (28 hours) + +**Total:** 5 weeks (110 hours) + +**Accelerated path (core features only):** 2-3 weeks (Phases 1-2) + +--- + +## Next Immediate Steps + +1. **Research kicad-skip Wire API** (TODAY) + - Test with Python REPL + - Document findings + - Choose implementation approach + +2. **Create Test Environment** (TOMORROW) + - Set up test schematic + - Manual wire creation in KiCad + - Export for comparison + +3. **Implement Basic Wire** (THIS WEEK) + - Update ConnectionManager.add_wire() + - Test with simple coordinates + - Verify in KiCad + +4. **Fix Pin Discovery** (THIS WEEK) + - Parse symbol definitions + - Calculate absolute positions + - Test with rotated symbols + +--- + +## User Communication + +**For Issue #26:** + +Update users that: + +- ✅ Component placement is DONE (with 10,000+ symbols) +- ⏳ Wire/connection tools are IN PROGRESS +- 📅 Estimated completion: 2-3 weeks for core functionality +- 🎯 Goal: Complete functional schematics with wiring + +--- + +**Status:** Ready for implementation +**Owner:** TBD +**Priority:** HIGH (user-blocking feature) diff --git a/docs/archive/SCHEMATIC_WORKFLOW_FIX.md b/docs/archive/SCHEMATIC_WORKFLOW_FIX.md index c315e33..ac732e7 100644 --- a/docs/archive/SCHEMATIC_WORKFLOW_FIX.md +++ b/docs/archive/SCHEMATIC_WORKFLOW_FIX.md @@ -1,125 +1,133 @@ -# Schematic Workflow Fix - Issue #26 - -## Problem Summary - -The schematic workflow was completely broken due to incorrect usage of the kicad-skip library: - -1. **`create_project`** only created PCB files, no schematic -2. **`create_schematic`** created orphaned schematic files not linked to projects -3. **`add_schematic_component`** called non-existent `schematic.add_symbol()` method -4. Project files didn't reference schematics in their structure - -## Root Cause - -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: -> "symbols: these don't have a new()" because they require complex mappings to library elements, pins, and properties. - -## Solution - -### 1. Template-Based Approach - -Created a template schematic (`python/templates/template_with_symbols.kicad_sch`) with: -- Complete `lib_symbols` section defining R, C, LED symbols -- 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 - -### 2. Updated Files - -**python/commands/project.py:** -- Now creates both `.kicad_pcb` AND `.kicad_sch` files -- Project file includes schematic reference in `sheets` array -- Copies template schematic with cloneable symbols - -**python/commands/schematic.py:** -- Uses template file instead of creating from scratch -- Proper minimal schematic structure when template unavailable - -**python/commands/component_schematic.py:** -- Completely rewritten to use `clone()` API -- Maps component types to template symbols -- Proper UUID generation for each cloned symbol -- Correct position setting: `symbol.at.value = [x, y, rotation]` - -### 3. Correct Workflow - -```python -from commands.project import ProjectCommands -from commands.schematic import SchematicManager -from commands.component_schematic import ComponentManager - -# Step 1: Create project (creates both PCB and schematic) -project_cmd = ProjectCommands() -result = project_cmd.create_project({ - "name": "MyProject", - "path": "/path/to/project" -}) - -# Step 2: Load the schematic -sch = SchematicManager.load_schematic(result['project']['schematicPath']) - -# Step 3: Add components by cloning templates -component_def = { - "type": "R", # Maps to _TEMPLATE_R - "reference": "R1", # Component reference - "value": "10k", # Component value - "footprint": "Resistor_SMD:R_0603_1608Metric", - "x": 50.8, # Position in mm - "y": 50.8, # Position in mm - "rotation": 0 # Rotation in degrees -} -symbol = ComponentManager.add_component(sch, component_def) - -# Step 4: Save the schematic -SchematicManager.save_schematic(sch, result['project']['schematicPath']) -``` - -## Supported Component Types - -Currently supported template symbols: -- `R` - Resistor (maps to `_TEMPLATE_R`) -- `C` - Capacitor (maps to `_TEMPLATE_C`) -- `D` or `LED` - LED (maps to `_TEMPLATE_D`) - -To add more component types, update: -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` - -## Testing - -Comprehensive test created at `/tmp/test_schematic_workflow.py`: -- Creates project with schematic -- Loads schematic -- Adds R, C, LED components -- Saves schematic -- Validates with `kicad-cli sch export pdf` - -All tests passing ✓ - -## Files Modified - -- `python/commands/project.py` - Added schematic creation -- `python/commands/schematic.py` - Fixed template usage -- `python/commands/component_schematic.py` - Rewritten to use clone() API -- `python/templates/empty.kicad_sch` - Minimal template (created) -- `python/templates/template_with_symbols.kicad_sch` - Template with cloneable symbols (created) - -## Limitations - -1. Can only add components that have templates defined -2. Template symbols remain in schematic (but marked as DNP/not in BOM) -3. Complex symbols (multi-unit, hierarchical) may need custom templates - -## Future Improvements - -1. Add more component templates (transistors, connectors, ICs) -2. Dynamic template generation from KiCad symbol libraries -3. Auto-hide template symbols in schematic -4. Support for custom user templates - -## References - -- GitHub Issue: #26 -- kicad-skip documentation: https://github.com/psychogenic/kicad-skip -- Test results: `/tmp/test_schematic_workflow/` +# Schematic Workflow Fix - Issue #26 + +## Problem Summary + +The schematic workflow was completely broken due to incorrect usage of the kicad-skip library: + +1. **`create_project`** only created PCB files, no schematic +2. **`create_schematic`** created orphaned schematic files not linked to projects +3. **`add_schematic_component`** called non-existent `schematic.add_symbol()` method +4. Project files didn't reference schematics in their structure + +## Root Cause + +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: + +> "symbols: these don't have a new()" because they require complex mappings to library elements, pins, and properties. + +## Solution + +### 1. Template-Based Approach + +Created a template schematic (`python/templates/template_with_symbols.kicad_sch`) with: + +- Complete `lib_symbols` section defining R, C, LED symbols +- 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 + +### 2. Updated Files + +**python/commands/project.py:** + +- Now creates both `.kicad_pcb` AND `.kicad_sch` files +- Project file includes schematic reference in `sheets` array +- Copies template schematic with cloneable symbols + +**python/commands/schematic.py:** + +- Uses template file instead of creating from scratch +- Proper minimal schematic structure when template unavailable + +**python/commands/component_schematic.py:** + +- Completely rewritten to use `clone()` API +- Maps component types to template symbols +- Proper UUID generation for each cloned symbol +- Correct position setting: `symbol.at.value = [x, y, rotation]` + +### 3. Correct Workflow + +```python +from commands.project import ProjectCommands +from commands.schematic import SchematicManager +from commands.component_schematic import ComponentManager + +# Step 1: Create project (creates both PCB and schematic) +project_cmd = ProjectCommands() +result = project_cmd.create_project({ + "name": "MyProject", + "path": "/path/to/project" +}) + +# Step 2: Load the schematic +sch = SchematicManager.load_schematic(result['project']['schematicPath']) + +# Step 3: Add components by cloning templates +component_def = { + "type": "R", # Maps to _TEMPLATE_R + "reference": "R1", # Component reference + "value": "10k", # Component value + "footprint": "Resistor_SMD:R_0603_1608Metric", + "x": 50.8, # Position in mm + "y": 50.8, # Position in mm + "rotation": 0 # Rotation in degrees +} +symbol = ComponentManager.add_component(sch, component_def) + +# Step 4: Save the schematic +SchematicManager.save_schematic(sch, result['project']['schematicPath']) +``` + +## Supported Component Types + +Currently supported template symbols: + +- `R` - Resistor (maps to `_TEMPLATE_R`) +- `C` - Capacitor (maps to `_TEMPLATE_C`) +- `D` or `LED` - LED (maps to `_TEMPLATE_D`) + +To add more component types, update: + +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` + +## Testing + +Comprehensive test created at `/tmp/test_schematic_workflow.py`: + +- Creates project with schematic +- Loads schematic +- Adds R, C, LED components +- Saves schematic +- Validates with `kicad-cli sch export pdf` + +All tests passing ✓ + +## Files Modified + +- `python/commands/project.py` - Added schematic creation +- `python/commands/schematic.py` - Fixed template usage +- `python/commands/component_schematic.py` - Rewritten to use clone() API +- `python/templates/empty.kicad_sch` - Minimal template (created) +- `python/templates/template_with_symbols.kicad_sch` - Template with cloneable symbols (created) + +## Limitations + +1. Can only add components that have templates defined +2. Template symbols remain in schematic (but marked as DNP/not in BOM) +3. Complex symbols (multi-unit, hierarchical) may need custom templates + +## Future Improvements + +1. Add more component templates (transistors, connectors, ICs) +2. Dynamic template generation from KiCad symbol libraries +3. Auto-hide template symbols in schematic +4. Support for custom user templates + +## References + +- GitHub Issue: #26 +- kicad-skip documentation: https://github.com/psychogenic/kicad-skip +- Test results: `/tmp/test_schematic_workflow/` diff --git a/docs/archive/WEEK1_SESSION1_SUMMARY.md b/docs/archive/WEEK1_SESSION1_SUMMARY.md index efa3206..acb11a0 100644 --- a/docs/archive/WEEK1_SESSION1_SUMMARY.md +++ b/docs/archive/WEEK1_SESSION1_SUMMARY.md @@ -1,505 +1,538 @@ -# Week 1 - Session 1 Summary -**Date:** October 25, 2025 -**Status:** ✅ **EXCELLENT PROGRESS** - ---- - -## 🎯 Mission - -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:** -- Linux-first platform support -- JLCPCB & Digikey integration -- End-to-end PCB design workflow -- Migrate to KiCAD IPC API (future-proof) - ---- - -## ✅ What We Accomplished Today - -### 1. **Complete Project Analysis** 📊 - -Created comprehensive documentation: -- ✅ Full codebase exploration (6 tool categories, 9 Python command modules) -- ✅ Identified critical issues (deprecated SWIG API, Windows-only paths) -- ✅ Researched KiCAD IPC API, JLCPCB API, Digikey API -- ✅ Researched MCP best practices - -**Key Findings:** -- SWIG Python bindings are DEPRECATED (will be removed in KiCAD 10.0) -- Current architecture works but is Windows-centric -- Missing core AI-assisted features (part selection, BOM management) - ---- - -### 2. **12-Week Rebuild Plan Created** 🗺️ - -Designed comprehensive roadmap in 4 phases: - -#### **Phase 1: Foundation & Migration (Weeks 1-4)** -- Linux compatibility -- KiCAD IPC API migration -- Performance improvements (caching, async) - -#### **Phase 2: Core AI Features (Weeks 5-8)** -- JLCPCB integration (parts library + pricing) -- Digikey integration (parametric search) -- Smart BOM management -- Design pattern library - -#### **Phase 3: Novice-Friendly Workflows (Weeks 9-11)** -- Guided step-by-step workflows -- Visual feedback system -- Intelligent error recovery - -#### **Phase 4: Polish & Launch (Week 12)** -- Testing, documentation, community building - ---- - -### 3. **Linux Compatibility Infrastructure** 🐧 - -Created complete cross-platform support: - -**Files Created:** -- ✅ `docs/LINUX_COMPATIBILITY_AUDIT.md` - Comprehensive audit report -- ✅ `python/utils/platform_helper.py` - Cross-platform path detection -- ✅ `config/linux-config.example.json` - Linux configuration template -- ✅ `config/windows-config.example.json` - Windows configuration template -- ✅ `config/macos-config.example.json` - macOS configuration template - -**Platform Helper Features:** -```python -PlatformHelper.get_config_dir() # ~/.config/kicad-mcp on Linux -PlatformHelper.get_log_dir() # ~/.config/kicad-mcp/logs -PlatformHelper.get_cache_dir() # ~/.cache/kicad-mcp -PlatformHelper.get_kicad_python_paths() # Auto-detects KiCAD install -``` - ---- - -### 4. **CI/CD Pipeline** 🚀 - -Created GitHub Actions workflow: - -**File:** `.github/workflows/ci.yml` - -**Testing Matrix:** -- TypeScript build on Ubuntu 24.04, 22.04, Windows, macOS -- Python tests on Python 3.10, 3.11, 3.12 -- Integration tests with KiCAD 9.0 installation -- Code quality checks (ESLint, Prettier, Black, MyPy) -- Docker build test (future) -- Coverage reporting to Codecov - -**Status:** Ready to run on next git push - ---- - -### 5. **Python Testing Framework** 🧪 - -Set up comprehensive testing infrastructure: - -**Files Created:** -- ✅ `pytest.ini` - Pytest configuration -- ✅ `requirements.txt` - Production dependencies -- ✅ `requirements-dev.txt` - Development dependencies -- ✅ `tests/test_platform_helper.py` - 20+ unit tests - -**Test Categories:** -```python -@pytest.mark.unit # Fast, no external dependencies -@pytest.mark.integration # Requires KiCAD -@pytest.mark.linux # Linux-specific tests -@pytest.mark.windows # Windows-specific tests -``` - -**Test Results:** -``` -✅ Platform detection works correctly -✅ Config directories follow XDG spec on Linux -✅ Python 3.12.3 detected correctly -✅ Paths created automatically -``` - ---- - -### 6. **Developer Documentation** 📚 - -Created contributor guide: - -**File:** `CONTRIBUTING.md` - -**Includes:** -- Platform-specific setup instructions (Linux/Windows/macOS) -- Project structure overview -- Development workflow -- Testing guide -- Code style guidelines (Black, MyPy, ESLint) -- Pull request process - ---- - -### 7. **Dependencies Management** 📦 - -**Production Dependencies (requirements.txt):** -``` -kicad-skip>=0.1.0 # Schematic manipulation -Pillow>=9.0.0 # Image processing -cairosvg>=2.7.0 # SVG rendering -pydantic>=2.5.0 # Data validation -requests>=2.31.0 # API clients -python-dotenv>=1.0.0 # Config management -``` - -**Development Dependencies:** -``` -pytest>=7.4.0 # Testing -black>=23.7.0 # Code formatting -mypy>=1.5.0 # Type checking -pylint>=2.17.0 # Linting -``` - ---- - -## 🎯 Week 1 Progress Tracking - -### ✅ Completed Tasks (8/9) - -1. ✅ **Audit codebase for Linux compatibility** - - Created comprehensive audit document - - Identified all platform-specific issues - - Prioritized fixes (P0, P1, P2, P3) - -2. ✅ **Create GitHub Actions CI/CD** - - Multi-platform testing matrix - - Python + TypeScript testing - - Code quality checks - - Coverage reporting - -3. ✅ **Fix path handling** - - Created PlatformHelper utility - - Follows XDG Base Directory spec on Linux - - Auto-detects KiCAD installation paths - -4. ✅ **Update logging paths** - - Linux: ~/.config/kicad-mcp/logs - - Windows: ~\.kicad-mcp\logs - - macOS: ~/Library/Application Support/kicad-mcp/logs - -5. ✅ **Create CONTRIBUTING.md** - - Complete developer guide - - Platform-specific setup - - Testing instructions - -6. ✅ **Set up pytest framework** - - pytest.ini with coverage - - Test markers for organization - - Sample tests passing - -7. ✅ **Create platform config templates** - - linux-config.example.json - - windows-config.example.json - - macos-config.example.json - -8. ✅ **Create development infrastructure** - - requirements.txt + requirements-dev.txt - - Platform helper utilities - - Test framework - -### ⏳ Remaining Week 1 Tasks (1/9) - -9. ⏳ **Docker container for testing** (Optional for Week 1) - - Will create in Week 2 for consistent testing environment - ---- - -## 📁 Files Created/Modified Today - -### New Files (17) - -``` -.github/workflows/ci.yml # CI/CD pipeline -config/linux-config.example.json # Linux config -config/windows-config.example.json # Windows config -config/macos-config.example.json # macOS config -docs/LINUX_COMPATIBILITY_AUDIT.md # Audit report -docs/WEEK1_SESSION1_SUMMARY.md # This file -python/utils/__init__.py # Utils package -python/utils/platform_helper.py # Platform detection (300 lines) -tests/__init__.py # Tests package -tests/test_platform_helper.py # Platform tests (150 lines) -pytest.ini # Pytest config -requirements.txt # Python deps -requirements-dev.txt # Python dev deps -CONTRIBUTING.md # Developer guide -``` - -### Modified Files (1) - -``` -python/utils/platform_helper.py # Fixed docstring warnings -``` - ---- - -## 🧪 Testing Status - -### Unit Tests - -```bash -$ python3 python/utils/platform_helper.py -✅ Platform detection works -✅ Linux detected correctly -✅ Python 3.12.3 found -✅ Config dir: /home/chris/.config/kicad-mcp -✅ Log dir: /home/chris/.config/kicad-mcp/logs -✅ Cache dir: /home/chris/.cache/kicad-mcp -⚠️ KiCAD not installed (expected on dev machine) -``` - -### CI/CD Pipeline - -``` -Status: Ready to run -Triggers: Push to main/develop, Pull Requests -Platforms: Ubuntu 24.04, 22.04, Windows, macOS -Python: 3.10, 3.11, 3.12 -Node: 18.x, 20.x, 22.x -``` - ---- - -## 🎯 Next Steps (Week 1 Remaining) - -### Week 1 - Days 2-5 - -1. **Update README.md with Linux installation** - - Add Linux-specific setup instructions - - Link to platform-specific configs - - Add troubleshooting section - -2. **Test on actual Ubuntu 24.04 LTS** - - Install KiCAD 9.0 - - Run full test suite - - Document any issues found - -3. **Begin IPC API research** (Week 2 prep) - - Install `kicad-python` package - - Test IPC API connection - - Compare with SWIG API - -4. **Start JLCPCB API research** (Week 5 prep) - - Apply for API access - - Review API documentation - - Plan integration architecture - ---- - -## 📊 Metrics - -### Code Quality - -- **Python Code Style:** Black formatting ready -- **Type Hints:** 100% in new code (platform_helper.py) -- **Documentation:** Comprehensive docstrings -- **Test Coverage:** 20+ unit tests for platform_helper - -### Platform Support - -- **Windows:** ✅ Original support maintained -- **Linux:** ✅ Full support added -- **macOS:** ✅ Partial support (untested) - -### Dependencies - -- **Python Packages:** 7 production, 10 development -- **Node.js Packages:** Existing (no changes yet) -- **External APIs:** 0 (planned: JLCPCB, Digikey) - ---- - -## 🚀 Impact Assessment - -### Before Today -- ❌ Windows-only -- ❌ No CI/CD -- ❌ No tests -- ❌ Hardcoded paths -- ❌ No developer documentation - -### After Today -- ✅ Cross-platform (Linux/Windows/macOS) -- ✅ GitHub Actions CI/CD -- ✅ 20+ unit tests with pytest -- ✅ Platform-agnostic paths (XDG spec) -- ✅ Complete developer guide - -**Developer Experience:** Massively improved -**Contributor Onboarding:** Now takes minutes instead of hours -**Code Maintainability:** Significantly better -**Future-Proofing:** Foundation laid for IPC API migration - ---- - -## 💡 Key Decisions Made - -### 1. **IPC API Migration: Proceed Immediately** ✅ -- SWIG is deprecated, will be removed in KiCAD 10.0 -- IPC API is stable, officially supported -- Better performance and cross-language support -- Decision: Migrate in Week 2-3 - -### 2. **Linux-First Approach** ✅ -- Hobbyists often use Linux -- Better for open-source development -- Easier CI/CD with GitHub Actions -- Decision: Linux is primary development platform - -### 3. **JLCPCB Integration Priority** ✅ -- Hobbyists love JLCPCB for cheap assembly -- "Basic parts" filter is critical -- Better stock than Digikey for hobbyists -- Decision: JLCPCB before Digikey - -### 4. **Pytest over unittest** ✅ -- More Pythonic -- Better fixtures and parametrization -- Industry standard -- Decision: Use pytest for all tests - ---- - -## 🎓 Lessons Learned - -### Technical Insights - -1. **XDG Base Directory Spec** - Linux has clear standards for config/cache/data -2. **pathlib > os.path** - More readable, cross-platform by default -3. **Platform detection** - Check environment variables before hardcoding paths -4. **Type hints** - Make code self-documenting and catch bugs early - -### Process Insights - -1. **Audit first, code second** - Understanding the problem space saves time -2. **Infrastructure before features** - CI/CD and testing pay dividends -3. **Documentation is code** - Good docs prevent future confusion -4. **Cross-platform from day 1** - Retrofitting is painful - ---- - -## 🎉 Highlights - -### Biggest Win -✨ **Complete cross-platform infrastructure in one session** - -### Most Valuable Addition -🔧 **PlatformHelper utility** - Solves path issues elegantly - -### Best Decision -🎯 **Creating comprehensive plan first** - Clear roadmap for 12 weeks - -### Unexpected Discovery -⚠️ **SWIG deprecation** - Would have been a nasty surprise later! - ---- - -## 🤝 Collaboration Notes - -### What Went Well -- Clear requirements from user -- Good research phase before coding -- Incremental progress with testing - -### What to Improve -- Need actual Ubuntu 24.04 testing -- Should run pytest suite -- Need to test KiCAD 9.0 integration - ---- - -## 📅 Schedule Status - -### Week 1 Goals -- [x] Linux compatibility audit (**100% complete**) -- [x] CI/CD setup (**100% complete**) -- [x] Development infrastructure (**100% complete**) -- [ ] Linux installation testing (**0% complete** - needs Ubuntu 24.04) - -**Overall Week 1 Progress: ~80% complete** - -**Status: 🟢 ON TRACK** - ---- - -## 🎯 Next Session Goals - -1. Update README.md with Linux instructions -2. Test on actual Ubuntu 24.04 LTS with KiCAD 9.0 -3. Run full pytest suite -4. Fix any issues found during testing -5. Begin IPC API research (install kicad-python) - -**Estimated Time: 2-3 hours** - ---- - -## 📝 Notes for Future - -### Architecture Decisions to Make -- [ ] Redis vs in-memory cache? -- [ ] Session storage approach? -- [ ] WebSocket vs STDIO for future scaling? - -### Dependencies to Research -- [ ] JLCPCB API client library (exists?) -- [ ] Digikey API v3 (issus/DigiKeyApi looks good) -- [ ] kicad-python 0.5.0 compatibility - -### Questions to Answer -- [ ] How to handle KiCAD running vs not running (IPC requirement)? -- [ ] Should we support both SWIG and IPC during migration? -- [ ] BOM format standardization? - ---- - -## 🏆 Success Metrics Achieved Today - -| Metric | Target | Achieved | Status | -|--------|--------|----------|--------| -| Platform support | Linux primary | ✅ Linux ready | ✅ | -| CI/CD pipeline | GitHub Actions | ✅ Complete | ✅ | -| Test coverage | Setup pytest | ✅ 20+ tests | ✅ | -| Documentation | CONTRIBUTING.md | ✅ Complete | ✅ | -| Config templates | 3 platforms | ✅ 3 created | ✅ | -| Platform helper | Path utilities | ✅ 300 lines | ✅ | - -**Overall Session Rating: 🌟🌟🌟🌟🌟 (5/5)** - ---- - -## 🙏 Acknowledgments - -- **KiCAD Team** - For the excellent IPC API documentation -- **Anthropic** - For MCP specification and best practices -- **JLCPCB/Digikey** - For API availability - ---- - -**Session End Time:** October 25, 2025 -**Duration:** ~2 hours -**Files Created:** 17 -**Lines of Code:** ~1000+ -**Tests Written:** 20+ -**Documentation Pages:** 5 - ---- - -## 🚀 Ready for Week 1, Day 2! - -**Next Session Focus:** Linux testing + README updates -**Energy Level:** 🔋🔋🔋🔋🔋 (High) -**Confidence Level:** 💪💪💪💪💪 (Very High) - -Let's keep this momentum going! 🎉 +# Week 1 - Session 1 Summary + +**Date:** October 25, 2025 +**Status:** ✅ **EXCELLENT PROGRESS** + +--- + +## 🎯 Mission + +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:** + +- Linux-first platform support +- JLCPCB & Digikey integration +- End-to-end PCB design workflow +- Migrate to KiCAD IPC API (future-proof) + +--- + +## ✅ What We Accomplished Today + +### 1. **Complete Project Analysis** 📊 + +Created comprehensive documentation: + +- ✅ Full codebase exploration (6 tool categories, 9 Python command modules) +- ✅ Identified critical issues (deprecated SWIG API, Windows-only paths) +- ✅ Researched KiCAD IPC API, JLCPCB API, Digikey API +- ✅ Researched MCP best practices + +**Key Findings:** + +- SWIG Python bindings are DEPRECATED (will be removed in KiCAD 10.0) +- Current architecture works but is Windows-centric +- Missing core AI-assisted features (part selection, BOM management) + +--- + +### 2. **12-Week Rebuild Plan Created** 🗺️ + +Designed comprehensive roadmap in 4 phases: + +#### **Phase 1: Foundation & Migration (Weeks 1-4)** + +- Linux compatibility +- KiCAD IPC API migration +- Performance improvements (caching, async) + +#### **Phase 2: Core AI Features (Weeks 5-8)** + +- JLCPCB integration (parts library + pricing) +- Digikey integration (parametric search) +- Smart BOM management +- Design pattern library + +#### **Phase 3: Novice-Friendly Workflows (Weeks 9-11)** + +- Guided step-by-step workflows +- Visual feedback system +- Intelligent error recovery + +#### **Phase 4: Polish & Launch (Week 12)** + +- Testing, documentation, community building + +--- + +### 3. **Linux Compatibility Infrastructure** 🐧 + +Created complete cross-platform support: + +**Files Created:** + +- ✅ `docs/LINUX_COMPATIBILITY_AUDIT.md` - Comprehensive audit report +- ✅ `python/utils/platform_helper.py` - Cross-platform path detection +- ✅ `config/linux-config.example.json` - Linux configuration template +- ✅ `config/windows-config.example.json` - Windows configuration template +- ✅ `config/macos-config.example.json` - macOS configuration template + +**Platform Helper Features:** + +```python +PlatformHelper.get_config_dir() # ~/.config/kicad-mcp on Linux +PlatformHelper.get_log_dir() # ~/.config/kicad-mcp/logs +PlatformHelper.get_cache_dir() # ~/.cache/kicad-mcp +PlatformHelper.get_kicad_python_paths() # Auto-detects KiCAD install +``` + +--- + +### 4. **CI/CD Pipeline** 🚀 + +Created GitHub Actions workflow: + +**File:** `.github/workflows/ci.yml` + +**Testing Matrix:** + +- TypeScript build on Ubuntu 24.04, 22.04, Windows, macOS +- Python tests on Python 3.10, 3.11, 3.12 +- Integration tests with KiCAD 9.0 installation +- Code quality checks (ESLint, Prettier, Black, MyPy) +- Docker build test (future) +- Coverage reporting to Codecov + +**Status:** Ready to run on next git push + +--- + +### 5. **Python Testing Framework** 🧪 + +Set up comprehensive testing infrastructure: + +**Files Created:** + +- ✅ `pytest.ini` - Pytest configuration +- ✅ `requirements.txt` - Production dependencies +- ✅ `requirements-dev.txt` - Development dependencies +- ✅ `tests/test_platform_helper.py` - 20+ unit tests + +**Test Categories:** + +```python +@pytest.mark.unit # Fast, no external dependencies +@pytest.mark.integration # Requires KiCAD +@pytest.mark.linux # Linux-specific tests +@pytest.mark.windows # Windows-specific tests +``` + +**Test Results:** + +``` +✅ Platform detection works correctly +✅ Config directories follow XDG spec on Linux +✅ Python 3.12.3 detected correctly +✅ Paths created automatically +``` + +--- + +### 6. **Developer Documentation** 📚 + +Created contributor guide: + +**File:** `CONTRIBUTING.md` + +**Includes:** + +- Platform-specific setup instructions (Linux/Windows/macOS) +- Project structure overview +- Development workflow +- Testing guide +- Code style guidelines (Black, MyPy, ESLint) +- Pull request process + +--- + +### 7. **Dependencies Management** 📦 + +**Production Dependencies (requirements.txt):** + +``` +kicad-skip>=0.1.0 # Schematic manipulation +Pillow>=9.0.0 # Image processing +cairosvg>=2.7.0 # SVG rendering +pydantic>=2.5.0 # Data validation +requests>=2.31.0 # API clients +python-dotenv>=1.0.0 # Config management +``` + +**Development Dependencies:** + +``` +pytest>=7.4.0 # Testing +black>=23.7.0 # Code formatting +mypy>=1.5.0 # Type checking +pylint>=2.17.0 # Linting +``` + +--- + +## 🎯 Week 1 Progress Tracking + +### ✅ Completed Tasks (8/9) + +1. ✅ **Audit codebase for Linux compatibility** + - Created comprehensive audit document + - Identified all platform-specific issues + - Prioritized fixes (P0, P1, P2, P3) + +2. ✅ **Create GitHub Actions CI/CD** + - Multi-platform testing matrix + - Python + TypeScript testing + - Code quality checks + - Coverage reporting + +3. ✅ **Fix path handling** + - Created PlatformHelper utility + - Follows XDG Base Directory spec on Linux + - Auto-detects KiCAD installation paths + +4. ✅ **Update logging paths** + - Linux: ~/.config/kicad-mcp/logs + - Windows: ~\.kicad-mcp\logs + - macOS: ~/Library/Application Support/kicad-mcp/logs + +5. ✅ **Create CONTRIBUTING.md** + - Complete developer guide + - Platform-specific setup + - Testing instructions + +6. ✅ **Set up pytest framework** + - pytest.ini with coverage + - Test markers for organization + - Sample tests passing + +7. ✅ **Create platform config templates** + - linux-config.example.json + - windows-config.example.json + - macos-config.example.json + +8. ✅ **Create development infrastructure** + - requirements.txt + requirements-dev.txt + - Platform helper utilities + - Test framework + +### ⏳ Remaining Week 1 Tasks (1/9) + +9. ⏳ **Docker container for testing** (Optional for Week 1) + - Will create in Week 2 for consistent testing environment + +--- + +## 📁 Files Created/Modified Today + +### New Files (17) + +``` +.github/workflows/ci.yml # CI/CD pipeline +config/linux-config.example.json # Linux config +config/windows-config.example.json # Windows config +config/macos-config.example.json # macOS config +docs/LINUX_COMPATIBILITY_AUDIT.md # Audit report +docs/WEEK1_SESSION1_SUMMARY.md # This file +python/utils/__init__.py # Utils package +python/utils/platform_helper.py # Platform detection (300 lines) +tests/__init__.py # Tests package +tests/test_platform_helper.py # Platform tests (150 lines) +pytest.ini # Pytest config +requirements.txt # Python deps +requirements-dev.txt # Python dev deps +CONTRIBUTING.md # Developer guide +``` + +### Modified Files (1) + +``` +python/utils/platform_helper.py # Fixed docstring warnings +``` + +--- + +## 🧪 Testing Status + +### Unit Tests + +```bash +$ python3 python/utils/platform_helper.py +✅ Platform detection works +✅ Linux detected correctly +✅ Python 3.12.3 found +✅ Config dir: /home/chris/.config/kicad-mcp +✅ Log dir: /home/chris/.config/kicad-mcp/logs +✅ Cache dir: /home/chris/.cache/kicad-mcp +⚠️ KiCAD not installed (expected on dev machine) +``` + +### CI/CD Pipeline + +``` +Status: Ready to run +Triggers: Push to main/develop, Pull Requests +Platforms: Ubuntu 24.04, 22.04, Windows, macOS +Python: 3.10, 3.11, 3.12 +Node: 18.x, 20.x, 22.x +``` + +--- + +## 🎯 Next Steps (Week 1 Remaining) + +### Week 1 - Days 2-5 + +1. **Update README.md with Linux installation** + - Add Linux-specific setup instructions + - Link to platform-specific configs + - Add troubleshooting section + +2. **Test on actual Ubuntu 24.04 LTS** + - Install KiCAD 9.0 + - Run full test suite + - Document any issues found + +3. **Begin IPC API research** (Week 2 prep) + - Install `kicad-python` package + - Test IPC API connection + - Compare with SWIG API + +4. **Start JLCPCB API research** (Week 5 prep) + - Apply for API access + - Review API documentation + - Plan integration architecture + +--- + +## 📊 Metrics + +### Code Quality + +- **Python Code Style:** Black formatting ready +- **Type Hints:** 100% in new code (platform_helper.py) +- **Documentation:** Comprehensive docstrings +- **Test Coverage:** 20+ unit tests for platform_helper + +### Platform Support + +- **Windows:** ✅ Original support maintained +- **Linux:** ✅ Full support added +- **macOS:** ✅ Partial support (untested) + +### Dependencies + +- **Python Packages:** 7 production, 10 development +- **Node.js Packages:** Existing (no changes yet) +- **External APIs:** 0 (planned: JLCPCB, Digikey) + +--- + +## 🚀 Impact Assessment + +### Before Today + +- ❌ Windows-only +- ❌ No CI/CD +- ❌ No tests +- ❌ Hardcoded paths +- ❌ No developer documentation + +### After Today + +- ✅ Cross-platform (Linux/Windows/macOS) +- ✅ GitHub Actions CI/CD +- ✅ 20+ unit tests with pytest +- ✅ Platform-agnostic paths (XDG spec) +- ✅ Complete developer guide + +**Developer Experience:** Massively improved +**Contributor Onboarding:** Now takes minutes instead of hours +**Code Maintainability:** Significantly better +**Future-Proofing:** Foundation laid for IPC API migration + +--- + +## 💡 Key Decisions Made + +### 1. **IPC API Migration: Proceed Immediately** ✅ + +- SWIG is deprecated, will be removed in KiCAD 10.0 +- IPC API is stable, officially supported +- Better performance and cross-language support +- Decision: Migrate in Week 2-3 + +### 2. **Linux-First Approach** ✅ + +- Hobbyists often use Linux +- Better for open-source development +- Easier CI/CD with GitHub Actions +- Decision: Linux is primary development platform + +### 3. **JLCPCB Integration Priority** ✅ + +- Hobbyists love JLCPCB for cheap assembly +- "Basic parts" filter is critical +- Better stock than Digikey for hobbyists +- Decision: JLCPCB before Digikey + +### 4. **Pytest over unittest** ✅ + +- More Pythonic +- Better fixtures and parametrization +- Industry standard +- Decision: Use pytest for all tests + +--- + +## 🎓 Lessons Learned + +### Technical Insights + +1. **XDG Base Directory Spec** - Linux has clear standards for config/cache/data +2. **pathlib > os.path** - More readable, cross-platform by default +3. **Platform detection** - Check environment variables before hardcoding paths +4. **Type hints** - Make code self-documenting and catch bugs early + +### Process Insights + +1. **Audit first, code second** - Understanding the problem space saves time +2. **Infrastructure before features** - CI/CD and testing pay dividends +3. **Documentation is code** - Good docs prevent future confusion +4. **Cross-platform from day 1** - Retrofitting is painful + +--- + +## 🎉 Highlights + +### Biggest Win + +✨ **Complete cross-platform infrastructure in one session** + +### Most Valuable Addition + +🔧 **PlatformHelper utility** - Solves path issues elegantly + +### Best Decision + +🎯 **Creating comprehensive plan first** - Clear roadmap for 12 weeks + +### Unexpected Discovery + +⚠️ **SWIG deprecation** - Would have been a nasty surprise later! + +--- + +## 🤝 Collaboration Notes + +### What Went Well + +- Clear requirements from user +- Good research phase before coding +- Incremental progress with testing + +### What to Improve + +- Need actual Ubuntu 24.04 testing +- Should run pytest suite +- Need to test KiCAD 9.0 integration + +--- + +## 📅 Schedule Status + +### Week 1 Goals + +- [x] Linux compatibility audit (**100% complete**) +- [x] CI/CD setup (**100% complete**) +- [x] Development infrastructure (**100% complete**) +- [ ] Linux installation testing (**0% complete** - needs Ubuntu 24.04) + +**Overall Week 1 Progress: ~80% complete** + +**Status: 🟢 ON TRACK** + +--- + +## 🎯 Next Session Goals + +1. Update README.md with Linux instructions +2. Test on actual Ubuntu 24.04 LTS with KiCAD 9.0 +3. Run full pytest suite +4. Fix any issues found during testing +5. Begin IPC API research (install kicad-python) + +**Estimated Time: 2-3 hours** + +--- + +## 📝 Notes for Future + +### Architecture Decisions to Make + +- [ ] Redis vs in-memory cache? +- [ ] Session storage approach? +- [ ] WebSocket vs STDIO for future scaling? + +### Dependencies to Research + +- [ ] JLCPCB API client library (exists?) +- [ ] Digikey API v3 (issus/DigiKeyApi looks good) +- [ ] kicad-python 0.5.0 compatibility + +### Questions to Answer + +- [ ] How to handle KiCAD running vs not running (IPC requirement)? +- [ ] Should we support both SWIG and IPC during migration? +- [ ] BOM format standardization? + +--- + +## 🏆 Success Metrics Achieved Today + +| Metric | Target | Achieved | Status | +| ---------------- | --------------- | -------------- | ------ | +| Platform support | Linux primary | ✅ Linux ready | ✅ | +| CI/CD pipeline | GitHub Actions | ✅ Complete | ✅ | +| Test coverage | Setup pytest | ✅ 20+ tests | ✅ | +| Documentation | CONTRIBUTING.md | ✅ Complete | ✅ | +| Config templates | 3 platforms | ✅ 3 created | ✅ | +| Platform helper | Path utilities | ✅ 300 lines | ✅ | + +**Overall Session Rating: 🌟🌟🌟🌟🌟 (5/5)** + +--- + +## 🙏 Acknowledgments + +- **KiCAD Team** - For the excellent IPC API documentation +- **Anthropic** - For MCP specification and best practices +- **JLCPCB/Digikey** - For API availability + +--- + +**Session End Time:** October 25, 2025 +**Duration:** ~2 hours +**Files Created:** 17 +**Lines of Code:** ~1000+ +**Tests Written:** 20+ +**Documentation Pages:** 5 + +--- + +## 🚀 Ready for Week 1, Day 2! + +**Next Session Focus:** Linux testing + README updates +**Energy Level:** 🔋🔋🔋🔋🔋 (High) +**Confidence Level:** 💪💪💪💪💪 (Very High) + +Let's keep this momentum going! 🎉 diff --git a/docs/archive/WEEK1_SESSION2_SUMMARY.md b/docs/archive/WEEK1_SESSION2_SUMMARY.md index 76eb8d3..d12f170 100644 --- a/docs/archive/WEEK1_SESSION2_SUMMARY.md +++ b/docs/archive/WEEK1_SESSION2_SUMMARY.md @@ -1,422 +1,457 @@ -# Week 1 - Session 2 Summary -**Date:** October 25, 2025 (Afternoon) -**Status:** 🚀 **OUTSTANDING PROGRESS** - ---- - -## 🎯 Session Goals - -Continue Week 1 implementation while user installs KiCAD: -1. Update README with comprehensive Linux guide -2. Create installation scripts -3. Begin IPC API preparation -4. Set up development infrastructure - ---- - -## ✅ Completed Work - -### 1. **README.md Major Update** 📚 - -**File:** `README.md` - -**Changes:** -- ✅ Updated project status to reflect v2.0 rebuild -- ✅ Added collapsible platform-specific installation sections: - - 🐧 **Linux (Ubuntu/Debian)** - Primary, detailed - - 🪟 **Windows 10/11** - Fully supported - - 🍎 **macOS** - Experimental -- ✅ Updated system requirements (Linux primary platform) -- ✅ Added Quick Start section with test commands -- ✅ Better visual organization with emojis and status indicators - -**Impact:** New users can now install on Linux in < 10 minutes! - ---- - -### 2. **Linux Installation Script** 🛠️ - -**File:** `scripts/install-linux.sh` - -**Features:** -- ✅ Fully automated Ubuntu/Debian installation -- ✅ Color-coded output (info/success/warning/error) -- ✅ Safety checks (platform detection, command validation) -- ✅ Installs: - - KiCAD 9.0 from PPA - - Node.js 20.x - - Python dependencies - - Builds TypeScript -- ✅ Verification checks after installation -- ✅ Helpful next-steps guidance - -**Usage:** -```bash -cd kicad-mcp-server -./scripts/install-linux.sh -``` - -**Lines of Code:** ~200 lines of robust shell script - ---- - -### 3. **Pre-Commit Hooks Configuration** 🔧 - -**File:** `.pre-commit-config.yaml` - -**Hooks Added:** -- ✅ **Python:** - - Black (code formatting) - - isort (import sorting) - - MyPy (type checking) - - Flake8 (linting) - - Bandit (security checks) -- ✅ **TypeScript/JavaScript:** - - Prettier (formatting) -- ✅ **General:** - - Trailing whitespace removal - - End-of-file fixer - - YAML/JSON validation - - Large file detection - - Merge conflict detection - - Private key detection -- ✅ **Markdown:** - - Markdownlint (formatting) - -**Setup:** -```bash -pip install pre-commit -pre-commit install -``` - -**Impact:** Automatic code quality enforcement on every commit! - ---- - -### 4. **IPC API Migration Plan** 📋 - -**File:** `docs/IPC_API_MIGRATION_PLAN.md` - -**Comprehensive 30-page migration guide:** -- ✅ Why migrate (SWIG deprecation analysis) -- ✅ IPC API architecture overview -- ✅ 4-phase migration strategy (10 days) -- ✅ API comparison tables (SWIG vs IPC) -- ✅ Testing strategy -- ✅ Rollback plan -- ✅ Success criteria -- ✅ Timeline with day-by-day tasks - -**Key Insights:** -- SWIG will be removed in KiCAD 10.0 -- IPC is faster for some operations -- Protocol Buffers ensure API stability -- Multi-language support opens future possibilities - ---- - -### 5. **IPC API Abstraction Layer** 🏗️ - -**New Module:** `python/kicad_api/` - -**Files Created (5):** - -1. **`__init__.py`** (20 lines) - - Package exports - - Version info - - Usage examples - -2. **`base.py`** (180 lines) - - `KiCADBackend` abstract base class - - `BoardAPI` abstract interface - - Custom exceptions (`BackendError`, `ConnectionError`, etc.) - - Defines contract for all backends - -3. **`factory.py`** (160 lines) - - `create_backend()` - Smart backend selection - - Auto-detection (try IPC, fall back to SWIG) - - Environment variable support (`KICAD_BACKEND`) - - `get_available_backends()` - Diagnostic function - - Comprehensive error handling - -4. **`ipc_backend.py`** (210 lines) - - `IPCBackend` class (kicad-python wrapper) - - `IPCBoardAPI` class - - Connection management - - Skeleton methods (to be implemented in Week 2-3) - - Clear TODO markers for migration - -5. **`swig_backend.py`** (220 lines) - - `SWIGBackend` class (wraps existing code) - - `SWIGBoardAPI` class - - Backward compatibility layer - - Deprecation warnings - - Bridges old commands to new interface - -**Total Lines of Code:** ~800 lines - -**Architecture:** -```python -from kicad_api import create_backend - -# Auto-detect best backend -backend = create_backend() - -# Or specify explicitly -backend = create_backend('ipc') # Use IPC -backend = create_backend('swig') # Use SWIG (deprecated) - -# Use unified interface -if backend.connect(): - board = backend.get_board() - board.set_size(100, 80) -``` - -**Key Features:** -- ✅ Abstraction allows painless migration -- ✅ Both backends can coexist during transition -- ✅ Easy testing (compare SWIG vs IPC outputs) -- ✅ Future-proof (add new backends easily) -- ✅ Type hints throughout -- ✅ Comprehensive error handling - ---- - -### 6. **Enhanced package.json** 📦 - -**File:** `package.json` - -**Improvements:** -- ✅ Version bumped to `2.0.0-alpha.1` -- ✅ Better description -- ✅ Enhanced npm scripts: - ```json - "build:watch": "tsc --watch" - "clean": "rm -rf dist" - "rebuild": "npm run clean && npm run build" - "test": "npm run test:ts && npm run test:py" - "test:py": "pytest tests/ -v" - "test:coverage": "pytest with coverage" - "lint": "npm run lint:ts && npm run lint:py" - "lint:py": "black + mypy + flake8" - "format": "prettier + black" - ``` - -**Impact:** Better developer experience, easier workflows - ---- - -## 📊 Statistics - -### Files Created/Modified (Session 2) - -**New Files (10):** -``` -docs/IPC_API_MIGRATION_PLAN.md # 500+ lines -docs/WEEK1_SESSION2_SUMMARY.md # This file -scripts/install-linux.sh # 200 lines -.pre-commit-config.yaml # 60 lines -python/kicad_api/__init__.py # 20 lines -python/kicad_api/base.py # 180 lines -python/kicad_api/factory.py # 160 lines -python/kicad_api/ipc_backend.py # 210 lines -python/kicad_api/swig_backend.py # 220 lines -``` - -**Modified Files (2):** -``` -README.md # Major rewrite -package.json # Enhanced scripts -``` - -**Total New Lines:** ~1,600+ lines of code/documentation - ---- - -### Combined Sessions 1+2 Today - -**Files Created:** 27 -**Lines Written:** ~3,000+ -**Documentation Pages:** 8 -**Tests Created:** 20+ - ---- - -## 🎯 Week 1 Status - -### Progress: **95% Complete** ████████████░ - -| Task | Status | -|------|--------| -| Linux compatibility | ✅ Complete | -| CI/CD pipeline | ✅ Complete | -| Cross-platform paths | ✅ Complete | -| Developer docs | ✅ Complete | -| pytest framework | ✅ Complete | -| Config templates | ✅ Complete | -| Installation scripts | ✅ Complete | -| Pre-commit hooks | ✅ Complete | -| IPC migration plan | ✅ Complete | -| IPC abstraction layer | ✅ Complete | -| README updates | ✅ Complete | -| Testing on Ubuntu | ⏳ Pending (needs KiCAD install) | - -**Only Remaining:** Test with actual KiCAD 9.0 installation! - ---- - -## 🚀 Ready for Week 2 - -### IPC API Migration Prep ✅ - -Everything is in place to begin migration: -- ✅ Abstraction layer architecture defined -- ✅ Base classes and interfaces ready -- ✅ Factory pattern for backend selection -- ✅ SWIG wrapper for backward compatibility -- ✅ IPC skeleton awaiting implementation -- ✅ Comprehensive migration plan documented - -**Week 2 kickoff tasks:** -1. Install `kicad-python` package -2. Test IPC connection to running KiCAD -3. Begin porting `project.py` module -4. Create side-by-side tests (SWIG vs IPC) - ---- - -## 💡 Key Insights from Session 2 - -### 1. **Installation Automation** -The bash script reduces setup time from 30+ minutes to < 10 minutes with zero manual intervention. - -### 2. **Pre-Commit Hooks** -Automatic code quality checks prevent bugs before they're committed. This will save hours in code review. - -### 3. **Abstraction Pattern** -The backend abstraction is elegant - allows gradual migration without breaking existing functionality. Users won't notice the transition. - -### 4. **Documentation Quality** -The IPC migration plan is thorough enough that another developer could execute it independently. - ---- - -## 🧪 Testing Readiness - -### When KiCAD is Installed - -You can immediately test: - -**1. Platform Helper:** -```bash -python3 python/utils/platform_helper.py -``` - -**2. Backend Detection:** -```bash -python3 python/kicad_api/factory.py -``` - -**3. Installation Script:** -```bash -./scripts/install-linux.sh -``` - -**4. Pytest Suite:** -```bash -pytest tests/ -v -``` - -**5. Pre-commit Hooks:** -```bash -pre-commit run --all-files -``` - ---- - -## 📈 Impact Assessment - -### Developer Onboarding -- **Before:** 2-3 hours setup, Windows-only, manual steps -- **After:** 10 minutes automated, cross-platform, one script - -### Code Quality -- **Before:** No automated checks, inconsistent style -- **After:** Pre-commit hooks, 100% type hints, Black formatting - -### Future-Proofing -- **Before:** Deprecated SWIG API, no migration path -- **After:** IPC API ready, abstraction layer in place - -### Documentation -- **Before:** README only, Windows-focused -- **After:** 8 comprehensive docs, Linux-primary, migration guides - ---- - -## 🎯 Next Actions - -### Immediate (Tonight/Tomorrow) -1. Install KiCAD 9.0 on your system -2. Run `./scripts/install-linux.sh` -3. Test backend detection -4. Verify pytest suite passes - -### Week 2 Start (Monday) -1. Install `kicad-python` package -2. Test IPC connection -3. Begin project.py migration -4. Create first IPC API tests - ---- - -## 🏆 Session 2 Achievements - -### Infrastructure -- ✅ Automated Linux installation -- ✅ Pre-commit hooks for code quality -- ✅ Enhanced npm scripts -- ✅ IPC API abstraction layer (800+ lines) - -### Documentation -- ✅ Updated README (Linux-primary) -- ✅ 30-page IPC migration plan -- ✅ Session summaries - -### Architecture -- ✅ Backend abstraction pattern -- ✅ Factory with auto-detection -- ✅ SWIG backward compatibility -- ✅ IPC skeleton ready for implementation - ---- - -## 🎉 Overall Day Summary - -**Sessions 1+2 Combined:** -- ⏱️ **Time:** ~4-5 hours total -- 📝 **Files:** 27 created -- 💻 **Code:** ~3,000+ lines -- 📚 **Docs:** 8 comprehensive pages -- 🧪 **Tests:** 20+ unit tests -- ✅ **Week 1:** 95% complete - -**Status:** 🟢 **AHEAD OF SCHEDULE** - ---- - -## 🚀 Momentum Check - -**Energy Level:** 🔋🔋🔋🔋🔋 (Maximum) -**Code Quality:** ⭐⭐⭐⭐⭐ (Excellent) -**Documentation:** 📖📖📖📖📖 (Comprehensive) -**Architecture:** 🏗️🏗️🏗️🏗️🏗️ (Solid) - -**Ready for Week 2 IPC Migration:** ✅ YES! - ---- - -**End of Session 2** -**Next:** KiCAD installation + testing + Week 2 kickoff - -Let's keep this incredible momentum going! 🎉🚀 +# Week 1 - Session 2 Summary + +**Date:** October 25, 2025 (Afternoon) +**Status:** 🚀 **OUTSTANDING PROGRESS** + +--- + +## 🎯 Session Goals + +Continue Week 1 implementation while user installs KiCAD: + +1. Update README with comprehensive Linux guide +2. Create installation scripts +3. Begin IPC API preparation +4. Set up development infrastructure + +--- + +## ✅ Completed Work + +### 1. **README.md Major Update** 📚 + +**File:** `README.md` + +**Changes:** + +- ✅ Updated project status to reflect v2.0 rebuild +- ✅ Added collapsible platform-specific installation sections: + - 🐧 **Linux (Ubuntu/Debian)** - Primary, detailed + - 🪟 **Windows 10/11** - Fully supported + - 🍎 **macOS** - Experimental +- ✅ Updated system requirements (Linux primary platform) +- ✅ Added Quick Start section with test commands +- ✅ Better visual organization with emojis and status indicators + +**Impact:** New users can now install on Linux in < 10 minutes! + +--- + +### 2. **Linux Installation Script** 🛠️ + +**File:** `scripts/install-linux.sh` + +**Features:** + +- ✅ Fully automated Ubuntu/Debian installation +- ✅ Color-coded output (info/success/warning/error) +- ✅ Safety checks (platform detection, command validation) +- ✅ Installs: + - KiCAD 9.0 from PPA + - Node.js 20.x + - Python dependencies + - Builds TypeScript +- ✅ Verification checks after installation +- ✅ Helpful next-steps guidance + +**Usage:** + +```bash +cd kicad-mcp-server +./scripts/install-linux.sh +``` + +**Lines of Code:** ~200 lines of robust shell script + +--- + +### 3. **Pre-Commit Hooks Configuration** 🔧 + +**File:** `.pre-commit-config.yaml` + +**Hooks Added:** + +- ✅ **Python:** + - Black (code formatting) + - isort (import sorting) + - MyPy (type checking) + - Flake8 (linting) + - Bandit (security checks) +- ✅ **TypeScript/JavaScript:** + - Prettier (formatting) +- ✅ **General:** + - Trailing whitespace removal + - End-of-file fixer + - YAML/JSON validation + - Large file detection + - Merge conflict detection + - Private key detection +- ✅ **Markdown:** + - Markdownlint (formatting) + +**Setup:** + +```bash +pip install pre-commit +pre-commit install +``` + +**Impact:** Automatic code quality enforcement on every commit! + +--- + +### 4. **IPC API Migration Plan** 📋 + +**File:** `docs/IPC_API_MIGRATION_PLAN.md` + +**Comprehensive 30-page migration guide:** + +- ✅ Why migrate (SWIG deprecation analysis) +- ✅ IPC API architecture overview +- ✅ 4-phase migration strategy (10 days) +- ✅ API comparison tables (SWIG vs IPC) +- ✅ Testing strategy +- ✅ Rollback plan +- ✅ Success criteria +- ✅ Timeline with day-by-day tasks + +**Key Insights:** + +- SWIG will be removed in KiCAD 10.0 +- IPC is faster for some operations +- Protocol Buffers ensure API stability +- Multi-language support opens future possibilities + +--- + +### 5. **IPC API Abstraction Layer** 🏗️ + +**New Module:** `python/kicad_api/` + +**Files Created (5):** + +1. **`__init__.py`** (20 lines) + - Package exports + - Version info + - Usage examples + +2. **`base.py`** (180 lines) + - `KiCADBackend` abstract base class + - `BoardAPI` abstract interface + - Custom exceptions (`BackendError`, `ConnectionError`, etc.) + - Defines contract for all backends + +3. **`factory.py`** (160 lines) + - `create_backend()` - Smart backend selection + - Auto-detection (try IPC, fall back to SWIG) + - Environment variable support (`KICAD_BACKEND`) + - `get_available_backends()` - Diagnostic function + - Comprehensive error handling + +4. **`ipc_backend.py`** (210 lines) + - `IPCBackend` class (kicad-python wrapper) + - `IPCBoardAPI` class + - Connection management + - Skeleton methods (to be implemented in Week 2-3) + - Clear TODO markers for migration + +5. **`swig_backend.py`** (220 lines) + - `SWIGBackend` class (wraps existing code) + - `SWIGBoardAPI` class + - Backward compatibility layer + - Deprecation warnings + - Bridges old commands to new interface + +**Total Lines of Code:** ~800 lines + +**Architecture:** + +```python +from kicad_api import create_backend + +# Auto-detect best backend +backend = create_backend() + +# Or specify explicitly +backend = create_backend('ipc') # Use IPC +backend = create_backend('swig') # Use SWIG (deprecated) + +# Use unified interface +if backend.connect(): + board = backend.get_board() + board.set_size(100, 80) +``` + +**Key Features:** + +- ✅ Abstraction allows painless migration +- ✅ Both backends can coexist during transition +- ✅ Easy testing (compare SWIG vs IPC outputs) +- ✅ Future-proof (add new backends easily) +- ✅ Type hints throughout +- ✅ Comprehensive error handling + +--- + +### 6. **Enhanced package.json** 📦 + +**File:** `package.json` + +**Improvements:** + +- ✅ Version bumped to `2.0.0-alpha.1` +- ✅ Better description +- ✅ Enhanced npm scripts: + ```json + "build:watch": "tsc --watch" + "clean": "rm -rf dist" + "rebuild": "npm run clean && npm run build" + "test": "npm run test:ts && npm run test:py" + "test:py": "pytest tests/ -v" + "test:coverage": "pytest with coverage" + "lint": "npm run lint:ts && npm run lint:py" + "lint:py": "black + mypy + flake8" + "format": "prettier + black" + ``` + +**Impact:** Better developer experience, easier workflows + +--- + +## 📊 Statistics + +### Files Created/Modified (Session 2) + +**New Files (10):** + +``` +docs/IPC_API_MIGRATION_PLAN.md # 500+ lines +docs/WEEK1_SESSION2_SUMMARY.md # This file +scripts/install-linux.sh # 200 lines +.pre-commit-config.yaml # 60 lines +python/kicad_api/__init__.py # 20 lines +python/kicad_api/base.py # 180 lines +python/kicad_api/factory.py # 160 lines +python/kicad_api/ipc_backend.py # 210 lines +python/kicad_api/swig_backend.py # 220 lines +``` + +**Modified Files (2):** + +``` +README.md # Major rewrite +package.json # Enhanced scripts +``` + +**Total New Lines:** ~1,600+ lines of code/documentation + +--- + +### Combined Sessions 1+2 Today + +**Files Created:** 27 +**Lines Written:** ~3,000+ +**Documentation Pages:** 8 +**Tests Created:** 20+ + +--- + +## 🎯 Week 1 Status + +### Progress: **95% Complete** ████████████░ + +| Task | Status | +| --------------------- | -------------------------------- | +| Linux compatibility | ✅ Complete | +| CI/CD pipeline | ✅ Complete | +| Cross-platform paths | ✅ Complete | +| Developer docs | ✅ Complete | +| pytest framework | ✅ Complete | +| Config templates | ✅ Complete | +| Installation scripts | ✅ Complete | +| Pre-commit hooks | ✅ Complete | +| IPC migration plan | ✅ Complete | +| IPC abstraction layer | ✅ Complete | +| README updates | ✅ Complete | +| Testing on Ubuntu | ⏳ Pending (needs KiCAD install) | + +**Only Remaining:** Test with actual KiCAD 9.0 installation! + +--- + +## 🚀 Ready for Week 2 + +### IPC API Migration Prep ✅ + +Everything is in place to begin migration: + +- ✅ Abstraction layer architecture defined +- ✅ Base classes and interfaces ready +- ✅ Factory pattern for backend selection +- ✅ SWIG wrapper for backward compatibility +- ✅ IPC skeleton awaiting implementation +- ✅ Comprehensive migration plan documented + +**Week 2 kickoff tasks:** + +1. Install `kicad-python` package +2. Test IPC connection to running KiCAD +3. Begin porting `project.py` module +4. Create side-by-side tests (SWIG vs IPC) + +--- + +## 💡 Key Insights from Session 2 + +### 1. **Installation Automation** + +The bash script reduces setup time from 30+ minutes to < 10 minutes with zero manual intervention. + +### 2. **Pre-Commit Hooks** + +Automatic code quality checks prevent bugs before they're committed. This will save hours in code review. + +### 3. **Abstraction Pattern** + +The backend abstraction is elegant - allows gradual migration without breaking existing functionality. Users won't notice the transition. + +### 4. **Documentation Quality** + +The IPC migration plan is thorough enough that another developer could execute it independently. + +--- + +## 🧪 Testing Readiness + +### When KiCAD is Installed + +You can immediately test: + +**1. Platform Helper:** + +```bash +python3 python/utils/platform_helper.py +``` + +**2. Backend Detection:** + +```bash +python3 python/kicad_api/factory.py +``` + +**3. Installation Script:** + +```bash +./scripts/install-linux.sh +``` + +**4. Pytest Suite:** + +```bash +pytest tests/ -v +``` + +**5. Pre-commit Hooks:** + +```bash +pre-commit run --all-files +``` + +--- + +## 📈 Impact Assessment + +### Developer Onboarding + +- **Before:** 2-3 hours setup, Windows-only, manual steps +- **After:** 10 minutes automated, cross-platform, one script + +### Code Quality + +- **Before:** No automated checks, inconsistent style +- **After:** Pre-commit hooks, 100% type hints, Black formatting + +### Future-Proofing + +- **Before:** Deprecated SWIG API, no migration path +- **After:** IPC API ready, abstraction layer in place + +### Documentation + +- **Before:** README only, Windows-focused +- **After:** 8 comprehensive docs, Linux-primary, migration guides + +--- + +## 🎯 Next Actions + +### Immediate (Tonight/Tomorrow) + +1. Install KiCAD 9.0 on your system +2. Run `./scripts/install-linux.sh` +3. Test backend detection +4. Verify pytest suite passes + +### Week 2 Start (Monday) + +1. Install `kicad-python` package +2. Test IPC connection +3. Begin project.py migration +4. Create first IPC API tests + +--- + +## 🏆 Session 2 Achievements + +### Infrastructure + +- ✅ Automated Linux installation +- ✅ Pre-commit hooks for code quality +- ✅ Enhanced npm scripts +- ✅ IPC API abstraction layer (800+ lines) + +### Documentation + +- ✅ Updated README (Linux-primary) +- ✅ 30-page IPC migration plan +- ✅ Session summaries + +### Architecture + +- ✅ Backend abstraction pattern +- ✅ Factory with auto-detection +- ✅ SWIG backward compatibility +- ✅ IPC skeleton ready for implementation + +--- + +## 🎉 Overall Day Summary + +**Sessions 1+2 Combined:** + +- ⏱️ **Time:** ~4-5 hours total +- 📝 **Files:** 27 created +- 💻 **Code:** ~3,000+ lines +- 📚 **Docs:** 8 comprehensive pages +- 🧪 **Tests:** 20+ unit tests +- ✅ **Week 1:** 95% complete + +**Status:** 🟢 **AHEAD OF SCHEDULE** + +--- + +## 🚀 Momentum Check + +**Energy Level:** 🔋🔋🔋🔋🔋 (Maximum) +**Code Quality:** ⭐⭐⭐⭐⭐ (Excellent) +**Documentation:** 📖📖📖📖📖 (Comprehensive) +**Architecture:** 🏗️🏗️🏗️🏗️🏗️ (Solid) + +**Ready for Week 2 IPC Migration:** ✅ YES! + +--- + +**End of Session 2** +**Next:** KiCAD installation + testing + Week 2 kickoff + +Let's keep this incredible momentum going! 🎉🚀 diff --git a/docs/mcp-router-guide.md b/docs/mcp-router-guide.md index bb1ae93..54921c3 100644 --- a/docs/mcp-router-guide.md +++ b/docs/mcp-router-guide.md @@ -108,25 +108,25 @@ export const toolCategories: ToolCategory[] = [ properties: { output_dir: { type: "string", - description: "Output directory path" + description: "Output directory path", }, layers: { type: "array", items: { type: "string" }, - description: "Layers to export (default: all copper + silkscreen + mask)" + description: "Layers to export (default: all copper + silkscreen + mask)", }, format: { type: "string", enum: ["rs274x", "x2"], - description: "Gerber format version" - } + description: "Gerber format version", + }, }, - required: ["output_dir"] + required: ["output_dir"], }, handler: async (params) => { // Your implementation return { success: true, files: ["..."] }; - } + }, }, { name: "export_drill", @@ -135,24 +135,31 @@ export const toolCategories: ToolCategory[] = [ type: "object", properties: { 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", description: "Export bill of materials as CSV or XML", - inputSchema: { /* ... */ }, - handler: async (params) => { /* ... */ } + inputSchema: { + /* ... */ + }, + handler: async (params) => { + /* ... */ + }, }, // ... more export tools - ] + ], }, { name: "drc", - description: "Design rule checking: clearance validation, electrical rules, manufacturing constraints", + description: + "Design rule checking: clearance validation, electrical rules, manufacturing constraints", tools: [ { name: "run_drc", @@ -162,17 +169,21 @@ export const toolCategories: ToolCategory[] = [ properties: { report_all: { 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", description: "Get current DRC violations without re-running check", inputSchema: { type: "object", properties: {} }, - handler: async (params) => { /* ... */ } + handler: async (params) => { + /* ... */ + }, }, { name: "set_design_rules", @@ -183,12 +194,14 @@ export const toolCategories: ToolCategory[] = [ min_clearance: { type: "number", description: "Minimum clearance 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_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", @@ -208,22 +221,26 @@ export const toolCategories: ToolCategory[] = [ type: "object", properties: { x: { type: "number" }, - y: { type: "number" } - } + y: { type: "number" }, + }, }, - description: "Polygon vertices in mm" + description: "Polygon vertices in mm", }, - priority: { type: "number", description: "Fill priority (higher fills first)" } + priority: { type: "number", description: "Fill priority (higher fills first)" }, }, - required: ["net_name", "layer", "points"] + required: ["net_name", "layer", "points"], + }, + handler: async (params) => { + /* ... */ }, - handler: async (params) => { /* ... */ } }, { name: "fill_zones", description: "Recalculate and fill all copper zones", inputSchema: { type: "object", properties: {} }, - handler: async (params) => { /* ... */ } + handler: async (params) => { + /* ... */ + }, }, { name: "remove_zone", @@ -231,13 +248,15 @@ export const toolCategories: ToolCategory[] = [ inputSchema: { type: "object", 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... ]; @@ -293,7 +312,7 @@ export function searchTools(query: string): Array<{ matches.push({ category: category.name, tool: tool.name, - description: tool.description + description: tool.description, }); } } @@ -313,12 +332,7 @@ These are the tools that enable discovery and execution. ```typescript // src/tools/router.ts -import { - getAllCategories, - getCategory, - getTool, - searchTools -} from "./registry.js"; +import { getAllCategories, getCategory, getTool, searchTools } from "./registry.js"; export const routerTools = { list_tool_categories: { @@ -329,20 +343,20 @@ export const routerTools = { inputSchema: { type: "object" as const, properties: {}, - required: [] + required: [], }, handler: async () => { const categories = getAllCategories(); return { total_categories: categories.length, total_tools: categories.reduce((sum, c) => sum + c.tools.length, 0), - categories: categories.map(c => ({ + categories: categories.map((c) => ({ name: c.name, description: c.description, - tool_count: c.tools.length - })) + tool_count: c.tools.length, + })), }; - } + }, }, get_category_tools: { @@ -356,29 +370,29 @@ export const routerTools = { properties: { category: { 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 }) => { const category = getCategory(params.category); if (!category) { return { error: `Unknown category: ${params.category}`, - available_categories: getAllCategories().map(c => c.name) + available_categories: getAllCategories().map((c) => c.name), }; } return { category: category.name, description: category.description, - tools: category.tools.map(t => ({ + tools: category.tools.map((t) => ({ name: t.name, description: t.description, - parameters: t.inputSchema - })) + parameters: t.inputSchema, + })), }; - } + }, }, execute_tool: { @@ -391,21 +405,21 @@ export const routerTools = { properties: { tool_name: { type: "string", - description: "Tool name (from get_category_tools)" + description: "Tool name (from get_category_tools)", }, params: { 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 }) => { const entry = getTool(input.tool_name); if (!entry) { return { 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 { tool: input.tool_name, category: entry.category, - result + result, }; } catch (err) { return { error: `Tool execution failed: ${(err as Error).message}`, tool: input.tool_name, - category: entry.category + category: entry.category, }; } - } + }, }, search_tools: { @@ -436,20 +450,20 @@ export const routerTools = { properties: { query: { 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 }) => { const matches = searchTools(params.query); return { query: params.query, 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: { type: "string", description: "Optional template to use", - enum: ["blank", "arduino", "raspberry-pi"] - } + enum: ["blank", "arduino", "raspberry-pi"], + }, }, - required: ["name", "path"] + required: ["name", "path"], }, handler: async (params) => { // Implementation return { success: true, project_path: `${params.path}/${params.name}` }; - } + }, }, { name: "open_project", @@ -494,29 +508,35 @@ export const directTools: ToolDefinition[] = [ inputSchema: { type: "object", 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", description: "Save all project files", inputSchema: { type: "object", - properties: {} + properties: {}, + }, + handler: async (params) => { + /* ... */ }, - handler: async (params) => { /* ... */ } }, { name: "get_project_info", description: "Get current project information: path, files, status", inputSchema: { type: "object", - properties: {} + properties: {}, + }, + handler: async (params) => { + /* ... */ }, - handler: async (params) => { /* ... */ } }, // === PRIMARY OPERATIONS (your core workflow) === @@ -530,11 +550,13 @@ export const directTools: ToolDefinition[] = [ reference: { type: "string", description: "Reference designator (e.g., R1, U1)" }, x: { type: "number", description: "X 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", @@ -544,11 +566,13 @@ export const directTools: ToolDefinition[] = [ properties: { reference: { type: "string", description: "Component reference (e.g., R1)" }, 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", @@ -556,10 +580,12 @@ export const directTools: ToolDefinition[] = [ inputSchema: { type: "object", 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) === @@ -571,36 +597,42 @@ export const directTools: ToolDefinition[] = [ properties: { start: { type: "object", - properties: { x: { type: "number" }, y: { type: "number" } } + properties: { x: { type: "number" }, y: { type: "number" } }, }, end: { 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", description: "List all nets/connections", inputSchema: { type: "object", - properties: {} + properties: {}, + }, + handler: async (params) => { + /* ... */ }, - handler: async (params) => { /* ... */ } }, { name: "get_info", description: "Get general information about current state", inputSchema: { 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 { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { - CallToolRequestSchema, - ListToolsRequestSchema, -} from "@modelcontextprotocol/sdk/types.js"; +import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { directTools } from "./tools/direct.js"; import { routerTools } from "./tools/router.js"; @@ -634,14 +663,11 @@ const server = new Server( capabilities: { tools: {}, }, - } + }, ); // Combine all visible tools -const allVisibleTools = [ - ...directTools, - ...Object.values(routerTools) -]; +const allVisibleTools = [...directTools, ...Object.values(routerTools)]; // Build a handler map for quick lookup const toolHandlers = new Map Promise>(); @@ -656,7 +682,7 @@ for (const tool of Object.values(routerTools)) { // List tools handler - returns only direct + router tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { - tools: allVisibleTools.map(tool => ({ + tools: allVisibleTools.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, @@ -676,9 +702,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { type: "text", text: JSON.stringify({ 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, }; @@ -690,8 +716,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { content: [ { type: "text", - text: JSON.stringify(result, null, 2) - } + text: JSON.stringify(result, null, 2), + }, ], }; } catch (error) { @@ -700,9 +726,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { { type: "text", text: JSON.stringify({ - error: `Tool execution failed: ${(error as Error).message}` - }) - } + error: `Tool execution failed: ${(error as Error).message}`, + }), + }, ], isError: true, }; @@ -734,12 +760,12 @@ Include tools that are: **Examples by domain:** -| Domain | Direct Tools | -|--------|-------------| -| **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 | -| **Git** | status, add, commit, push, pull, checkout, branch, log | -| **Database** | connect, query, list_tables, describe_table | +| Domain | Direct Tools | +| ------------ | -------------------------------------------------------------------------------------------------------------------------------- | +| **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 | +| **Git** | status, add, commit, push, pull, checkout, branch, log | +| **Database** | connect, query, list_tables, describe_table | ### Routed Tools (Hidden Behind Router) @@ -753,13 +779,13 @@ Include tools that are: **Examples:** -| Category | Why Route It | -|----------|-------------| -| `export` | Only used at end of workflow | -| `drc/validation` | Used during review phase | -| `advanced_*` | Specialty operations | -| `bulk_*` | Batch operations | -| `config/settings` | One-time setup | +| Category | Why Route It | +| ----------------- | ---------------------------- | +| `export` | Only used at end of workflow | +| `drc/validation` | Used during review phase | +| `advanced_*` | Specialty operations | +| `bulk_*` | Batch operations | +| `config/settings` | One-time setup | --- @@ -832,18 +858,18 @@ For an IDA Pro MCP server with 100+ tools: ```typescript const directTools = [ - "open_database", // Load IDB - "save_database", // Save IDB - "get_function", // Get function by address/name - "list_functions", // List all functions - "decompile", // Decompile function (Hex-Rays) - "add_comment", // Add comment at address - "rename", // Rename address/function - "get_xrefs_to", // Get cross-references to address - "get_xrefs_from", // Get cross-references from address - "get_strings", // List strings - "search_bytes", // Search for byte pattern - "get_segments", // List segments + "open_database", // Load IDB + "save_database", // Save IDB + "get_function", // Get function by address/name + "list_functions", // List all functions + "decompile", // Decompile function (Hex-Rays) + "add_comment", // Add comment at address + "rename", // Rename address/function + "get_xrefs_to", // Get cross-references to address + "get_xrefs_from", // Get cross-references from address + "get_strings", // List strings + "search_bytes", // Search for byte pattern + "get_segments", // List segments ]; ``` @@ -854,52 +880,52 @@ const categories = [ { name: "disassembly", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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 import { describe, it, expect } from "vitest"; -import { - searchTools, - getCategory, - getTool, - getAllCategories -} from "../src/tools/registry.js"; +import { searchTools, getCategory, getTool, getAllCategories } from "../src/tools/registry.js"; import { routerTools } from "../src/tools/router.js"; describe("Tool Registry", () => { it("should find tools by keyword", () => { const results = searchTools("export"); 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", () => { @@ -998,7 +1019,7 @@ describe("Router Tools", () => { it("get_category_tools returns tools for valid category", async () => { const result = await routerTools.get_category_tools.handler({ - category: "export" + category: "export", }); expect(result.tools).toBeDefined(); expect(result.tools.length).toBeGreaterThan(0); @@ -1006,7 +1027,7 @@ describe("Router Tools", () => { it("get_category_tools returns error for invalid category", async () => { const result = await routerTools.get_category_tools.handler({ - category: "nonexistent" + category: "nonexistent", }); expect(result.error).toBeDefined(); }); @@ -1014,7 +1035,7 @@ describe("Router Tools", () => { it("execute_tool runs valid tool", async () => { const result = await routerTools.execute_tool.handler({ tool_name: "export_gerber", - params: { output_dir: "/tmp/test" } + params: { output_dir: "/tmp/test" }, }); expect(result.error).toBeUndefined(); }); @@ -1022,7 +1043,7 @@ describe("Router Tools", () => { it("execute_tool returns error for invalid tool", async () => { const result = await routerTools.execute_tool.handler({ tool_name: "nonexistent_tool", - params: {} + params: {}, }); expect(result.error).toBeDefined(); }); @@ -1141,11 +1162,11 @@ Before shipping your router-based MCP server: ## Summary -| Before | After | -|--------|-------| -| 100 tools visible | 15-18 tools visible | -| ~60K+ tokens consumed | ~10K tokens consumed | -| Tool selection confusion | Clear categories | -| Context starvation | Room for conversation | +| Before | After | +| ------------------------ | --------------------- | +| 100 tools visible | 15-18 tools visible | +| ~60K+ tokens consumed | ~10K tokens consumed | +| Tool selection confusion | Clear categories | +| Context starvation | Room for conversation | The router pattern gives you unlimited tool capacity while keeping Claude focused and efficient. diff --git a/package-lock.json b/package-lock.json index e806c4c..b3d4947 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@types/glob": "^8.1.0", "@types/node": "^20.19.0", "nodemon": "^3.0.1", + "prettier": "^3.8.1", "typescript": "^5.9.3" } }, @@ -1150,6 +1151,22 @@ "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": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", diff --git a/package.json b/package.json index 64e5e62..1d4c9a5 100644 --- a/package.json +++ b/package.json @@ -1,49 +1,50 @@ -{ - "name": "kicad-mcp", - "version": "2.1.0-alpha", - "description": "AI-assisted PCB design with KiCAD via Model Context Protocol", - "type": "module", - "main": "dist/index.js", - "scripts": { - "build": "tsc", - "build:watch": "tsc --watch", - "start": "node dist/index.js", - "dev": "npm run build:watch & nodemon dist/index.js", - "clean": "rm -rf dist", - "rebuild": "npm run clean && npm run build", - "test": "npm run test:ts && npm run test:py", - "test:ts": "echo 'TypeScript tests not yet configured'", - "test:py": "pytest tests/ -v", - "test:coverage": "pytest tests/ --cov=python --cov-report=html --cov-report=term", - "lint": "npm run lint:ts && npm run lint:py", - "lint:ts": "eslint src/ || echo 'ESLint not configured'", - "lint:py": "cd python && black . && mypy . && flake8 .", - "format": "prettier --write 'src/**/*.ts' && black python/", - "prepare": "npm run build", - "pretest": "npm run build" - }, - "keywords": [ - "kicad", - "mcp", - "model-context-protocol", - "pcb-design", - "ai", - "claude" - ], - "author": "", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.21.0", - "dotenv": "^17.0.0", - "express": "^5.1.0", - "zod": "^3.25.0" - }, - "devDependencies": { - "@cfworker/json-schema": "^4.1.1", - "@types/express": "^5.0.5", - "@types/glob": "^8.1.0", - "@types/node": "^20.19.0", - "nodemon": "^3.0.1", - "typescript": "^5.9.3" - } -} +{ + "name": "kicad-mcp", + "version": "2.1.0-alpha", + "description": "AI-assisted PCB design with KiCAD via Model Context Protocol", + "type": "module", + "main": "dist/index.js", + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "start": "node dist/index.js", + "dev": "npm run build:watch & nodemon dist/index.js", + "clean": "rm -rf dist", + "rebuild": "npm run clean && npm run build", + "test": "npm run test:ts && npm run test:py", + "test:ts": "echo 'TypeScript tests not yet configured'", + "test:py": "pytest tests/ -v", + "test:coverage": "pytest tests/ --cov=python --cov-report=html --cov-report=term", + "lint": "npm run lint:ts && npm run lint:py", + "lint:ts": "eslint src/ || echo 'ESLint not configured'", + "lint:py": "cd python && black . && mypy . && flake8 .", + "format": "prettier --write 'src/**/*.ts' && black python/", + "prepare": "npm run build", + "pretest": "npm run build" + }, + "keywords": [ + "kicad", + "mcp", + "model-context-protocol", + "pcb-design", + "ai", + "claude" + ], + "author": "", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.21.0", + "dotenv": "^17.0.0", + "express": "^5.1.0", + "zod": "^3.25.0" + }, + "devDependencies": { + "@cfworker/json-schema": "^4.1.1", + "@types/express": "^5.0.5", + "@types/glob": "^8.1.0", + "@types/node": "^20.19.0", + "nodemon": "^3.0.1", + "prettier": "^3.8.1", + "typescript": "^5.9.3" + } +} diff --git a/src/config.ts b/src/config.ts index 38e6fb6..ac4aeb0 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,31 +2,31 @@ * Configuration handling for KiCAD MCP server */ -import { readFile } from 'fs/promises'; -import { existsSync } from 'fs'; -import { join, dirname } from 'path'; -import { fileURLToPath } from 'url'; -import { z } from 'zod'; -import { logger } from './logger.js'; +import { readFile } from "fs/promises"; +import { existsSync } from "fs"; +import { join, dirname } from "path"; +import { fileURLToPath } from "url"; +import { z } from "zod"; +import { logger } from "./logger.js"; // Get the current directory const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // 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 */ const ConfigSchema = z.object({ - name: z.string().default('kicad-mcp-server'), - version: z.string().default('1.0.0'), - description: z.string().default('MCP server for KiCAD PCB design operations'), + name: z.string().default("kicad-mcp-server"), + version: z.string().default("1.0.0"), + description: z.string().default("MCP server for KiCAD PCB design operations"), pythonPath: z.string().optional(), kicadPath: z.string().optional(), - logLevel: z.enum(['error', 'warn', 'info', 'debug']).default('info'), - logDir: z.string().optional() + logLevel: z.enum(["error", "warn", "info", "debug"]).default("info"), + logDir: z.string().optional(), }); /** @@ -52,7 +52,7 @@ export async function loadConfig(configPath?: string): Promise { } // Read and parse configuration - const configData = await readFile(filePath, 'utf-8'); + const configData = await readFile(filePath, "utf-8"); const config = JSON.parse(configData); // Validate configuration diff --git a/src/index.ts b/src/index.ts index 05bbe7f..1ddec83 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,11 +3,11 @@ * Main entry point */ -import { join, dirname } from 'path'; -import { fileURLToPath } from 'url'; -import { KiCADMcpServer } from './server.js'; -import { loadConfig } from './config.js'; -import { logger } from './logger.js'; +import { join, dirname } from "path"; +import { fileURLToPath } from "url"; +import { KiCADMcpServer } from "./server.js"; +import { loadConfig } from "./config.js"; +import { logger } from "./logger.js"; // Get the current directory const __filename = fileURLToPath(import.meta.url); @@ -26,13 +26,10 @@ async function main() { const config = await loadConfig(options.configPath); // 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 - const server = new KiCADMcpServer( - kicadScriptPath, - config.logLevel - ); + const server = new KiCADMcpServer(kicadScriptPath, config.logLevel); // Start the server await server.start(); @@ -40,8 +37,7 @@ async function main() { // Setup graceful shutdown setupGracefulShutdown(server); - logger.info('KiCAD MCP server started with STDIO transport'); - + logger.info("KiCAD MCP server started with STDIO transport"); } catch (error) { logger.error(`Failed to start KiCAD MCP server: ${error}`); process.exit(1); @@ -55,7 +51,7 @@ function parseCommandLineArgs(args: string[]) { let configPath = undefined; 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]; i++; } @@ -69,24 +65,24 @@ function parseCommandLineArgs(args: string[]) { */ function setupGracefulShutdown(server: KiCADMcpServer) { // Handle termination signals - process.on('SIGINT', async () => { - logger.info('Received SIGINT signal. Shutting down...'); + process.on("SIGINT", async () => { + logger.info("Received SIGINT signal. Shutting down..."); await shutdownServer(server); }); - process.on('SIGTERM', async () => { - logger.info('Received SIGTERM signal. Shutting down...'); + process.on("SIGTERM", async () => { + logger.info("Received SIGTERM signal. Shutting down..."); await shutdownServer(server); }); // Handle uncaught exceptions - process.on('uncaughtException', async (error) => { + process.on("uncaughtException", async (error) => { logger.error(`Uncaught exception: ${error}`); await shutdownServer(server); }); // Handle unhandled promise rejections - process.on('unhandledRejection', async (reason) => { + process.on("unhandledRejection", async (reason) => { logger.error(`Unhandled promise rejection: ${reason}`); await shutdownServer(server); }); @@ -97,9 +93,9 @@ function setupGracefulShutdown(server: KiCADMcpServer) { */ async function shutdownServer(server: KiCADMcpServer) { try { - logger.info('Shutting down KiCAD MCP server...'); + logger.info("Shutting down KiCAD MCP server..."); await server.stop(); - logger.info('Server shutdown complete. Exiting...'); + logger.info("Server shutdown complete. Exiting..."); process.exit(0); } catch (error) { logger.error(`Error during shutdown: ${error}`); diff --git a/src/kicad-server.ts b/src/kicad-server.ts index dd633c4..b8f365b 100644 --- a/src/kicad-server.ts +++ b/src/kicad-server.ts @@ -1,500 +1,504 @@ -import { Server } from '@modelcontextprotocol/sdk/server/index.js'; -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; -import { spawn, ChildProcess } from 'child_process'; -import { existsSync } from 'fs'; -import path from 'path'; - -// Import all tool definitions for reference -// import { registerBoardTools } from './tools/board.js'; -// import { registerComponentTools } from './tools/component.js'; -// import { registerRoutingTools } from './tools/routing.js'; -// import { registerDesignRuleTools } from './tools/design-rules.js'; -// import { registerExportTools } from './tools/export.js'; -// import { registerProjectTools } from './tools/project.js'; -// import { registerSchematicTools } from './tools/schematic.js'; - -class KiCADServer { - private server: Server; - private pythonProcess: ChildProcess | null = null; - private kicadScriptPath: string; - private requestQueue: Array<{ request: any, resolve: Function, reject: Function }> = []; - private processingRequest = false; - - constructor() { - // Set absolute path to the Python KiCAD interface script - // Using a hardcoded path to avoid cwd() issues when running from Cline - this.kicadScriptPath = 'c:/repo/KiCAD-MCP/python/kicad_interface.py'; - - // Check if script exists - if (!existsSync(this.kicadScriptPath)) { - throw new Error(`KiCAD interface script not found: ${this.kicadScriptPath}`); - } - - // Initialize the server - this.server = new Server( - { - name: 'kicad-mcp-server', - version: '1.0.0' - }, - { - capabilities: { - tools: { - // Empty object here, tools will be registered dynamically - } - } - } - ); - - // Initialize handler with direct pass-through to Python KiCAD interface - // We don't register TypeScript tools since we'll handle everything in Python - - // Register tool list handler - this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools: [ - // Project tools - { - name: 'create_project', - description: 'Create a new KiCAD project', - inputSchema: { - type: 'object', - properties: { - projectName: { type: 'string', description: 'Name of the new project' }, - path: { type: 'string', description: 'Path where to create the project' }, - template: { type: 'string', description: 'Optional template to use' } - }, - required: ['projectName'] - } - }, - { - name: 'open_project', - description: 'Open an existing KiCAD project', - inputSchema: { - type: 'object', - properties: { - filename: { type: 'string', description: 'Path to the project file' } - }, - required: ['filename'] - } - }, - { - name: 'save_project', - description: 'Save the current KiCAD project', - inputSchema: { - type: 'object', - properties: { - filename: { type: 'string', description: 'Optional path to save to' } - } - } - }, - { - name: 'get_project_info', - description: 'Get information about the current project', - inputSchema: { - type: 'object', - properties: {} - } - }, - - // Board tools - { - name: 'set_board_size', - description: 'Set the size of the PCB board', - inputSchema: { - type: 'object', - properties: { - width: { type: 'number', description: 'Board width' }, - height: { type: 'number', description: 'Board height' }, - unit: { type: 'string', description: 'Unit of measurement (mm or inch)' } - }, - required: ['width', 'height'] - } - }, - { - name: 'add_board_outline', - description: 'Add a board outline to the PCB', - inputSchema: { - type: 'object', - properties: { - shape: { type: 'string', description: 'Shape of outline (rectangle, circle, polygon, rounded_rectangle)' }, - width: { type: 'number', description: 'Width for rectangle shapes' }, - height: { type: 'number', description: 'Height for rectangle shapes' }, - radius: { type: 'number', description: 'Radius for circle shapes' }, - cornerRadius: { type: 'number', description: 'Corner radius for rounded rectangles' }, - 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 - { - name: 'place_component', - description: 'Place a component on the PCB', - inputSchema: { - type: 'object', - properties: { - componentId: { type: 'string', description: 'Component ID/footprint to place' }, - position: { type: 'object', description: 'Position coordinates' }, - reference: { type: 'string', description: 'Component reference designator' }, - value: { type: 'string', description: 'Component value' }, - rotation: { type: 'number', description: 'Rotation angle in degrees' }, - layer: { type: 'string', description: 'Layer to place component on' } - }, - required: ['componentId', 'position'] - } - }, - - // Routing tools - { - name: 'add_net', - description: 'Add a new net to the PCB', - inputSchema: { - type: 'object', - properties: { - name: { type: 'string', description: 'Net name' }, - class: { type: 'string', description: 'Net class' } - }, - required: ['name'] - } - }, - { - name: 'route_trace', - description: 'Route a trace between two points or pads', - inputSchema: { - type: 'object', - properties: { - start: { type: 'object', description: 'Start point or pad' }, - end: { type: 'object', description: 'End point or pad' }, - layer: { type: 'string', description: 'Layer to route on' }, - width: { type: 'number', description: 'Track width' }, - net: { type: 'string', description: 'Net name' } - }, - required: ['start', 'end'] - } - }, - - // Schematic tools - { - name: 'create_schematic', - description: 'Create a new KiCAD schematic', - inputSchema: { - type: 'object', - properties: { - projectName: { type: 'string', description: 'Name of the schematic project' }, - path: { type: 'string', description: 'Path where to create the schematic file' }, - metadata: { type: 'object', description: 'Optional metadata for the schematic' } - }, - required: ['projectName'] - } - }, - { - name: 'load_schematic', - description: 'Load an existing KiCAD schematic', - inputSchema: { - type: 'object', - properties: { - filename: { type: 'string', description: 'Path to the schematic file to load' } - }, - required: ['filename'] - } - }, - { - name: 'add_schematic_component', - description: 'Add a component to a KiCAD schematic', - inputSchema: { - type: 'object', - properties: { - schematicPath: { type: 'string', description: 'Path to the schematic file' }, - component: { - type: 'object', - description: 'Component definition', - properties: { - type: { type: 'string', description: 'Component type (e.g., R, C, LED)' }, - reference: { type: 'string', description: 'Reference designator (e.g., R1, C2)' }, - value: { type: 'string', description: 'Component value (e.g., 10k, 0.1uF)' }, - library: { type: 'string', description: 'Symbol library name' }, - x: { type: 'number', description: 'X position in schematic' }, - y: { type: 'number', description: 'Y position in schematic' }, - rotation: { type: 'number', description: 'Rotation angle in degrees' }, - properties: { type: 'object', description: 'Additional properties' } - }, - required: ['type', 'reference'] - } - }, - required: ['schematicPath', 'component'] - } - }, - { - name: 'add_schematic_wire', - description: 'Add a wire connection to a KiCAD schematic', - inputSchema: { - type: 'object', - properties: { - schematicPath: { type: 'string', description: 'Path to the schematic file' }, - startPoint: { - type: 'array', - description: 'Starting point coordinates [x, y]', - items: { type: 'number' }, - minItems: 2, - maxItems: 2 - }, - endPoint: { - type: 'array', - description: 'Ending point coordinates [x, y]', - items: { type: 'number' }, - minItems: 2, - maxItems: 2 - } - }, - required: ['schematicPath', 'startPoint', 'endPoint'] - } - }, - { - name: 'list_schematic_libraries', - description: 'List available KiCAD symbol libraries', - inputSchema: { - type: 'object', - properties: { - searchPaths: { - type: 'array', - description: 'Optional search paths for libraries', - items: { type: 'string' } - } - } - } - }, - { - name: 'export_schematic_pdf', - description: 'Export a KiCAD schematic to PDF', - inputSchema: { - type: 'object', - properties: { - schematicPath: { type: 'string', description: 'Path to the schematic file' }, - outputPath: { type: 'string', description: 'Path for the output PDF file' } - }, - required: ['schematicPath', 'outputPath'] - } - } - ] - })); - - // Register tool call handler - this.server.setRequestHandler(CallToolRequestSchema, async (request: any) => { - const toolName = request.params.name; - const args = request.params.arguments || {}; - - // Pass all commands directly to KiCAD Python interface - try { - return await this.callKicadScript(toolName, args); - } catch (error) { - console.error(`Error executing tool ${toolName}:`, error); - throw new Error(`Unknown tool: ${toolName}`); - } - }); - } - - async start() { - try { - console.error('Starting KiCAD MCP server...'); - - // Start the Python process for KiCAD scripting - console.error(`Starting Python process with script: ${this.kicadScriptPath}`); - const pythonExe = 'C:\\Program Files\\KiCad\\9.0\\bin\\python.exe'; - - console.error(`Using Python executable: ${pythonExe}`); - this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], { - stdio: ['pipe', 'pipe', 'pipe'], - env: { - ...process.env, - PYTHONPATH: 'C:/Program Files/KiCad/9.0/lib/python3/dist-packages' - } - }); - - // Listen for process exit - this.pythonProcess.on('exit', (code, signal) => { - console.error(`Python process exited with code ${code} and signal ${signal}`); - this.pythonProcess = null; - }); - - // Listen for process errors - this.pythonProcess.on('error', (err) => { - console.error(`Python process error: ${err.message}`); - }); - - // Set up error logging for stderr - if (this.pythonProcess.stderr) { - this.pythonProcess.stderr.on('data', (data: Buffer) => { - console.error(`Python stderr: ${data.toString()}`); - }); - } - - // Connect to transport - const transport = new StdioServerTransport(); - await this.server.connect(transport); - console.error('KiCAD MCP server running'); - - // Keep the process running - process.on('SIGINT', () => { - if (this.pythonProcess) { - this.pythonProcess.kill(); - } - this.server.close().catch(console.error); - process.exit(0); - }); - - } catch (error: unknown) { - if (error instanceof Error) { - console.error('Failed to start MCP server:', error.message); - } else { - console.error('Failed to start MCP server: Unknown error'); - } - process.exit(1); - } - } - - private async callKicadScript(command: string, params: any): Promise { - return new Promise((resolve, reject) => { - // Check if Python process is running - if (!this.pythonProcess) { - console.error('Python process is not running'); - reject(new Error("Python process for KiCAD scripting is not running")); - return; - } - - // Add request to queue - this.requestQueue.push({ - request: { command, params }, - resolve, - reject - }); - - // Process the queue if not already processing - if (!this.processingRequest) { - this.processNextRequest(); - } - }); - } - - private processNextRequest(): void { - // If no more requests or already processing, return - if (this.requestQueue.length === 0 || this.processingRequest) { - return; - } - - // Set processing flag - this.processingRequest = true; - - // Get the next request - const { request, resolve, reject } = this.requestQueue.shift()!; - - try { - console.error(`Processing KiCAD command: ${request.command}`); - - // Format the command and parameters as JSON - const requestStr = JSON.stringify(request); - - // Set up response handling - let responseData = ''; - - // Clear any previous listeners - if (this.pythonProcess?.stdout) { - this.pythonProcess.stdout.removeAllListeners('data'); - } - - // Set up new listeners - if (this.pythonProcess?.stdout) { - this.pythonProcess.stdout.on('data', (data: Buffer) => { - const chunk = data.toString(); - console.error(`Received data chunk: ${chunk.length} bytes`); - responseData += chunk; - - // Check if we have a complete response - try { - // Try to parse the response as JSON - const result = JSON.parse(responseData); - - // If we get here, we have a valid JSON response - console.error(`Completed KiCAD command: ${request.command} with result: ${JSON.stringify(result)}`); - - // Reset processing flag - this.processingRequest = false; - - // Process next request if any - setTimeout(() => this.processNextRequest(), 0); - - // Clear listeners - if (this.pythonProcess?.stdout) { - this.pythonProcess.stdout.removeAllListeners('data'); - } - - // Resolve with the expected MCP tool response format - if (result.success) { - resolve({ - content: [ - { - type: 'text', - text: JSON.stringify(result, null, 2) - } - ] - }); - } else { - resolve({ - content: [ - { - type: 'text', - text: result.errorDetails || result.message || 'Unknown error' - } - ], - isError: true - }); - } - } catch (e) { - // Not a complete JSON yet, keep collecting data - } - }); - } - - // Set a timeout - const timeout = setTimeout(() => { - console.error(`Command timeout: ${request.command}`); - - // Clear listeners - if (this.pythonProcess?.stdout) { - this.pythonProcess.stdout.removeAllListeners('data'); - } - - // Reset processing flag - this.processingRequest = false; - - // Process next request - setTimeout(() => this.processNextRequest(), 0); - - // Reject the promise - reject(new Error(`Command timeout: ${request.command}`)); - }, 30000); // 30 seconds timeout - - // Write the request to the Python process - console.error(`Sending request: ${requestStr}`); - this.pythonProcess?.stdin?.write(requestStr + '\n'); - } catch (error) { - console.error(`Error processing request: ${error}`); - - // Reset processing flag - this.processingRequest = false; - - // Process next request - setTimeout(() => this.processNextRequest(), 0); - - // Reject the promise - reject(error); - } - } -} - -// Start the server -const server = new KiCADServer(); -server.start().catch(console.error); +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; +import { spawn, ChildProcess } from "child_process"; +import { existsSync } from "fs"; +import path from "path"; + +// Import all tool definitions for reference +// import { registerBoardTools } from './tools/board.js'; +// import { registerComponentTools } from './tools/component.js'; +// import { registerRoutingTools } from './tools/routing.js'; +// import { registerDesignRuleTools } from './tools/design-rules.js'; +// import { registerExportTools } from './tools/export.js'; +// import { registerProjectTools } from './tools/project.js'; +// import { registerSchematicTools } from './tools/schematic.js'; + +class KiCADServer { + private server: Server; + private pythonProcess: ChildProcess | null = null; + private kicadScriptPath: string; + private requestQueue: Array<{ request: any; resolve: Function; reject: Function }> = []; + private processingRequest = false; + + constructor() { + // Set absolute path to the Python KiCAD interface script + // Using a hardcoded path to avoid cwd() issues when running from Cline + this.kicadScriptPath = "c:/repo/KiCAD-MCP/python/kicad_interface.py"; + + // Check if script exists + if (!existsSync(this.kicadScriptPath)) { + throw new Error(`KiCAD interface script not found: ${this.kicadScriptPath}`); + } + + // Initialize the server + this.server = new Server( + { + name: "kicad-mcp-server", + version: "1.0.0", + }, + { + capabilities: { + tools: { + // Empty object here, tools will be registered dynamically + }, + }, + }, + ); + + // Initialize handler with direct pass-through to Python KiCAD interface + // We don't register TypeScript tools since we'll handle everything in Python + + // Register tool list handler + this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: [ + // Project tools + { + name: "create_project", + description: "Create a new KiCAD project", + inputSchema: { + type: "object", + properties: { + projectName: { type: "string", description: "Name of the new project" }, + path: { type: "string", description: "Path where to create the project" }, + template: { type: "string", description: "Optional template to use" }, + }, + required: ["projectName"], + }, + }, + { + name: "open_project", + description: "Open an existing KiCAD project", + inputSchema: { + type: "object", + properties: { + filename: { type: "string", description: "Path to the project file" }, + }, + required: ["filename"], + }, + }, + { + name: "save_project", + description: "Save the current KiCAD project", + inputSchema: { + type: "object", + properties: { + filename: { type: "string", description: "Optional path to save to" }, + }, + }, + }, + { + name: "get_project_info", + description: "Get information about the current project", + inputSchema: { + type: "object", + properties: {}, + }, + }, + + // Board tools + { + name: "set_board_size", + description: "Set the size of the PCB board", + inputSchema: { + type: "object", + properties: { + width: { type: "number", description: "Board width" }, + height: { type: "number", description: "Board height" }, + unit: { type: "string", description: "Unit of measurement (mm or inch)" }, + }, + required: ["width", "height"], + }, + }, + { + name: "add_board_outline", + description: "Add a board outline to the PCB", + inputSchema: { + type: "object", + properties: { + shape: { + type: "string", + description: "Shape of outline (rectangle, circle, polygon, rounded_rectangle)", + }, + width: { type: "number", description: "Width for rectangle shapes" }, + height: { type: "number", description: "Height for rectangle shapes" }, + radius: { type: "number", description: "Radius for circle shapes" }, + cornerRadius: { type: "number", description: "Corner radius for rounded rectangles" }, + 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 + { + name: "place_component", + description: "Place a component on the PCB", + inputSchema: { + type: "object", + properties: { + componentId: { type: "string", description: "Component ID/footprint to place" }, + position: { type: "object", description: "Position coordinates" }, + reference: { type: "string", description: "Component reference designator" }, + value: { type: "string", description: "Component value" }, + rotation: { type: "number", description: "Rotation angle in degrees" }, + layer: { type: "string", description: "Layer to place component on" }, + }, + required: ["componentId", "position"], + }, + }, + + // Routing tools + { + name: "add_net", + description: "Add a new net to the PCB", + inputSchema: { + type: "object", + properties: { + name: { type: "string", description: "Net name" }, + class: { type: "string", description: "Net class" }, + }, + required: ["name"], + }, + }, + { + name: "route_trace", + description: "Route a trace between two points or pads", + inputSchema: { + type: "object", + properties: { + start: { type: "object", description: "Start point or pad" }, + end: { type: "object", description: "End point or pad" }, + layer: { type: "string", description: "Layer to route on" }, + width: { type: "number", description: "Track width" }, + net: { type: "string", description: "Net name" }, + }, + required: ["start", "end"], + }, + }, + + // Schematic tools + { + name: "create_schematic", + description: "Create a new KiCAD schematic", + inputSchema: { + type: "object", + properties: { + projectName: { type: "string", description: "Name of the schematic project" }, + path: { type: "string", description: "Path where to create the schematic file" }, + metadata: { type: "object", description: "Optional metadata for the schematic" }, + }, + required: ["projectName"], + }, + }, + { + name: "load_schematic", + description: "Load an existing KiCAD schematic", + inputSchema: { + type: "object", + properties: { + filename: { type: "string", description: "Path to the schematic file to load" }, + }, + required: ["filename"], + }, + }, + { + name: "add_schematic_component", + description: "Add a component to a KiCAD schematic", + inputSchema: { + type: "object", + properties: { + schematicPath: { type: "string", description: "Path to the schematic file" }, + component: { + type: "object", + description: "Component definition", + properties: { + type: { type: "string", description: "Component type (e.g., R, C, LED)" }, + reference: { type: "string", description: "Reference designator (e.g., R1, C2)" }, + value: { type: "string", description: "Component value (e.g., 10k, 0.1uF)" }, + library: { type: "string", description: "Symbol library name" }, + x: { type: "number", description: "X position in schematic" }, + y: { type: "number", description: "Y position in schematic" }, + rotation: { type: "number", description: "Rotation angle in degrees" }, + properties: { type: "object", description: "Additional properties" }, + }, + required: ["type", "reference"], + }, + }, + required: ["schematicPath", "component"], + }, + }, + { + name: "add_schematic_wire", + description: "Add a wire connection to a KiCAD schematic", + inputSchema: { + type: "object", + properties: { + schematicPath: { type: "string", description: "Path to the schematic file" }, + startPoint: { + type: "array", + description: "Starting point coordinates [x, y]", + items: { type: "number" }, + minItems: 2, + maxItems: 2, + }, + endPoint: { + type: "array", + description: "Ending point coordinates [x, y]", + items: { type: "number" }, + minItems: 2, + maxItems: 2, + }, + }, + required: ["schematicPath", "startPoint", "endPoint"], + }, + }, + { + name: "list_schematic_libraries", + description: "List available KiCAD symbol libraries", + inputSchema: { + type: "object", + properties: { + searchPaths: { + type: "array", + description: "Optional search paths for libraries", + items: { type: "string" }, + }, + }, + }, + }, + { + name: "export_schematic_pdf", + description: "Export a KiCAD schematic to PDF", + inputSchema: { + type: "object", + properties: { + schematicPath: { type: "string", description: "Path to the schematic file" }, + outputPath: { type: "string", description: "Path for the output PDF file" }, + }, + required: ["schematicPath", "outputPath"], + }, + }, + ], + })); + + // Register tool call handler + this.server.setRequestHandler(CallToolRequestSchema, async (request: any) => { + const toolName = request.params.name; + const args = request.params.arguments || {}; + + // Pass all commands directly to KiCAD Python interface + try { + return await this.callKicadScript(toolName, args); + } catch (error) { + console.error(`Error executing tool ${toolName}:`, error); + throw new Error(`Unknown tool: ${toolName}`); + } + }); + } + + async start() { + try { + console.error("Starting KiCAD MCP server..."); + + // Start the Python process for KiCAD scripting + console.error(`Starting Python process with script: ${this.kicadScriptPath}`); + const pythonExe = "C:\\Program Files\\KiCad\\9.0\\bin\\python.exe"; + + console.error(`Using Python executable: ${pythonExe}`); + this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], { + stdio: ["pipe", "pipe", "pipe"], + env: { + ...process.env, + PYTHONPATH: "C:/Program Files/KiCad/9.0/lib/python3/dist-packages", + }, + }); + + // Listen for process exit + this.pythonProcess.on("exit", (code, signal) => { + console.error(`Python process exited with code ${code} and signal ${signal}`); + this.pythonProcess = null; + }); + + // Listen for process errors + this.pythonProcess.on("error", (err) => { + console.error(`Python process error: ${err.message}`); + }); + + // Set up error logging for stderr + if (this.pythonProcess.stderr) { + this.pythonProcess.stderr.on("data", (data: Buffer) => { + console.error(`Python stderr: ${data.toString()}`); + }); + } + + // Connect to transport + const transport = new StdioServerTransport(); + await this.server.connect(transport); + console.error("KiCAD MCP server running"); + + // Keep the process running + process.on("SIGINT", () => { + if (this.pythonProcess) { + this.pythonProcess.kill(); + } + this.server.close().catch(console.error); + process.exit(0); + }); + } catch (error: unknown) { + if (error instanceof Error) { + console.error("Failed to start MCP server:", error.message); + } else { + console.error("Failed to start MCP server: Unknown error"); + } + process.exit(1); + } + } + + private async callKicadScript(command: string, params: any): Promise { + return new Promise((resolve, reject) => { + // Check if Python process is running + if (!this.pythonProcess) { + console.error("Python process is not running"); + reject(new Error("Python process for KiCAD scripting is not running")); + return; + } + + // Add request to queue + this.requestQueue.push({ + request: { command, params }, + resolve, + reject, + }); + + // Process the queue if not already processing + if (!this.processingRequest) { + this.processNextRequest(); + } + }); + } + + private processNextRequest(): void { + // If no more requests or already processing, return + if (this.requestQueue.length === 0 || this.processingRequest) { + return; + } + + // Set processing flag + this.processingRequest = true; + + // Get the next request + const { request, resolve, reject } = this.requestQueue.shift()!; + + try { + console.error(`Processing KiCAD command: ${request.command}`); + + // Format the command and parameters as JSON + const requestStr = JSON.stringify(request); + + // Set up response handling + let responseData = ""; + + // Clear any previous listeners + if (this.pythonProcess?.stdout) { + this.pythonProcess.stdout.removeAllListeners("data"); + } + + // Set up new listeners + if (this.pythonProcess?.stdout) { + this.pythonProcess.stdout.on("data", (data: Buffer) => { + const chunk = data.toString(); + console.error(`Received data chunk: ${chunk.length} bytes`); + responseData += chunk; + + // Check if we have a complete response + try { + // Try to parse the response as JSON + const result = JSON.parse(responseData); + + // If we get here, we have a valid JSON response + console.error( + `Completed KiCAD command: ${request.command} with result: ${JSON.stringify(result)}`, + ); + + // Reset processing flag + this.processingRequest = false; + + // Process next request if any + setTimeout(() => this.processNextRequest(), 0); + + // Clear listeners + if (this.pythonProcess?.stdout) { + this.pythonProcess.stdout.removeAllListeners("data"); + } + + // Resolve with the expected MCP tool response format + if (result.success) { + resolve({ + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }); + } else { + resolve({ + content: [ + { + type: "text", + text: result.errorDetails || result.message || "Unknown error", + }, + ], + isError: true, + }); + } + } catch (e) { + // Not a complete JSON yet, keep collecting data + } + }); + } + + // Set a timeout + const timeout = setTimeout(() => { + console.error(`Command timeout: ${request.command}`); + + // Clear listeners + if (this.pythonProcess?.stdout) { + this.pythonProcess.stdout.removeAllListeners("data"); + } + + // Reset processing flag + this.processingRequest = false; + + // Process next request + setTimeout(() => this.processNextRequest(), 0); + + // Reject the promise + reject(new Error(`Command timeout: ${request.command}`)); + }, 30000); // 30 seconds timeout + + // Write the request to the Python process + console.error(`Sending request: ${requestStr}`); + this.pythonProcess?.stdin?.write(requestStr + "\n"); + } catch (error) { + console.error(`Error processing request: ${error}`); + + // Reset processing flag + this.processingRequest = false; + + // Process next request + setTimeout(() => this.processNextRequest(), 0); + + // Reject the promise + reject(error); + } + } +} + +// Start the server +const server = new KiCADServer(); +server.start().catch(console.error); diff --git a/src/logger.ts b/src/logger.ts index cb1cef7..7246152 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -2,21 +2,21 @@ * Logger for KiCAD MCP server */ -import { existsSync, mkdirSync, appendFileSync } from 'fs'; -import { join } from 'path'; -import * as os from 'os'; +import { existsSync, mkdirSync, appendFileSync } from "fs"; +import { join } from "path"; +import * as os from "os"; // Log levels -type LogLevel = 'error' | 'warn' | 'info' | 'debug'; +type LogLevel = "error" | "warn" | "info" | "debug"; // 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 */ class Logger { - private logLevel: LogLevel = 'info'; + private logLevel: LogLevel = "info"; private logDir: string = DEFAULT_LOG_DIR; /** @@ -45,7 +45,7 @@ class Logger { * @param message Message to log */ error(message: string): void { - this.log('error', message); + this.log("error", message); } /** @@ -53,8 +53,8 @@ class Logger { * @param message Message to log */ warn(message: string): void { - if (['error', 'warn', 'info', 'debug'].includes(this.logLevel)) { - this.log('warn', message); + if (["error", "warn", "info", "debug"].includes(this.logLevel)) { + this.log("warn", message); } } @@ -63,8 +63,8 @@ class Logger { * @param message Message to log */ info(message: string): void { - if (['info', 'debug'].includes(this.logLevel)) { - this.log('info', message); + if (["info", "debug"].includes(this.logLevel)) { + this.log("info", message); } } @@ -73,8 +73,8 @@ class Logger { * @param message Message to log */ debug(message: string): void { - if (this.logLevel === 'debug') { - this.log('debug', message); + if (this.logLevel === "debug") { + this.log("debug", message); } } @@ -85,8 +85,9 @@ class Logger { */ private log(level: LogLevel, message: string): void { const now = new Date(); - const pad = (n: number, w = 2) => String(n).padStart(w, '0'); - const timestamp = `${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())} ` + + const pad = (n: number, w = 2) => String(n).padStart(w, "0"); + const timestamp = + `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ` + `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())},${pad(now.getMilliseconds(), 3)}`; const formattedMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`; @@ -101,8 +102,8 @@ class Logger { mkdirSync(this.logDir, { recursive: true }); } - const logFile = join(this.logDir, `kicad-mcp-${new Date().toISOString().split('T')[0]}.log`); - appendFileSync(logFile, formattedMessage + '\n'); + const logFile = join(this.logDir, `kicad-mcp-${new Date().toISOString().split("T")[0]}.log`); + appendFileSync(logFile, formattedMessage + "\n"); } catch (error) { console.error(`Failed to write to log file: ${error}`); } diff --git a/src/prompts/component.ts b/src/prompts/component.ts index 4379609..ba25631 100644 --- a/src/prompts/component.ts +++ b/src/prompts/component.ts @@ -1,231 +1,237 @@ -/** - * Component prompts for KiCAD MCP server - * - * These prompts guide the LLM in providing assistance with component-related tasks - * in KiCAD PCB design. - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; - -/** - * Register component prompts with the MCP server - * - * @param server MCP server instance - */ -export function registerComponentPrompts(server: McpServer): void { - logger.info('Registering component prompts'); - - // ------------------------------------------------------ - // Component Selection Prompt - // ------------------------------------------------------ - server.prompt( - "component_selection", - { - requirements: z.string().describe("Description of the circuit requirements and constraints") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to select components for a circuit design. Given the following requirements: - -{{requirements}} - -Suggest appropriate components with their values, ratings, and footprints. Consider factors like: -- Power and voltage ratings -- Current handling capabilities -- Tolerance requirements -- Physical size constraints and package types -- Availability and cost considerations -- Thermal characteristics -- 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.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Component Placement Strategy Prompt - // ------------------------------------------------------ - server.prompt( - "component_placement_strategy", - { - components: z.string().describe("List of components to be placed on the PCB") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping with component placement for a PCB layout. Here are the components to place: - -{{components}} - -Provide a strategy for optimal placement considering: - -1. Signal Integrity: - - Group related components to minimize signal path length - - Keep sensitive signals away from noisy components - - Consider appropriate placement for bypass/decoupling capacitors - -2. Thermal Management: - - Distribute heat-generating components - - Ensure adequate spacing for cooling - - Placement near heat sinks or vias for thermal dissipation - -3. EMI/EMC Concerns: - - Separate digital and analog sections - - Consider ground plane partitioning - - Shield sensitive components - -4. Manufacturing and Assembly: - - Component orientation for automated assembly - - Adequate spacing for rework - - Consider component height distribution - -Group components functionally and suggest a logical arrangement. If possible, provide a rough sketch or description of component zones.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Component Replacement Analysis Prompt - // ------------------------------------------------------ - server.prompt( - "component_replacement_analysis", - { - component_info: z.string().describe("Information about the component that needs to be replaced") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to find a replacement for a component that is unavailable or needs to be updated. Here's the original component information: - -{{component_info}} - -Consider these factors when suggesting replacements: - -1. Electrical Compatibility: - - Match or exceed key electrical specifications - - Ensure voltage/current/power ratings are compatible - - Consider parametric equivalents - -2. Physical Compatibility: - - Footprint compatibility or adaptation requirements - - Package differences and mounting considerations - - Size and clearance requirements - -3. Performance Impact: - - How the replacement might affect circuit performance - - Potential need for circuit adjustments - -4. Availability and Cost: - - Current market availability - - Cost comparison with original part - - Lead time considerations - -Suggest suitable replacement options and explain the advantages and disadvantages of each. Include any circuit modifications that might be necessary.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Component Troubleshooting Prompt - // ------------------------------------------------------ - server.prompt( - "component_troubleshooting", - { - issue_description: z.string().describe("Description of the component or circuit issue being troubleshooted") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to troubleshoot an issue with a component or circuit section in a PCB design. Here's the issue description: - -{{issue_description}} - -Use the following systematic approach to diagnose the problem: - -1. Component Verification: - - Check component values, footprints, and orientation - - Verify correct part numbers and specifications - - Examine for potential manufacturing defects - -2. Circuit Analysis: - - Review the schematic for design errors - - Check for proper connections and signal paths - - Verify power and ground connections - -3. Layout Review: - - Examine component placement and orientation - - Check for adequate clearances - - Review trace routing and potential interference - -4. Environmental Factors: - - Consider temperature, humidity, and other environmental impacts - - Check for potential EMI/RFI issues - - 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.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Component Value Calculation Prompt - // ------------------------------------------------------ - server.prompt( - "component_value_calculation", - { - circuit_requirements: z.string().describe("Description of the circuit function and performance requirements") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to calculate appropriate component values for a specific circuit function. Here's the circuit description and requirements: - -{{circuit_requirements}} - -Follow these steps to determine the optimal component values: - -1. Identify the relevant circuit equations and design formulas -2. Consider the design constraints and performance requirements -3. Calculate initial component values based on ideal behavior -4. Adjust for real-world factors: - - Component tolerances - - Temperature coefficients - - Parasitic effects - - 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.` - } - } - ] - }) - ); - - logger.info('Component prompts registered'); -} +/** + * Component prompts for KiCAD MCP server + * + * These prompts guide the LLM in providing assistance with component-related tasks + * in KiCAD PCB design. + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; + +/** + * Register component prompts with the MCP server + * + * @param server MCP server instance + */ +export function registerComponentPrompts(server: McpServer): void { + logger.info("Registering component prompts"); + + // ------------------------------------------------------ + // Component Selection Prompt + // ------------------------------------------------------ + server.prompt( + "component_selection", + { + requirements: z.string().describe("Description of the circuit requirements and constraints"), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to select components for a circuit design. Given the following requirements: + +{{requirements}} + +Suggest appropriate components with their values, ratings, and footprints. Consider factors like: +- Power and voltage ratings +- Current handling capabilities +- Tolerance requirements +- Physical size constraints and package types +- Availability and cost considerations +- Thermal characteristics +- 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.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Component Placement Strategy Prompt + // ------------------------------------------------------ + server.prompt( + "component_placement_strategy", + { + components: z.string().describe("List of components to be placed on the PCB"), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping with component placement for a PCB layout. Here are the components to place: + +{{components}} + +Provide a strategy for optimal placement considering: + +1. Signal Integrity: + - Group related components to minimize signal path length + - Keep sensitive signals away from noisy components + - Consider appropriate placement for bypass/decoupling capacitors + +2. Thermal Management: + - Distribute heat-generating components + - Ensure adequate spacing for cooling + - Placement near heat sinks or vias for thermal dissipation + +3. EMI/EMC Concerns: + - Separate digital and analog sections + - Consider ground plane partitioning + - Shield sensitive components + +4. Manufacturing and Assembly: + - Component orientation for automated assembly + - Adequate spacing for rework + - Consider component height distribution + +Group components functionally and suggest a logical arrangement. If possible, provide a rough sketch or description of component zones.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Component Replacement Analysis Prompt + // ------------------------------------------------------ + server.prompt( + "component_replacement_analysis", + { + component_info: z + .string() + .describe("Information about the component that needs to be replaced"), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to find a replacement for a component that is unavailable or needs to be updated. Here's the original component information: + +{{component_info}} + +Consider these factors when suggesting replacements: + +1. Electrical Compatibility: + - Match or exceed key electrical specifications + - Ensure voltage/current/power ratings are compatible + - Consider parametric equivalents + +2. Physical Compatibility: + - Footprint compatibility or adaptation requirements + - Package differences and mounting considerations + - Size and clearance requirements + +3. Performance Impact: + - How the replacement might affect circuit performance + - Potential need for circuit adjustments + +4. Availability and Cost: + - Current market availability + - Cost comparison with original part + - Lead time considerations + +Suggest suitable replacement options and explain the advantages and disadvantages of each. Include any circuit modifications that might be necessary.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Component Troubleshooting Prompt + // ------------------------------------------------------ + server.prompt( + "component_troubleshooting", + { + issue_description: z + .string() + .describe("Description of the component or circuit issue being troubleshooted"), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to troubleshoot an issue with a component or circuit section in a PCB design. Here's the issue description: + +{{issue_description}} + +Use the following systematic approach to diagnose the problem: + +1. Component Verification: + - Check component values, footprints, and orientation + - Verify correct part numbers and specifications + - Examine for potential manufacturing defects + +2. Circuit Analysis: + - Review the schematic for design errors + - Check for proper connections and signal paths + - Verify power and ground connections + +3. Layout Review: + - Examine component placement and orientation + - Check for adequate clearances + - Review trace routing and potential interference + +4. Environmental Factors: + - Consider temperature, humidity, and other environmental impacts + - Check for potential EMI/RFI issues + - 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.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Component Value Calculation Prompt + // ------------------------------------------------------ + server.prompt( + "component_value_calculation", + { + circuit_requirements: z + .string() + .describe("Description of the circuit function and performance requirements"), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to calculate appropriate component values for a specific circuit function. Here's the circuit description and requirements: + +{{circuit_requirements}} + +Follow these steps to determine the optimal component values: + +1. Identify the relevant circuit equations and design formulas +2. Consider the design constraints and performance requirements +3. Calculate initial component values based on ideal behavior +4. Adjust for real-world factors: + - Component tolerances + - Temperature coefficients + - Parasitic effects + - 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.`, + }, + }, + ], + }), + ); + + logger.info("Component prompts registered"); +} diff --git a/src/prompts/design.ts b/src/prompts/design.ts index 5c2f5cb..0082ec1 100644 --- a/src/prompts/design.ts +++ b/src/prompts/design.ts @@ -1,321 +1,345 @@ -/** - * Design prompts for KiCAD MCP server - * - * These prompts guide the LLM in providing assistance with general PCB design tasks - * in KiCAD. - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; - -/** - * Register design prompts with the MCP server - * - * @param server MCP server instance - */ -export function registerDesignPrompts(server: McpServer): void { - logger.info('Registering design prompts'); - - // ------------------------------------------------------ - // PCB Layout Review Prompt - // ------------------------------------------------------ - server.prompt( - "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") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to review a PCB layout for potential issues and improvements. Here's information about the current PCB design: - -{{pcb_design_info}} - -When reviewing the PCB layout, consider these key areas: - -1. Component Placement: - - Logical grouping of related components - - Orientation for efficient routing - - Thermal considerations for heat-generating components - - Mechanical constraints (mounting holes, connectors at edges) - - Accessibility for testing and rework - -2. Signal Integrity: - - Trace lengths for critical signals - - Differential pair routing quality - - Potential crosstalk issues - - Return path continuity - - Decoupling capacitor placement - -3. Power Distribution: - - Adequate copper for power rails - - Power plane design and continuity - - Decoupling strategy effectiveness - - Voltage regulator thermal management - -4. EMI/EMC Considerations: - - Ground plane integrity - - Potential antenna effects - - Shielding requirements - - Loop area minimization - - Edge radiation control - -5. Manufacturing and Assembly: - - DFM (Design for Manufacturing) issues - - DFA (Design for Assembly) considerations - - Testability features - - Silkscreen clarity and usefulness - - Solder mask considerations - -Based on the provided information, identify potential issues and suggest specific improvements to enhance the PCB design.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Layer Stack-up Planning Prompt - // ------------------------------------------------------ - server.prompt( - "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") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to plan an appropriate layer stack-up for a PCB design. Here's information about the design requirements: - -{{design_requirements}} - -When planning a PCB layer stack-up, consider these important factors: - -1. Signal Integrity Requirements: - - Controlled impedance needs - - High-speed signal routing - - EMI/EMC considerations - - Crosstalk mitigation - -2. Power Distribution Needs: - - Current requirements for power rails - - Power integrity considerations - - Decoupling effectiveness - - Thermal management - -3. Manufacturing Constraints: - - Fabrication capabilities and limitations - - Cost considerations - - Available materials and their properties - - Standard vs. specialized processes - -4. Layer Types and Arrangement: - - Signal layers - - Power and ground planes - - Mixed signal/plane layers - - Microstrip vs. stripline configurations - -5. Material Selection: - - Dielectric constant (Er) requirements - - Loss tangent considerations for high-speed - - Thermal properties - - 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.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Design Rule Development Prompt - // ------------------------------------------------------ - server.prompt( - "design_rule_development", - { - project_requirements: z.string().describe("Information about the PCB project requirements, including technology, speed/frequency, manufacturing capabilities, and any special considerations") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to develop appropriate design rules for a PCB project. Here's information about the project requirements: - -{{project_requirements}} - -When developing PCB design rules, consider these key areas: - -1. Clearance Rules: - - Minimum spacing between copper features - - Different clearance requirements for different net classes - - High-voltage clearance requirements - - Polygon pour clearances - -2. Width Rules: - - Minimum trace widths for signal nets - - Power trace width requirements based on current - - Differential pair width and spacing - - Net class-specific width rules - -3. Via Rules: - - Minimum via size and drill diameter - - Via annular ring requirements - - Microvias and buried/blind via specifications - - Via-in-pad rules - -4. Manufacturing Constraints: - - Minimum hole size - - Aspect ratio limitations - - Soldermask and silkscreen constraints - - Edge clearances - -5. Special Requirements: - - Impedance control specifications - - High-speed routing constraints - - Thermal relief parameters - - 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.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Component Selection Guidance Prompt - // ------------------------------------------------------ - server.prompt( - "component_selection_guidance", - { - circuit_requirements: z.string().describe("Information about the circuit requirements, including functionality, performance needs, operating environment, and any special considerations") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping with component selection for a PCB design. Here's information about the circuit requirements: - -{{circuit_requirements}} - -When selecting components for a PCB design, consider these important factors: - -1. Electrical Specifications: - - Voltage and current ratings - - Power handling capabilities - - Speed/frequency requirements - - Noise and precision considerations - - Operating temperature range - -2. Package and Footprint: - - Space constraints on the PCB - - Thermal dissipation requirements - - Manual vs. automated assembly - - Inspection and rework considerations - - Available footprint libraries - -3. Availability and Sourcing: - - Multiple source options - - Lead time considerations - - Lifecycle status (new, mature, end-of-life) - - Cost considerations - - Minimum order quantities - -4. Reliability and Quality: - - Industrial vs. commercial vs. automotive grade - - Expected lifetime of the product - - Environmental conditions - - Compliance with relevant standards - -5. Special Considerations: - - EMI/EMC performance - - Thermal characteristics - - Moisture sensitivity - - RoHS/REACH compliance - - 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.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // PCB Design Optimization Prompt - // ------------------------------------------------------ - server.prompt( - "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"), - optimization_goals: z.string().describe("Specific goals for optimization, such as performance improvement, cost reduction, size reduction, or manufacturability enhancement") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to optimize a PCB design. Here's information about the current design and optimization goals: - -{{design_info}} -{{optimization_goals}} - -When optimizing a PCB design, consider these key areas based on the stated goals: - -1. Performance Optimization: - - Critical signal path length reduction - - Impedance control improvement - - Decoupling strategy enhancement - - Thermal management improvement - - EMI/EMC reduction techniques - -2. Manufacturability Optimization: - - DFM rule compliance - - Testability improvements - - Assembly process simplification - - Yield improvement opportunities - - Tolerance and variation management - -3. Cost Optimization: - - Board size reduction opportunities - - Layer count optimization - - Component consolidation - - Alternative component options - - Panelization efficiency - -4. Reliability Optimization: - - Stress point identification and mitigation - - Environmental robustness improvements - - Failure mode mitigation - - Margin analysis and improvement - - Redundancy considerations - -5. Space/Size Optimization: - - Component placement density - - 3D space utilization - - Flex and rigid-flex opportunities - - Alternative packaging approaches - - 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.` - } - } - ] - }) - ); - - logger.info('Design prompts registered'); -} +/** + * Design prompts for KiCAD MCP server + * + * These prompts guide the LLM in providing assistance with general PCB design tasks + * in KiCAD. + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; + +/** + * Register design prompts with the MCP server + * + * @param server MCP server instance + */ +export function registerDesignPrompts(server: McpServer): void { + logger.info("Registering design prompts"); + + // ------------------------------------------------------ + // PCB Layout Review Prompt + // ------------------------------------------------------ + server.prompt( + "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", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to review a PCB layout for potential issues and improvements. Here's information about the current PCB design: + +{{pcb_design_info}} + +When reviewing the PCB layout, consider these key areas: + +1. Component Placement: + - Logical grouping of related components + - Orientation for efficient routing + - Thermal considerations for heat-generating components + - Mechanical constraints (mounting holes, connectors at edges) + - Accessibility for testing and rework + +2. Signal Integrity: + - Trace lengths for critical signals + - Differential pair routing quality + - Potential crosstalk issues + - Return path continuity + - Decoupling capacitor placement + +3. Power Distribution: + - Adequate copper for power rails + - Power plane design and continuity + - Decoupling strategy effectiveness + - Voltage regulator thermal management + +4. EMI/EMC Considerations: + - Ground plane integrity + - Potential antenna effects + - Shielding requirements + - Loop area minimization + - Edge radiation control + +5. Manufacturing and Assembly: + - DFM (Design for Manufacturing) issues + - DFA (Design for Assembly) considerations + - Testability features + - Silkscreen clarity and usefulness + - Solder mask considerations + +Based on the provided information, identify potential issues and suggest specific improvements to enhance the PCB design.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Layer Stack-up Planning Prompt + // ------------------------------------------------------ + server.prompt( + "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", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to plan an appropriate layer stack-up for a PCB design. Here's information about the design requirements: + +{{design_requirements}} + +When planning a PCB layer stack-up, consider these important factors: + +1. Signal Integrity Requirements: + - Controlled impedance needs + - High-speed signal routing + - EMI/EMC considerations + - Crosstalk mitigation + +2. Power Distribution Needs: + - Current requirements for power rails + - Power integrity considerations + - Decoupling effectiveness + - Thermal management + +3. Manufacturing Constraints: + - Fabrication capabilities and limitations + - Cost considerations + - Available materials and their properties + - Standard vs. specialized processes + +4. Layer Types and Arrangement: + - Signal layers + - Power and ground planes + - Mixed signal/plane layers + - Microstrip vs. stripline configurations + +5. Material Selection: + - Dielectric constant (Er) requirements + - Loss tangent considerations for high-speed + - Thermal properties + - 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.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Design Rule Development Prompt + // ------------------------------------------------------ + server.prompt( + "design_rule_development", + { + project_requirements: z + .string() + .describe( + "Information about the PCB project requirements, including technology, speed/frequency, manufacturing capabilities, and any special considerations", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to develop appropriate design rules for a PCB project. Here's information about the project requirements: + +{{project_requirements}} + +When developing PCB design rules, consider these key areas: + +1. Clearance Rules: + - Minimum spacing between copper features + - Different clearance requirements for different net classes + - High-voltage clearance requirements + - Polygon pour clearances + +2. Width Rules: + - Minimum trace widths for signal nets + - Power trace width requirements based on current + - Differential pair width and spacing + - Net class-specific width rules + +3. Via Rules: + - Minimum via size and drill diameter + - Via annular ring requirements + - Microvias and buried/blind via specifications + - Via-in-pad rules + +4. Manufacturing Constraints: + - Minimum hole size + - Aspect ratio limitations + - Soldermask and silkscreen constraints + - Edge clearances + +5. Special Requirements: + - Impedance control specifications + - High-speed routing constraints + - Thermal relief parameters + - 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.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Component Selection Guidance Prompt + // ------------------------------------------------------ + server.prompt( + "component_selection_guidance", + { + circuit_requirements: z + .string() + .describe( + "Information about the circuit requirements, including functionality, performance needs, operating environment, and any special considerations", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping with component selection for a PCB design. Here's information about the circuit requirements: + +{{circuit_requirements}} + +When selecting components for a PCB design, consider these important factors: + +1. Electrical Specifications: + - Voltage and current ratings + - Power handling capabilities + - Speed/frequency requirements + - Noise and precision considerations + - Operating temperature range + +2. Package and Footprint: + - Space constraints on the PCB + - Thermal dissipation requirements + - Manual vs. automated assembly + - Inspection and rework considerations + - Available footprint libraries + +3. Availability and Sourcing: + - Multiple source options + - Lead time considerations + - Lifecycle status (new, mature, end-of-life) + - Cost considerations + - Minimum order quantities + +4. Reliability and Quality: + - Industrial vs. commercial vs. automotive grade + - Expected lifetime of the product + - Environmental conditions + - Compliance with relevant standards + +5. Special Considerations: + - EMI/EMC performance + - Thermal characteristics + - Moisture sensitivity + - RoHS/REACH compliance + - 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.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // PCB Design Optimization Prompt + // ------------------------------------------------------ + server.prompt( + "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", + ), + optimization_goals: z + .string() + .describe( + "Specific goals for optimization, such as performance improvement, cost reduction, size reduction, or manufacturability enhancement", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to optimize a PCB design. Here's information about the current design and optimization goals: + +{{design_info}} +{{optimization_goals}} + +When optimizing a PCB design, consider these key areas based on the stated goals: + +1. Performance Optimization: + - Critical signal path length reduction + - Impedance control improvement + - Decoupling strategy enhancement + - Thermal management improvement + - EMI/EMC reduction techniques + +2. Manufacturability Optimization: + - DFM rule compliance + - Testability improvements + - Assembly process simplification + - Yield improvement opportunities + - Tolerance and variation management + +3. Cost Optimization: + - Board size reduction opportunities + - Layer count optimization + - Component consolidation + - Alternative component options + - Panelization efficiency + +4. Reliability Optimization: + - Stress point identification and mitigation + - Environmental robustness improvements + - Failure mode mitigation + - Margin analysis and improvement + - Redundancy considerations + +5. Space/Size Optimization: + - Component placement density + - 3D space utilization + - Flex and rigid-flex opportunities + - Alternative packaging approaches + - 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.`, + }, + }, + ], + }), + ); + + logger.info("Design prompts registered"); +} diff --git a/src/prompts/footprint.ts b/src/prompts/footprint.ts index 81556af..623104c 100644 --- a/src/prompts/footprint.ts +++ b/src/prompts/footprint.ts @@ -23,10 +23,7 @@ export function registerFootprintPrompts(server: McpServer): void { .describe( "Component description, e.g. 'SOT-23 NPN transistor' or '2-pin JST XH 2.5mm connector'", ), - libraryPath: z - .string() - .optional() - .describe("Target .pretty library path (optional)"), + libraryPath: z.string().optional().describe("Target .pretty library path (optional)"), }, () => ({ messages: [ @@ -107,9 +104,7 @@ Now create the footprint for: {{component}}`, server.prompt( "footprint_ipc_checklist", { - footprintPath: z - .string() - .describe("Path to the .kicad_mod file to review"), + footprintPath: z.string().describe("Path to the .kicad_mod file to review"), }, () => ({ messages: [ diff --git a/src/prompts/routing.ts b/src/prompts/routing.ts index cd8eb92..0f146ac 100644 --- a/src/prompts/routing.ts +++ b/src/prompts/routing.ts @@ -1,288 +1,308 @@ -/** - * Routing prompts for KiCAD MCP server - * - * These prompts guide the LLM in providing assistance with routing-related tasks - * in KiCAD PCB design. - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; - -/** - * Register routing prompts with the MCP server - * - * @param server MCP server instance - */ -export function registerRoutingPrompts(server: McpServer): void { - logger.info('Registering routing prompts'); - - // ------------------------------------------------------ - // Routing Strategy Prompt - // ------------------------------------------------------ - server.prompt( - "routing_strategy", - { - board_info: z.string().describe("Information about the PCB board, including dimensions, layer stack-up, and components") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping to develop a routing strategy for a PCB design. Here's information about the board: - -{{board_info}} - -Consider the following aspects when developing your routing strategy: - -1. Signal Integrity: - - Group related signals and keep them close - - Minimize trace length for high-speed signals - - Consider differential pair routing for appropriate signals - - Avoid right-angle bends in traces - -2. Power Distribution: - - Use appropriate trace widths for power and ground - - Consider using power planes for better distribution - - Place decoupling capacitors close to ICs - -3. EMI/EMC Considerations: - - Keep digital and analog sections separated - - Consider ground plane partitioning - - Minimize loop areas for sensitive signals - -4. Manufacturing Constraints: - - Adhere to minimum trace width and spacing requirements - - Consider via size and placement restrictions - - Account for soldermask and silkscreen limitations - -5. Layer Stack-up Utilization: - - Determine which signals go on which layers - - Plan for layer transitions (vias) - - Consider impedance control requirements - -Provide a comprehensive routing strategy that addresses these aspects, with specific recommendations for this particular board design.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Differential Pair Routing Prompt - // ------------------------------------------------------ - server.prompt( - "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") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping with routing differential pairs on a PCB. Here's information about the differential pairs: - -{{differential_pairs}} - -When routing differential pairs, follow these best practices: - -1. Length Matching: - - Keep both traces in each pair the same length - - Maintain consistent spacing between the traces - - Use serpentine routing (meanders) for length matching when necessary - -2. Impedance Control: - - Maintain consistent trace width and spacing to control impedance - - Consider the layer stack-up and dielectric properties - - Avoid changing layers if possible; when necessary, use symmetrical via pairs - -3. Coupling and Crosstalk: - - Keep differential pairs tightly coupled to each other - - Maintain adequate spacing between different differential pairs - - Route away from single-ended signals that could cause interference - -4. Reference Planes: - - Route over continuous reference planes - - Avoid splits in reference planes under differential pairs - - Consider the return path for the signals - -5. Termination: - - Plan for proper termination at the ends of the pairs - - Consider the need for series or parallel termination resistors - - 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.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // High-Speed Routing Prompt - // ------------------------------------------------------ - server.prompt( - "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") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping with routing high-speed signals on a PCB. Here's information about the high-speed signals: - -{{high_speed_signals}} - -When routing high-speed signals, consider these critical factors: - -1. Impedance Control: - - Maintain consistent trace width to control impedance - - Use controlled impedance calculations based on layer stack-up - - Consider microstrip vs. stripline routing depending on signal requirements - -2. Signal Integrity: - - Minimize trace length to reduce propagation delay - - Avoid sharp corners (use 45° angles or curves) - - Minimize vias to reduce discontinuities - - Consider using teardrops at pad connections - -3. Crosstalk Mitigation: - - Maintain adequate spacing between high-speed traces - - Use ground traces or planes for isolation - - Cross traces at 90° when traces must cross on adjacent layers - -4. Return Path Management: - - Ensure continuous return path under the signal - - Avoid reference plane splits under high-speed signals - - Use ground vias near signal vias for return path continuity - -5. Termination and Loading: - - Plan for proper termination (series, parallel, AC, etc.) - - Consider transmission line effects - - 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.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Power Distribution Prompt - // ------------------------------------------------------ - server.prompt( - "power_distribution", - { - power_requirements: z.string().describe("Information about the power requirements, including voltage rails, current needs, and components requiring power") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping with designing the power distribution network for a PCB. Here's information about the power requirements: - -{{power_requirements}} - -Consider these key aspects of power distribution network design: - -1. Power Planes vs. Traces: - - Determine when to use power planes versus wide traces - - Consider current requirements and voltage drop - - Plan the layer stack-up to accommodate power distribution - -2. Decoupling Strategy: - - Place decoupling capacitors close to ICs - - Use appropriate capacitor values and types - - Consider high-frequency and bulk decoupling needs - - Plan for power entry filtering - -3. Current Capacity: - - Calculate trace widths based on current requirements - - Consider thermal issues and heat dissipation - - Plan for current return paths - -4. Voltage Regulation: - - Place regulators strategically - - Consider thermal management for regulators - - Plan feedback paths for regulators - -5. EMI/EMC Considerations: - - Minimize loop areas - - Keep power and ground planes closely coupled - - 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.` - } - } - ] - }) - ); - - // ------------------------------------------------------ - // Via Usage Prompt - // ------------------------------------------------------ - server.prompt( - "via_usage", - { - board_info: z.string().describe("Information about the PCB board, including layer count, thickness, and design requirements") - }, - () => ({ - messages: [ - { - role: "user", - content: { - type: "text", - text: `You're helping with planning via usage in a PCB design. Here's information about the board: - -{{board_info}} - -Consider these important aspects of via usage: - -1. Via Types: - - Through-hole vias (span all layers) - - Blind vias (connect outer layer to inner layer) - - Buried vias (connect inner layers only) - - Microvias (small diameter vias for HDI designs) - -2. Manufacturing Constraints: - - Minimum via diameter and drill size - - Aspect ratio limitations (board thickness to hole diameter) - - Annular ring requirements - - Via-in-pad considerations and special processing - -3. Signal Integrity Impact: - - Capacitive loading effects of vias - - Impedance discontinuities - - Stub effects in through-hole vias - - Strategies to minimize via impact on high-speed signals - -4. Thermal Considerations: - - Using vias for thermal relief - - Via patterns for heat dissipation - - Thermal via sizing and spacing - -5. Design Optimization: - - Via fanout strategies - - Sharing vias between signals vs. dedicated vias - - Via placement to minimize trace length - - 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.` - } - } - ] - }) - ); - - logger.info('Routing prompts registered'); -} +/** + * Routing prompts for KiCAD MCP server + * + * These prompts guide the LLM in providing assistance with routing-related tasks + * in KiCAD PCB design. + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; + +/** + * Register routing prompts with the MCP server + * + * @param server MCP server instance + */ +export function registerRoutingPrompts(server: McpServer): void { + logger.info("Registering routing prompts"); + + // ------------------------------------------------------ + // Routing Strategy Prompt + // ------------------------------------------------------ + server.prompt( + "routing_strategy", + { + board_info: z + .string() + .describe( + "Information about the PCB board, including dimensions, layer stack-up, and components", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping to develop a routing strategy for a PCB design. Here's information about the board: + +{{board_info}} + +Consider the following aspects when developing your routing strategy: + +1. Signal Integrity: + - Group related signals and keep them close + - Minimize trace length for high-speed signals + - Consider differential pair routing for appropriate signals + - Avoid right-angle bends in traces + +2. Power Distribution: + - Use appropriate trace widths for power and ground + - Consider using power planes for better distribution + - Place decoupling capacitors close to ICs + +3. EMI/EMC Considerations: + - Keep digital and analog sections separated + - Consider ground plane partitioning + - Minimize loop areas for sensitive signals + +4. Manufacturing Constraints: + - Adhere to minimum trace width and spacing requirements + - Consider via size and placement restrictions + - Account for soldermask and silkscreen limitations + +5. Layer Stack-up Utilization: + - Determine which signals go on which layers + - Plan for layer transitions (vias) + - Consider impedance control requirements + +Provide a comprehensive routing strategy that addresses these aspects, with specific recommendations for this particular board design.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Differential Pair Routing Prompt + // ------------------------------------------------------ + server.prompt( + "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", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping with routing differential pairs on a PCB. Here's information about the differential pairs: + +{{differential_pairs}} + +When routing differential pairs, follow these best practices: + +1. Length Matching: + - Keep both traces in each pair the same length + - Maintain consistent spacing between the traces + - Use serpentine routing (meanders) for length matching when necessary + +2. Impedance Control: + - Maintain consistent trace width and spacing to control impedance + - Consider the layer stack-up and dielectric properties + - Avoid changing layers if possible; when necessary, use symmetrical via pairs + +3. Coupling and Crosstalk: + - Keep differential pairs tightly coupled to each other + - Maintain adequate spacing between different differential pairs + - Route away from single-ended signals that could cause interference + +4. Reference Planes: + - Route over continuous reference planes + - Avoid splits in reference planes under differential pairs + - Consider the return path for the signals + +5. Termination: + - Plan for proper termination at the ends of the pairs + - Consider the need for series or parallel termination resistors + - 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.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // High-Speed Routing Prompt + // ------------------------------------------------------ + server.prompt( + "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", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping with routing high-speed signals on a PCB. Here's information about the high-speed signals: + +{{high_speed_signals}} + +When routing high-speed signals, consider these critical factors: + +1. Impedance Control: + - Maintain consistent trace width to control impedance + - Use controlled impedance calculations based on layer stack-up + - Consider microstrip vs. stripline routing depending on signal requirements + +2. Signal Integrity: + - Minimize trace length to reduce propagation delay + - Avoid sharp corners (use 45° angles or curves) + - Minimize vias to reduce discontinuities + - Consider using teardrops at pad connections + +3. Crosstalk Mitigation: + - Maintain adequate spacing between high-speed traces + - Use ground traces or planes for isolation + - Cross traces at 90° when traces must cross on adjacent layers + +4. Return Path Management: + - Ensure continuous return path under the signal + - Avoid reference plane splits under high-speed signals + - Use ground vias near signal vias for return path continuity + +5. Termination and Loading: + - Plan for proper termination (series, parallel, AC, etc.) + - Consider transmission line effects + - 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.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Power Distribution Prompt + // ------------------------------------------------------ + server.prompt( + "power_distribution", + { + power_requirements: z + .string() + .describe( + "Information about the power requirements, including voltage rails, current needs, and components requiring power", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping with designing the power distribution network for a PCB. Here's information about the power requirements: + +{{power_requirements}} + +Consider these key aspects of power distribution network design: + +1. Power Planes vs. Traces: + - Determine when to use power planes versus wide traces + - Consider current requirements and voltage drop + - Plan the layer stack-up to accommodate power distribution + +2. Decoupling Strategy: + - Place decoupling capacitors close to ICs + - Use appropriate capacitor values and types + - Consider high-frequency and bulk decoupling needs + - Plan for power entry filtering + +3. Current Capacity: + - Calculate trace widths based on current requirements + - Consider thermal issues and heat dissipation + - Plan for current return paths + +4. Voltage Regulation: + - Place regulators strategically + - Consider thermal management for regulators + - Plan feedback paths for regulators + +5. EMI/EMC Considerations: + - Minimize loop areas + - Keep power and ground planes closely coupled + - 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.`, + }, + }, + ], + }), + ); + + // ------------------------------------------------------ + // Via Usage Prompt + // ------------------------------------------------------ + server.prompt( + "via_usage", + { + board_info: z + .string() + .describe( + "Information about the PCB board, including layer count, thickness, and design requirements", + ), + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `You're helping with planning via usage in a PCB design. Here's information about the board: + +{{board_info}} + +Consider these important aspects of via usage: + +1. Via Types: + - Through-hole vias (span all layers) + - Blind vias (connect outer layer to inner layer) + - Buried vias (connect inner layers only) + - Microvias (small diameter vias for HDI designs) + +2. Manufacturing Constraints: + - Minimum via diameter and drill size + - Aspect ratio limitations (board thickness to hole diameter) + - Annular ring requirements + - Via-in-pad considerations and special processing + +3. Signal Integrity Impact: + - Capacitive loading effects of vias + - Impedance discontinuities + - Stub effects in through-hole vias + - Strategies to minimize via impact on high-speed signals + +4. Thermal Considerations: + - Using vias for thermal relief + - Via patterns for heat dissipation + - Thermal via sizing and spacing + +5. Design Optimization: + - Via fanout strategies + - Sharing vias between signals vs. dedicated vias + - Via placement to minimize trace length + - 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.`, + }, + }, + ], + }), + ); + + logger.info("Routing prompts registered"); +} diff --git a/src/resources/board.ts b/src/resources/board.ts index ce5d1f3..11f86b8 100644 --- a/src/resources/board.ts +++ b/src/resources/board.ts @@ -1,354 +1,372 @@ -/** - * Board resources for KiCAD MCP server - * - * These resources provide information about the PCB board - * to the LLM, enabling better context-aware assistance. - */ - -import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; -import { createJsonResponse, createBinaryResponse } from '../utils/resource-helpers.js'; - -// Command function type for KiCAD script calls -type CommandFunction = (command: string, params: Record) => Promise; - -/** - * Register board resources with the MCP server - * - * @param server MCP server instance - * @param callKicadScript Function to call KiCAD script commands - */ -export function registerBoardResources(server: McpServer, callKicadScript: CommandFunction): void { - logger.info('Registering board resources'); - - // ------------------------------------------------------ - // Board Information Resource - // ------------------------------------------------------ - server.resource( - "board_info", - "kicad://board/info", - async (uri) => { - logger.debug('Retrieving board information'); - const result = await callKicadScript("get_board_info", {}); - - if (!result.success) { - logger.error(`Failed to retrieve board information: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve board information", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug('Successfully retrieved board information'); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Layer List Resource - // ------------------------------------------------------ - server.resource( - "layer_list", - "kicad://board/layers", - async (uri) => { - logger.debug('Retrieving layer list'); - const result = await callKicadScript("get_layer_list", {}); - - if (!result.success) { - logger.error(`Failed to retrieve layer list: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve layer list", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved ${result.layers?.length || 0} layers`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Board Extents Resource - // ------------------------------------------------------ - server.resource( - "board_extents", - new ResourceTemplate("kicad://board/extents/{unit?}", { - list: async () => ({ - resources: [ - { uri: "kicad://board/extents/mm", name: "Millimeters" }, - { uri: "kicad://board/extents/inch", name: "Inches" } - ] - }) - }), - async (uri, params) => { - const unit = params.unit || 'mm'; - - logger.debug(`Retrieving board extents in ${unit}`); - const result = await callKicadScript("get_board_extents", { unit }); - - if (!result.success) { - logger.error(`Failed to retrieve board extents: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve board extents", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug('Successfully retrieved board extents'); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Board 2D View Resource - // ------------------------------------------------------ - server.resource( - "board_2d_view", - new ResourceTemplate("kicad://board/2d-view/{format?}", { - list: async () => ({ - resources: [ - { uri: "kicad://board/2d-view/png", name: "PNG Format" }, - { uri: "kicad://board/2d-view/jpg", name: "JPEG Format" }, - { uri: "kicad://board/2d-view/svg", name: "SVG Format" } - ] - }) - }), - async (uri, params) => { - const format = (params.format || 'png') as 'png' | 'jpg' | 'svg'; - const width = params.width ? parseInt(params.width as string) : undefined; - const height = params.height ? parseInt(params.height as string) : undefined; - // Handle layers parameter - could be string or array - const layers = typeof params.layers === 'string' ? params.layers.split(',') : params.layers; - - logger.debug('Retrieving 2D board view'); - const result = await callKicadScript("get_board_2d_view", { - layers, - width, - height, - format - }); - - if (!result.success) { - logger.error(`Failed to retrieve 2D board view: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve 2D board view", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug('Successfully retrieved 2D board view'); - - if (format === 'svg') { - return { - contents: [{ - uri: uri.href, - text: result.imageData, - mimeType: "image/svg+xml" - }] - }; - } else { - return { - contents: [{ - uri: uri.href, - blob: result.imageData, - mimeType: format === "jpg" ? "image/jpeg" : "image/png" - }] - }; - } - } - ); - - // ------------------------------------------------------ - // Board 3D View Resource - // ------------------------------------------------------ - server.resource( - "board_3d_view", - new ResourceTemplate("kicad://board/3d-view/{angle?}", { - list: async () => ({ - resources: [ - { uri: "kicad://board/3d-view/isometric", name: "Isometric View" }, - { uri: "kicad://board/3d-view/top", name: "Top View" }, - { uri: "kicad://board/3d-view/bottom", name: "Bottom View" } - ] - }) - }), - async (uri, params) => { - const angle = params.angle || 'isometric'; - const width = params.width ? parseInt(params.width as string) : undefined; - const height = params.height ? parseInt(params.height as string) : undefined; - - logger.debug(`Retrieving 3D board view from ${angle} angle`); - const result = await callKicadScript("get_board_3d_view", { - width, - height, - angle - }); - - if (!result.success) { - logger.error(`Failed to retrieve 3D board view: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve 3D board view", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug('Successfully retrieved 3D board view'); - return { - contents: [{ - uri: uri.href, - blob: result.imageData, - mimeType: "image/png" - }] - }; - } - ); - - // ------------------------------------------------------ - // Board Statistics Resource - // ------------------------------------------------------ - server.resource( - "board_statistics", - "kicad://board/statistics", - async (uri) => { - logger.debug('Generating board statistics'); - - // Get board info - const boardResult = await callKicadScript("get_board_info", {}); - if (!boardResult.success) { - logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to generate board statistics", - details: boardResult.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - // Get component list - const componentsResult = await callKicadScript("get_component_list", {}); - if (!componentsResult.success) { - logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to generate board statistics", - details: componentsResult.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - // Get nets list - const netsResult = await callKicadScript("get_nets_list", {}); - if (!netsResult.success) { - logger.error(`Failed to retrieve nets list: ${netsResult.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to generate board statistics", - details: netsResult.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - // Combine all information into statistics - const statistics = { - board: { - size: boardResult.size, - layers: boardResult.layers?.length || 0, - title: boardResult.title - }, - components: { - count: componentsResult.components?.length || 0, - types: countComponentTypes(componentsResult.components || []) - }, - nets: { - count: netsResult.nets?.length || 0 - } - }; - - logger.debug('Successfully generated board statistics'); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(statistics), - mimeType: "application/json" - }] - }; - } - ); - - logger.info('Board resources registered'); -} - -/** - * Helper function to count component types - */ -function countComponentTypes(components: any[]): Record { - const typeCounts: Record = {}; - - for (const component of components) { - const type = component.value?.split(' ')[0] || 'Unknown'; - typeCounts[type] = (typeCounts[type] || 0) + 1; - } - - return typeCounts; -} +/** + * Board resources for KiCAD MCP server + * + * These resources provide information about the PCB board + * to the LLM, enabling better context-aware assistance. + */ + +import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; +import { createJsonResponse, createBinaryResponse } from "../utils/resource-helpers.js"; + +// Command function type for KiCAD script calls +type CommandFunction = (command: string, params: Record) => Promise; + +/** + * Register board resources with the MCP server + * + * @param server MCP server instance + * @param callKicadScript Function to call KiCAD script commands + */ +export function registerBoardResources(server: McpServer, callKicadScript: CommandFunction): void { + logger.info("Registering board resources"); + + // ------------------------------------------------------ + // Board Information Resource + // ------------------------------------------------------ + server.resource("board_info", "kicad://board/info", async (uri) => { + logger.debug("Retrieving board information"); + const result = await callKicadScript("get_board_info", {}); + + if (!result.success) { + logger.error(`Failed to retrieve board information: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve board information", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug("Successfully retrieved board information"); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); + + // ------------------------------------------------------ + // Layer List Resource + // ------------------------------------------------------ + server.resource("layer_list", "kicad://board/layers", async (uri) => { + logger.debug("Retrieving layer list"); + const result = await callKicadScript("get_layer_list", {}); + + if (!result.success) { + logger.error(`Failed to retrieve layer list: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve layer list", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug(`Successfully retrieved ${result.layers?.length || 0} layers`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); + + // ------------------------------------------------------ + // Board Extents Resource + // ------------------------------------------------------ + server.resource( + "board_extents", + new ResourceTemplate("kicad://board/extents/{unit?}", { + list: async () => ({ + resources: [ + { uri: "kicad://board/extents/mm", name: "Millimeters" }, + { uri: "kicad://board/extents/inch", name: "Inches" }, + ], + }), + }), + async (uri, params) => { + const unit = params.unit || "mm"; + + logger.debug(`Retrieving board extents in ${unit}`); + const result = await callKicadScript("get_board_extents", { unit }); + + if (!result.success) { + logger.error(`Failed to retrieve board extents: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve board extents", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug("Successfully retrieved board extents"); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Board 2D View Resource + // ------------------------------------------------------ + server.resource( + "board_2d_view", + new ResourceTemplate("kicad://board/2d-view/{format?}", { + list: async () => ({ + resources: [ + { uri: "kicad://board/2d-view/png", name: "PNG Format" }, + { uri: "kicad://board/2d-view/jpg", name: "JPEG Format" }, + { uri: "kicad://board/2d-view/svg", name: "SVG Format" }, + ], + }), + }), + async (uri, params) => { + const format = (params.format || "png") as "png" | "jpg" | "svg"; + const width = params.width ? parseInt(params.width as string) : undefined; + const height = params.height ? parseInt(params.height as string) : undefined; + // Handle layers parameter - could be string or array + const layers = typeof params.layers === "string" ? params.layers.split(",") : params.layers; + + logger.debug("Retrieving 2D board view"); + const result = await callKicadScript("get_board_2d_view", { + layers, + width, + height, + format, + }); + + if (!result.success) { + logger.error(`Failed to retrieve 2D board view: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve 2D board view", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug("Successfully retrieved 2D board view"); + + if (format === "svg") { + return { + contents: [ + { + uri: uri.href, + text: result.imageData, + mimeType: "image/svg+xml", + }, + ], + }; + } else { + return { + contents: [ + { + uri: uri.href, + blob: result.imageData, + mimeType: format === "jpg" ? "image/jpeg" : "image/png", + }, + ], + }; + } + }, + ); + + // ------------------------------------------------------ + // Board 3D View Resource + // ------------------------------------------------------ + server.resource( + "board_3d_view", + new ResourceTemplate("kicad://board/3d-view/{angle?}", { + list: async () => ({ + resources: [ + { uri: "kicad://board/3d-view/isometric", name: "Isometric View" }, + { uri: "kicad://board/3d-view/top", name: "Top View" }, + { uri: "kicad://board/3d-view/bottom", name: "Bottom View" }, + ], + }), + }), + async (uri, params) => { + const angle = params.angle || "isometric"; + const width = params.width ? parseInt(params.width as string) : undefined; + const height = params.height ? parseInt(params.height as string) : undefined; + + logger.debug(`Retrieving 3D board view from ${angle} angle`); + const result = await callKicadScript("get_board_3d_view", { + width, + height, + angle, + }); + + if (!result.success) { + logger.error(`Failed to retrieve 3D board view: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve 3D board view", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug("Successfully retrieved 3D board view"); + return { + contents: [ + { + uri: uri.href, + blob: result.imageData, + mimeType: "image/png", + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Board Statistics Resource + // ------------------------------------------------------ + server.resource("board_statistics", "kicad://board/statistics", async (uri) => { + logger.debug("Generating board statistics"); + + // Get board info + const boardResult = await callKicadScript("get_board_info", {}); + if (!boardResult.success) { + logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to generate board statistics", + details: boardResult.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + // Get component list + const componentsResult = await callKicadScript("get_component_list", {}); + if (!componentsResult.success) { + logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to generate board statistics", + details: componentsResult.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + // Get nets list + const netsResult = await callKicadScript("get_nets_list", {}); + if (!netsResult.success) { + logger.error(`Failed to retrieve nets list: ${netsResult.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to generate board statistics", + details: netsResult.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + // Combine all information into statistics + const statistics = { + board: { + size: boardResult.size, + layers: boardResult.layers?.length || 0, + title: boardResult.title, + }, + components: { + count: componentsResult.components?.length || 0, + types: countComponentTypes(componentsResult.components || []), + }, + nets: { + count: netsResult.nets?.length || 0, + }, + }; + + logger.debug("Successfully generated board statistics"); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(statistics), + mimeType: "application/json", + }, + ], + }; + }); + + logger.info("Board resources registered"); +} + +/** + * Helper function to count component types + */ +function countComponentTypes(components: any[]): Record { + const typeCounts: Record = {}; + + for (const component of components) { + const type = component.value?.split(" ")[0] || "Unknown"; + typeCounts[type] = (typeCounts[type] || 0) + 1; + } + + return typeCounts; +} diff --git a/src/resources/component.ts b/src/resources/component.ts index 947c4a1..05432e1 100644 --- a/src/resources/component.ts +++ b/src/resources/component.ts @@ -5,8 +5,8 @@ * to the LLM, enabling better context-aware assistance. */ -import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { logger } from '../logger.js'; +import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { logger } from "../logger.js"; // Command function type for KiCAD script calls type CommandFunction = (command: string, params: Record) => Promise; @@ -17,43 +17,46 @@ type CommandFunction = (command: string, params: Record) => Pro * @param server MCP server instance * @param callKicadScript Function to call KiCAD script commands */ -export function registerComponentResources(server: McpServer, callKicadScript: CommandFunction): void { - logger.info('Registering component resources'); +export function registerComponentResources( + server: McpServer, + callKicadScript: CommandFunction, +): void { + logger.info("Registering component resources"); // ------------------------------------------------------ // Component List Resource // ------------------------------------------------------ - server.resource( - "component_list", - "kicad://components", - async (uri) => { - logger.debug('Retrieving component list'); - const result = await callKicadScript("get_component_list", {}); + server.resource("component_list", "kicad://components", async (uri) => { + logger.debug("Retrieving component list"); + const result = await callKicadScript("get_component_list", {}); - if (!result.success) { - logger.error(`Failed to retrieve component list: ${result.errorDetails}`); - return { - contents: [{ + if (!result.success) { + logger.error(`Failed to retrieve component list: ${result.errorDetails}`); + return { + contents: [ + { uri: uri.href, text: JSON.stringify({ error: "Failed to retrieve component list", - details: result.errorDetails + details: result.errorDetails, }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved ${result.components?.length || 0} components`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] + mimeType: "application/json", + }, + ], }; } - ); + + logger.debug(`Successfully retrieved ${result.components?.length || 0} components`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); // ------------------------------------------------------ // Component Details Resource @@ -61,38 +64,42 @@ export function registerComponentResources(server: McpServer, callKicadScript: C server.resource( "component_details", new ResourceTemplate("kicad://component/{reference}/details", { - list: undefined + list: undefined, }), async (uri, params) => { const { reference } = params; logger.debug(`Retrieving details for component: ${reference}`); const result = await callKicadScript("get_component_properties", { - reference + reference, }); if (!result.success) { logger.error(`Failed to retrieve component details: ${result.errorDetails}`); return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: `Failed to retrieve details for component ${reference}`, - details: result.errorDetails - }), - mimeType: "application/json" - }] + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: `Failed to retrieve details for component ${reference}`, + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], }; } logger.debug(`Successfully retrieved details for component: ${reference}`); return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], }; - } + }, ); // ------------------------------------------------------ @@ -101,109 +108,113 @@ export function registerComponentResources(server: McpServer, callKicadScript: C server.resource( "component_connections", new ResourceTemplate("kicad://component/{reference}/connections", { - list: undefined + list: undefined, }), async (uri, params) => { const { reference } = params; logger.debug(`Retrieving connections for component: ${reference}`); const result = await callKicadScript("get_component_connections", { - reference + reference, }); if (!result.success) { logger.error(`Failed to retrieve component connections: ${result.errorDetails}`); return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: `Failed to retrieve connections for component ${reference}`, - details: result.errorDetails - }), - mimeType: "application/json" - }] + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: `Failed to retrieve connections for component ${reference}`, + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], }; } logger.debug(`Successfully retrieved connections for component: ${reference}`); return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], }; - } + }, ); // ------------------------------------------------------ // Component Placement Resource // ------------------------------------------------------ - server.resource( - "component_placement", - "kicad://components/placement", - async (uri) => { - logger.debug('Retrieving component placement information'); - const result = await callKicadScript("get_component_placement", {}); + server.resource("component_placement", "kicad://components/placement", async (uri) => { + logger.debug("Retrieving component placement information"); + const result = await callKicadScript("get_component_placement", {}); - if (!result.success) { - logger.error(`Failed to retrieve component placement: ${result.errorDetails}`); - return { - contents: [{ + if (!result.success) { + logger.error(`Failed to retrieve component placement: ${result.errorDetails}`); + return { + contents: [ + { uri: uri.href, text: JSON.stringify({ error: "Failed to retrieve component placement information", - details: result.errorDetails + details: result.errorDetails, }), - mimeType: "application/json" - }] - }; - } - - logger.debug('Successfully retrieved component placement information'); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] + mimeType: "application/json", + }, + ], }; } - ); + + logger.debug("Successfully retrieved component placement information"); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); // ------------------------------------------------------ // Component Groups Resource // ------------------------------------------------------ - server.resource( - "component_groups", - "kicad://components/groups", - async (uri) => { - logger.debug('Retrieving component groups'); - const result = await callKicadScript("get_component_groups", {}); + server.resource("component_groups", "kicad://components/groups", async (uri) => { + logger.debug("Retrieving component groups"); + const result = await callKicadScript("get_component_groups", {}); - if (!result.success) { - logger.error(`Failed to retrieve component groups: ${result.errorDetails}`); - return { - contents: [{ + if (!result.success) { + logger.error(`Failed to retrieve component groups: ${result.errorDetails}`); + return { + contents: [ + { uri: uri.href, text: JSON.stringify({ error: "Failed to retrieve component groups", - details: result.errorDetails + details: result.errorDetails, }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved ${result.groups?.length || 0} component groups`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] + mimeType: "application/json", + }, + ], }; } - ); + + logger.debug(`Successfully retrieved ${result.groups?.length || 0} component groups`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); // ------------------------------------------------------ // Component Visualization Resource @@ -211,39 +222,43 @@ export function registerComponentResources(server: McpServer, callKicadScript: C server.resource( "component_visualization", new ResourceTemplate("kicad://component/{reference}/visualization", { - list: undefined + list: undefined, }), async (uri, params) => { const { reference } = params; logger.debug(`Generating visualization for component: ${reference}`); const result = await callKicadScript("get_component_visualization", { - reference + reference, }); if (!result.success) { logger.error(`Failed to generate component visualization: ${result.errorDetails}`); return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: `Failed to generate visualization for component ${reference}`, - details: result.errorDetails - }), - mimeType: "application/json" - }] + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: `Failed to generate visualization for component ${reference}`, + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], }; } logger.debug(`Successfully generated visualization for component: ${reference}`); return { - contents: [{ - uri: uri.href, - blob: result.imageData, // Base64 encoded image data - mimeType: "image/png" - }] + contents: [ + { + uri: uri.href, + blob: result.imageData, // Base64 encoded image data + mimeType: "image/png", + }, + ], }; - } + }, ); - logger.info('Component resources registered'); + logger.info("Component resources registered"); } diff --git a/src/resources/index.ts b/src/resources/index.ts index c025fc3..db94cff 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,10 +1,10 @@ -/** - * Resources index for KiCAD MCP server - * - * Exports all resource registration functions - */ - -export { registerProjectResources } from './project.js'; -export { registerBoardResources } from './board.js'; -export { registerComponentResources } from './component.js'; -export { registerLibraryResources } from './library.js'; +/** + * Resources index for KiCAD MCP server + * + * Exports all resource registration functions + */ + +export { registerProjectResources } from "./project.js"; +export { registerBoardResources } from "./board.js"; +export { registerComponentResources } from "./component.js"; +export { registerLibraryResources } from "./library.js"; diff --git a/src/resources/library.ts b/src/resources/library.ts index 1b7acde..7e23dd9 100644 --- a/src/resources/library.ts +++ b/src/resources/library.ts @@ -1,290 +1,323 @@ -/** - * Library resources for KiCAD MCP server - * - * These resources provide information about KiCAD component libraries - * to the LLM, enabling better context-aware assistance. - */ - -import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; - -// Command function type for KiCAD script calls -type CommandFunction = (command: string, params: Record) => Promise; - -/** - * Register library resources with the MCP server - * - * @param server MCP server instance - * @param callKicadScript Function to call KiCAD script commands - */ -export function registerLibraryResources(server: McpServer, callKicadScript: CommandFunction): void { - logger.info('Registering library resources'); - - // ------------------------------------------------------ - // Component Library Resource - // ------------------------------------------------------ - server.resource( - "component_library", - new ResourceTemplate("kicad://components/{filter?}/{library?}", { - list: async () => ({ - resources: [ - { uri: "kicad://components", name: "All Components" } - ] - }) - }), - async (uri, params) => { - const filter = params.filter || ''; - const library = params.library || ''; - const limit = Number(params.limit) || undefined; - - logger.debug(`Retrieving component library${filter ? ` with filter: ${filter}` : ''}${library ? ` from library: ${library}` : ''}`); - - const result = await callKicadScript("get_component_library", { - filter, - library, - limit - }); - - if (!result.success) { - logger.error(`Failed to retrieve component library: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve component library", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved ${result.components?.length || 0} components from library`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Library List Resource - // ------------------------------------------------------ - server.resource( - "library_list", - "kicad://libraries", - async (uri) => { - logger.debug('Retrieving library list'); - const result = await callKicadScript("get_library_list", {}); - - if (!result.success) { - logger.error(`Failed to retrieve library list: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve library list", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved ${result.libraries?.length || 0} libraries`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Library Component Details Resource - // ------------------------------------------------------ - server.resource( - "library_component_details", - new ResourceTemplate("kicad://library/component/{componentId}/{library?}", { - list: undefined - }), - async (uri, params) => { - const { componentId, library } = params; - logger.debug(`Retrieving details for component: ${componentId}${library ? ` from library: ${library}` : ''}`); - - const result = await callKicadScript("get_component_details", { - componentId, - library - }); - - if (!result.success) { - logger.error(`Failed to retrieve component details: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: `Failed to retrieve details for component ${componentId}`, - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved details for component: ${componentId}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Component Footprint Resource - // ------------------------------------------------------ - server.resource( - "component_footprint", - new ResourceTemplate("kicad://footprint/{componentId}/{footprint?}", { - list: undefined - }), - async (uri, params) => { - const { componentId, footprint } = params; - logger.debug(`Retrieving footprint for component: ${componentId}${footprint ? ` (${footprint})` : ''}`); - - const result = await callKicadScript("get_component_footprint", { - componentId, - footprint - }); - - if (!result.success) { - logger.error(`Failed to retrieve component footprint: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: `Failed to retrieve footprint for component ${componentId}`, - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved footprint for component: ${componentId}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Component Symbol Resource - // ------------------------------------------------------ - server.resource( - "component_symbol", - new ResourceTemplate("kicad://symbol/{componentId}", { - list: undefined - }), - async (uri, params) => { - const { componentId } = params; - logger.debug(`Retrieving symbol for component: ${componentId}`); - - const result = await callKicadScript("get_component_symbol", { - componentId - }); - - if (!result.success) { - logger.error(`Failed to retrieve component symbol: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: `Failed to retrieve symbol for component ${componentId}`, - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved symbol for component: ${componentId}`); - - // If the result includes SVG data, return it as SVG - if (result.svgData) { - return { - contents: [{ - uri: uri.href, - text: result.svgData, - mimeType: "image/svg+xml" - }] - }; - } - - // Otherwise return the JSON result - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Component 3D Model Resource - // ------------------------------------------------------ - server.resource( - "component_3d_model", - new ResourceTemplate("kicad://3d-model/{componentId}/{footprint?}", { - list: undefined - }), - async (uri, params) => { - const { componentId, footprint } = params; - logger.debug(`Retrieving 3D model for component: ${componentId}${footprint ? ` (${footprint})` : ''}`); - - const result = await callKicadScript("get_component_3d_model", { - componentId, - footprint - }); - - if (!result.success) { - logger.error(`Failed to retrieve component 3D model: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: `Failed to retrieve 3D model for component ${componentId}`, - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved 3D model for component: ${componentId}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - logger.info('Library resources registered'); -} +/** + * Library resources for KiCAD MCP server + * + * These resources provide information about KiCAD component libraries + * to the LLM, enabling better context-aware assistance. + */ + +import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; + +// Command function type for KiCAD script calls +type CommandFunction = (command: string, params: Record) => Promise; + +/** + * Register library resources with the MCP server + * + * @param server MCP server instance + * @param callKicadScript Function to call KiCAD script commands + */ +export function registerLibraryResources( + server: McpServer, + callKicadScript: CommandFunction, +): void { + logger.info("Registering library resources"); + + // ------------------------------------------------------ + // Component Library Resource + // ------------------------------------------------------ + server.resource( + "component_library", + new ResourceTemplate("kicad://components/{filter?}/{library?}", { + list: async () => ({ + resources: [{ uri: "kicad://components", name: "All Components" }], + }), + }), + async (uri, params) => { + const filter = params.filter || ""; + const library = params.library || ""; + const limit = Number(params.limit) || undefined; + + logger.debug( + `Retrieving component library${filter ? ` with filter: ${filter}` : ""}${library ? ` from library: ${library}` : ""}`, + ); + + const result = await callKicadScript("get_component_library", { + filter, + library, + limit, + }); + + if (!result.success) { + logger.error(`Failed to retrieve component library: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve component library", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug( + `Successfully retrieved ${result.components?.length || 0} components from library`, + ); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Library List Resource + // ------------------------------------------------------ + server.resource("library_list", "kicad://libraries", async (uri) => { + logger.debug("Retrieving library list"); + const result = await callKicadScript("get_library_list", {}); + + if (!result.success) { + logger.error(`Failed to retrieve library list: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve library list", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug(`Successfully retrieved ${result.libraries?.length || 0} libraries`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); + + // ------------------------------------------------------ + // Library Component Details Resource + // ------------------------------------------------------ + server.resource( + "library_component_details", + new ResourceTemplate("kicad://library/component/{componentId}/{library?}", { + list: undefined, + }), + async (uri, params) => { + const { componentId, library } = params; + logger.debug( + `Retrieving details for component: ${componentId}${library ? ` from library: ${library}` : ""}`, + ); + + const result = await callKicadScript("get_component_details", { + componentId, + library, + }); + + if (!result.success) { + logger.error(`Failed to retrieve component details: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: `Failed to retrieve details for component ${componentId}`, + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug(`Successfully retrieved details for component: ${componentId}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Component Footprint Resource + // ------------------------------------------------------ + server.resource( + "component_footprint", + new ResourceTemplate("kicad://footprint/{componentId}/{footprint?}", { + list: undefined, + }), + async (uri, params) => { + const { componentId, footprint } = params; + logger.debug( + `Retrieving footprint for component: ${componentId}${footprint ? ` (${footprint})` : ""}`, + ); + + const result = await callKicadScript("get_component_footprint", { + componentId, + footprint, + }); + + if (!result.success) { + logger.error(`Failed to retrieve component footprint: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: `Failed to retrieve footprint for component ${componentId}`, + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug(`Successfully retrieved footprint for component: ${componentId}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Component Symbol Resource + // ------------------------------------------------------ + server.resource( + "component_symbol", + new ResourceTemplate("kicad://symbol/{componentId}", { + list: undefined, + }), + async (uri, params) => { + const { componentId } = params; + logger.debug(`Retrieving symbol for component: ${componentId}`); + + const result = await callKicadScript("get_component_symbol", { + componentId, + }); + + if (!result.success) { + logger.error(`Failed to retrieve component symbol: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: `Failed to retrieve symbol for component ${componentId}`, + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug(`Successfully retrieved symbol for component: ${componentId}`); + + // If the result includes SVG data, return it as SVG + if (result.svgData) { + return { + contents: [ + { + uri: uri.href, + text: result.svgData, + mimeType: "image/svg+xml", + }, + ], + }; + } + + // Otherwise return the JSON result + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Component 3D Model Resource + // ------------------------------------------------------ + server.resource( + "component_3d_model", + new ResourceTemplate("kicad://3d-model/{componentId}/{footprint?}", { + list: undefined, + }), + async (uri, params) => { + const { componentId, footprint } = params; + logger.debug( + `Retrieving 3D model for component: ${componentId}${footprint ? ` (${footprint})` : ""}`, + ); + + const result = await callKicadScript("get_component_3d_model", { + componentId, + footprint, + }); + + if (!result.success) { + logger.error(`Failed to retrieve component 3D model: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: `Failed to retrieve 3D model for component ${componentId}`, + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug(`Successfully retrieved 3D model for component: ${componentId}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }, + ); + + logger.info("Library resources registered"); +} diff --git a/src/resources/project.ts b/src/resources/project.ts index e2226ce..db3c3d2 100644 --- a/src/resources/project.ts +++ b/src/resources/project.ts @@ -1,260 +1,267 @@ -/** - * Project resources for KiCAD MCP server - * - * These resources provide information about the KiCAD project - * to the LLM, enabling better context-aware assistance. - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { logger } from '../logger.js'; - -// Command function type for KiCAD script calls -type CommandFunction = (command: string, params: Record) => Promise; - -/** - * Register project resources with the MCP server - * - * @param server MCP server instance - * @param callKicadScript Function to call KiCAD script commands - */ -export function registerProjectResources(server: McpServer, callKicadScript: CommandFunction): void { - logger.info('Registering project resources'); - - // ------------------------------------------------------ - // Project Information Resource - // ------------------------------------------------------ - server.resource( - "project_info", - "kicad://project/info", - async (uri) => { - logger.debug('Retrieving project information'); - const result = await callKicadScript("get_project_info", {}); - - if (!result.success) { - logger.error(`Failed to retrieve project information: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve project information", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug('Successfully retrieved project information'); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Project Properties Resource - // ------------------------------------------------------ - server.resource( - "project_properties", - "kicad://project/properties", - async (uri) => { - logger.debug('Retrieving project properties'); - const result = await callKicadScript("get_project_properties", {}); - - if (!result.success) { - logger.error(`Failed to retrieve project properties: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve project properties", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug('Successfully retrieved project properties'); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Project Files Resource - // ------------------------------------------------------ - server.resource( - "project_files", - "kicad://project/files", - async (uri) => { - logger.debug('Retrieving project files'); - const result = await callKicadScript("get_project_files", {}); - - if (!result.success) { - logger.error(`Failed to retrieve project files: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve project files", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug(`Successfully retrieved ${result.files?.length || 0} project files`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Project Status Resource - // ------------------------------------------------------ - server.resource( - "project_status", - "kicad://project/status", - async (uri) => { - logger.debug('Retrieving project status'); - const result = await callKicadScript("get_project_status", {}); - - if (!result.success) { - logger.error(`Failed to retrieve project status: ${result.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to retrieve project status", - details: result.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - logger.debug('Successfully retrieved project status'); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(result), - mimeType: "application/json" - }] - }; - } - ); - - // ------------------------------------------------------ - // Project Summary Resource - // ------------------------------------------------------ - server.resource( - "project_summary", - "kicad://project/summary", - async (uri) => { - logger.debug('Generating project summary'); - - // Get project info - const infoResult = await callKicadScript("get_project_info", {}); - if (!infoResult.success) { - logger.error(`Failed to retrieve project information: ${infoResult.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to generate project summary", - details: infoResult.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - // Get board info - const boardResult = await callKicadScript("get_board_info", {}); - if (!boardResult.success) { - logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to generate project summary", - details: boardResult.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - // Get component list - const componentsResult = await callKicadScript("get_component_list", {}); - if (!componentsResult.success) { - logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify({ - error: "Failed to generate project summary", - details: componentsResult.errorDetails - }), - mimeType: "application/json" - }] - }; - } - - // Combine all information into a summary - const summary = { - project: infoResult.project, - board: { - size: boardResult.size, - layers: boardResult.layers?.length || 0, - title: boardResult.title - }, - components: { - count: componentsResult.components?.length || 0, - types: countComponentTypes(componentsResult.components || []) - } - }; - - logger.debug('Successfully generated project summary'); - return { - contents: [{ - uri: uri.href, - text: JSON.stringify(summary), - mimeType: "application/json" - }] - }; - } - ); - - logger.info('Project resources registered'); -} - -/** - * Helper function to count component types - */ -function countComponentTypes(components: any[]): Record { - const typeCounts: Record = {}; - - for (const component of components) { - const type = component.value?.split(' ')[0] || 'Unknown'; - typeCounts[type] = (typeCounts[type] || 0) + 1; - } - - return typeCounts; -} +/** + * Project resources for KiCAD MCP server + * + * These resources provide information about the KiCAD project + * to the LLM, enabling better context-aware assistance. + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { logger } from "../logger.js"; + +// Command function type for KiCAD script calls +type CommandFunction = (command: string, params: Record) => Promise; + +/** + * Register project resources with the MCP server + * + * @param server MCP server instance + * @param callKicadScript Function to call KiCAD script commands + */ +export function registerProjectResources( + server: McpServer, + callKicadScript: CommandFunction, +): void { + logger.info("Registering project resources"); + + // ------------------------------------------------------ + // Project Information Resource + // ------------------------------------------------------ + server.resource("project_info", "kicad://project/info", async (uri) => { + logger.debug("Retrieving project information"); + const result = await callKicadScript("get_project_info", {}); + + if (!result.success) { + logger.error(`Failed to retrieve project information: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve project information", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug("Successfully retrieved project information"); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); + + // ------------------------------------------------------ + // Project Properties Resource + // ------------------------------------------------------ + server.resource("project_properties", "kicad://project/properties", async (uri) => { + logger.debug("Retrieving project properties"); + const result = await callKicadScript("get_project_properties", {}); + + if (!result.success) { + logger.error(`Failed to retrieve project properties: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve project properties", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug("Successfully retrieved project properties"); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); + + // ------------------------------------------------------ + // Project Files Resource + // ------------------------------------------------------ + server.resource("project_files", "kicad://project/files", async (uri) => { + logger.debug("Retrieving project files"); + const result = await callKicadScript("get_project_files", {}); + + if (!result.success) { + logger.error(`Failed to retrieve project files: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve project files", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug(`Successfully retrieved ${result.files?.length || 0} project files`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); + + // ------------------------------------------------------ + // Project Status Resource + // ------------------------------------------------------ + server.resource("project_status", "kicad://project/status", async (uri) => { + logger.debug("Retrieving project status"); + const result = await callKicadScript("get_project_status", {}); + + if (!result.success) { + logger.error(`Failed to retrieve project status: ${result.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to retrieve project status", + details: result.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + logger.debug("Successfully retrieved project status"); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(result), + mimeType: "application/json", + }, + ], + }; + }); + + // ------------------------------------------------------ + // Project Summary Resource + // ------------------------------------------------------ + server.resource("project_summary", "kicad://project/summary", async (uri) => { + logger.debug("Generating project summary"); + + // Get project info + const infoResult = await callKicadScript("get_project_info", {}); + if (!infoResult.success) { + logger.error(`Failed to retrieve project information: ${infoResult.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to generate project summary", + details: infoResult.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + // Get board info + const boardResult = await callKicadScript("get_board_info", {}); + if (!boardResult.success) { + logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to generate project summary", + details: boardResult.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + // Get component list + const componentsResult = await callKicadScript("get_component_list", {}); + if (!componentsResult.success) { + logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify({ + error: "Failed to generate project summary", + details: componentsResult.errorDetails, + }), + mimeType: "application/json", + }, + ], + }; + } + + // Combine all information into a summary + const summary = { + project: infoResult.project, + board: { + size: boardResult.size, + layers: boardResult.layers?.length || 0, + title: boardResult.title, + }, + components: { + count: componentsResult.components?.length || 0, + types: countComponentTypes(componentsResult.components || []), + }, + }; + + logger.debug("Successfully generated project summary"); + return { + contents: [ + { + uri: uri.href, + text: JSON.stringify(summary), + mimeType: "application/json", + }, + ], + }; + }); + + logger.info("Project resources registered"); +} + +/** + * Helper function to count component types + */ +function countComponentTypes(components: any[]): Record { + const typeCounts: Record = {}; + + for (const component of components) { + const type = component.value?.split(" ")[0] || "Unknown"; + typeCounts[type] = (typeCounts[type] || 0) + 1; + } + + return typeCounts; +} diff --git a/src/server.ts b/src/server.ts index 4a24c4f..6abd742 100644 --- a/src/server.ts +++ b/src/server.ts @@ -54,18 +54,8 @@ function findPythonExecutable(scriptPath: string): string { // Check for virtual environment const venvPaths = [ - join( - projectRoot, - "venv", - isWindows ? "Scripts" : "bin", - isWindows ? "python.exe" : "python", - ), - join( - projectRoot, - ".venv", - isWindows ? "Scripts" : "bin", - isWindows ? "python.exe" : "python", - ), + join(projectRoot, "venv", isWindows ? "Scripts" : "bin", isWindows ? "python.exe" : "python"), + join(projectRoot, ".venv", isWindows ? "Scripts" : "bin", isWindows ? "python.exe" : "python"), ]; for (const venvPath of venvPaths) { @@ -77,9 +67,7 @@ function findPythonExecutable(scriptPath: string): string { // Allow override via KICAD_PYTHON environment variable (any platform) if (process.env.KICAD_PYTHON) { - logger.info( - `Using KICAD_PYTHON environment variable: ${process.env.KICAD_PYTHON}`, - ); + logger.info(`Using KICAD_PYTHON environment variable: ${process.env.KICAD_PYTHON}`); return process.env.KICAD_PYTHON; } @@ -123,9 +111,7 @@ function findPythonExecutable(scriptPath: string): string { for (const path of homebrewPaths) { if (existsSync(path)) { - logger.info( - `Found Homebrew Python at: ${path} (ensure pcbnew is importable)`, - ); + logger.info(`Found Homebrew Python at: ${path} (ensure pcbnew is importable)`); return path; } } @@ -196,19 +182,14 @@ export class KiCADMcpServer { * @param kicadScriptPath Path to the Python KiCAD interface script * @param logLevel Log level for the server */ - constructor( - kicadScriptPath: string, - logLevel: "error" | "warn" | "info" | "debug" = "info", - ) { + constructor(kicadScriptPath: string, logLevel: "error" | "warn" | "info" | "debug" = "info") { // Set up the logger logger.setLogLevel(logLevel); // Check if KiCAD script exists this.kicadScriptPath = kicadScriptPath; if (!existsSync(this.kicadScriptPath)) { - throw new Error( - `KiCAD interface script not found: ${this.kicadScriptPath}`, - ); + throw new Error(`KiCAD interface script not found: ${this.kicadScriptPath}`); } // Initialize the MCP server @@ -267,9 +248,7 @@ export class KiCADMcpServer { registerFootprintPrompts(this.server); logger.info("All KiCAD tools, resources, and prompts registered"); - logger.info( - "Router pattern enabled: 4 router tools + direct tools for discovery", - ); + logger.info("Router pattern enabled: 4 router tools + direct tools for discovery"); } /** @@ -277,15 +256,12 @@ export class KiCADMcpServer { */ private async validatePrerequisites(pythonExe: string): Promise { const isWindows = process.platform === "win32"; - const isLinux = - process.platform !== "win32" && process.platform !== "darwin"; + const isLinux = process.platform !== "win32" && process.platform !== "darwin"; const errors: string[] = []; // Check if Python executable exists (for absolute paths) or is executable (for commands) const isAbsolutePath = - pythonExe.startsWith("/") || - pythonExe.startsWith("C:") || - pythonExe.startsWith("\\"); + pythonExe.startsWith("/") || pythonExe.startsWith("C:") || pythonExe.startsWith("\\"); if (isAbsolutePath) { // Absolute path: use existsSync @@ -293,16 +269,10 @@ export class KiCADMcpServer { errors.push(`Python executable not found: ${pythonExe}`); if (isWindows) { - errors.push( - "Windows: Install KiCAD 9.0+ from https://www.kicad.org/download/windows/", - ); - errors.push( - "Or run: .\\setup-windows.ps1 for automatic configuration", - ); + errors.push("Windows: Install KiCAD 9.0+ from https://www.kicad.org/download/windows/"); + errors.push("Or run: .\\setup-windows.ps1 for automatic configuration"); } else if (isLinux) { - errors.push( - "Linux: Install KiCAD 9.0+ or set KICAD_PYTHON environment variable", - ); + errors.push("Linux: Install KiCAD 9.0+ or set KICAD_PYTHON environment variable"); errors.push("Set KICAD_PYTHON to specify a custom Python path"); } } @@ -334,20 +304,14 @@ export class KiCADMcpServer { } catch (error: any) { errors.push(`Python executable not found in PATH: ${pythonExe}`); errors.push(`Error: ${error.message}`); - errors.push( - "Set KICAD_PYTHON environment variable to specify full path", - ); + errors.push("Set KICAD_PYTHON environment variable to specify full path"); if (isLinux) { errors.push(""); errors.push("Linux troubleshooting:"); errors.push("1. Check if python3 is installed: which python3"); - errors.push( - "2. Install KiCAD: sudo apt install kicad (Ubuntu/Debian)", - ); - errors.push( - "3. Set KICAD_PYTHON=/usr/bin/python3 in your MCP config", - ); + errors.push("2. Install KiCAD: sudo apt install kicad (Ubuntu/Debian)"); + 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) - const distPath = join( - dirname(dirname(this.kicadScriptPath)), - "dist", - "index.js", - ); + const distPath = join(dirname(dirname(this.kicadScriptPath)), "dist", "index.js"); if (!existsSync(distPath)) { errors.push("Project not built. Run: npm run build"); } @@ -458,9 +418,7 @@ export class KiCADMcpServer { logger.info("Starting KiCAD MCP server..."); // Start the Python process for KiCAD scripting - logger.info( - `Starting Python process with script: ${this.kicadScriptPath}`, - ); + logger.info(`Starting Python process with script: ${this.kicadScriptPath}`); const pythonExe = findPythonExecutable(this.kicadScriptPath); logger.info(`Using Python executable: ${pythonExe}`); @@ -468,25 +426,20 @@ export class KiCADMcpServer { // Validate prerequisites const isValid = await this.validatePrerequisites(pythonExe); if (!isValid) { - throw new Error( - "Prerequisites validation failed. See logs above for details.", - ); + throw new Error("Prerequisites validation failed. See logs above for details."); } this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], { stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, PYTHONPATH: - process.env.PYTHONPATH || - "C:/Program Files/KiCad/9.0/lib/python3/dist-packages", + process.env.PYTHONPATH || "C:/Program Files/KiCad/9.0/lib/python3/dist-packages", }, }); // Listen for process exit this.pythonProcess.on("exit", (code, signal) => { - logger.warn( - `Python process exited with code ${code} and signal ${signal}`, - ); + logger.warn(`Python process exited with code ${code} and signal ${signal}`); this.pythonProcess = null; }); @@ -563,17 +516,10 @@ export class KiCADMcpServer { // Determine timeout based on command type // DRC and export operations need longer timeouts for large boards let commandTimeout = 30000; // Default 30 seconds - const longRunningCommands = [ - "run_drc", - "export_gerber", - "export_pdf", - "export_3d", - ]; + const longRunningCommands = ["run_drc", "export_gerber", "export_pdf", "export_3d"]; if (longRunningCommands.includes(command)) { commandTimeout = 600000; // 10 minutes for long operations - logger.info( - `Using extended timeout (${commandTimeout / 1000}s) for command: ${command}`, - ); + logger.info(`Using extended timeout (${commandTimeout / 1000}s) for command: ${command}`); } // Add request to queue with timeout info @@ -678,12 +624,8 @@ export class KiCADMcpServer { // Set a timeout (use command-specific timeout or default) const timeoutDuration = request.timeout || 30000; const timeoutHandle = setTimeout(() => { - logger.error( - `Command timeout after ${timeoutDuration / 1000}s: ${request.command}`, - ); - logger.error( - `Buffer contents: ${this.responseBuffer.substring(0, 200)}...`, - ); + logger.error(`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`); + logger.error(`Buffer contents: ${this.responseBuffer.substring(0, 200)}...`); // Clear state this.responseBuffer = ""; @@ -691,11 +633,7 @@ export class KiCADMcpServer { this.processingRequest = false; // Reject the promise - reject( - new Error( - `Command timeout after ${timeoutDuration / 1000}s: ${request.command}`, - ), - ); + reject(new Error(`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`)); // Process next request setTimeout(() => this.processNextRequest(), 0); diff --git a/src/tools/board.ts b/src/tools/board.ts index 975781d..65e6631 100644 --- a/src/tools/board.ts +++ b/src/tools/board.ts @@ -1,384 +1,431 @@ -/** - * Board management tools for KiCAD MCP server - * - * These tools handle board setup, layer management, and board properties - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; - -// Command function type for KiCAD script calls -type CommandFunction = (command: string, params: Record) => Promise; - -/** - * Register board management tools with the MCP server - * - * @param server MCP server instance - * @param callKicadScript Function to call KiCAD script commands - */ -export function registerBoardTools(server: McpServer, callKicadScript: CommandFunction): void { - logger.info('Registering board management tools'); - - // ------------------------------------------------------ - // Set Board Size Tool - // ------------------------------------------------------ - server.tool( - "set_board_size", - { - width: z.number().describe("Board width"), - height: z.number().describe("Board height"), - unit: z.enum(["mm", "inch"]).describe("Unit of measurement") - }, - async ({ width, height, unit }) => { - logger.debug(`Setting board size to ${width}x${height} ${unit}`); - const result = await callKicadScript("set_board_size", { - width, - height, - unit - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Add Layer Tool - // ------------------------------------------------------ - server.tool( - "add_layer", - { - name: z.string().describe("Layer name"), - type: z.enum([ - "copper", "technical", "user", "signal" - ]).describe("Layer type"), - position: z.enum([ - "top", "bottom", "inner" - ]).describe("Layer position"), - number: z.number().optional().describe("Layer number (for inner layers)") - }, - async ({ name, type, position, number }) => { - logger.debug(`Adding ${type} layer: ${name}`); - const result = await callKicadScript("add_layer", { - name, - type, - position, - number - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Set Active Layer Tool - // ------------------------------------------------------ - server.tool( - "set_active_layer", - { - layer: z.string().describe("Layer name to set as active") - }, - async ({ layer }) => { - logger.debug(`Setting active layer to: ${layer}`); - const result = await callKicadScript("set_active_layer", { layer }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Get Board Info Tool - // ------------------------------------------------------ - server.tool( - "get_board_info", - {}, - async () => { - logger.debug('Getting board information'); - const result = await callKicadScript("get_board_info", {}); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Get Layer List Tool - // ------------------------------------------------------ - server.tool( - "get_layer_list", - {}, - async () => { - logger.debug('Getting layer list'); - const result = await callKicadScript("get_layer_list", {}); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Add Board Outline Tool - // ------------------------------------------------------ - server.tool( - "add_board_outline", - { - shape: z.enum(["rectangle", "circle", "polygon", "rounded_rectangle"]).describe("Shape of the outline"), - params: z.object({ - // For rectangle / rounded_rectangle - width: z.number().optional().describe("Width of rectangle"), - height: z.number().optional().describe("Height of rectangle"), - cornerRadius: z.number().optional().describe("Corner radius for rounded_rectangle (mm)"), - // For circle - radius: z.number().optional().describe("Radius of circle"), - // For polygon - points: z.array( - z.object({ - x: z.number().describe("X coordinate"), - y: z.number().describe("Y coordinate") - }) - ).optional().describe("Points of polygon"), - // 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)"), - y: z.number().describe("Y coordinate of top-left corner for rectangles (default: 0)"), - unit: z.enum(["mm", "inch"]).describe("Unit of measurement") - }).describe("Parameters for the outline shape") - }, - async ({ shape, params }) => { - logger.debug(`Adding ${shape} board outline`); - // Pass x/y as-is to Python; outline.py treats them as top-left corner - // and computes the center internally (center = x + width/2, y + height/2). - const result = await callKicadScript("add_board_outline", { - shape, - ...params - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Add Mounting Hole Tool - // ------------------------------------------------------ - server.tool( - "add_mounting_hole", - { - position: z.object({ - x: z.number().describe("X coordinate"), - y: z.number().describe("Y coordinate"), - unit: z.enum(["mm", "inch"]).describe("Unit of measurement") - }).describe("Position of the mounting hole"), - diameter: z.number().describe("Diameter of the hole"), - padDiameter: z.number().optional().describe("Optional diameter of the pad around the hole") - }, - async ({ position, diameter, padDiameter }) => { - logger.debug(`Adding mounting hole at (${position.x},${position.y}) ${position.unit}`); - const result = await callKicadScript("add_mounting_hole", { - position, - diameter, - padDiameter - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Add Text Tool - // ------------------------------------------------------ - server.tool( - "add_board_text", - { - text: z.string().describe("Text content"), - position: z.object({ - x: z.number().describe("X coordinate"), - y: z.number().describe("Y coordinate"), - unit: z.enum(["mm", "inch"]).describe("Unit of measurement") - }).describe("Position of the text"), - layer: z.string().describe("Layer to place the text on"), - size: z.number().describe("Text size"), - thickness: z.number().optional().describe("Line thickness"), - rotation: z.number().optional().describe("Rotation angle in degrees"), - style: z.enum(["normal", "italic", "bold"]).optional().describe("Text style") - }, - async ({ text, position, layer, size, thickness, rotation, style }) => { - logger.debug(`Adding text "${text}" at (${position.x},${position.y}) ${position.unit}`); - const result = await callKicadScript("add_board_text", { - text, - position, - layer, - size, - thickness, - rotation, - style - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Add Zone Tool - // ------------------------------------------------------ - server.tool( - "add_zone", - { - layer: z.string().describe("Layer for the zone"), - net: z.string().describe("Net name for the zone"), - points: z.array( - z.object({ - x: z.number().describe("X coordinate"), - y: z.number().describe("Y coordinate") - }) - ).describe("Points defining the zone outline"), - unit: z.enum(["mm", "inch"]).describe("Unit of measurement"), - clearance: z.number().optional().describe("Clearance value"), - minWidth: z.number().optional().describe("Minimum width"), - padConnection: z.enum(["thermal", "solid", "none"]).optional().describe("Pad connection type") - }, - async ({ layer, net, points, unit, clearance, minWidth, padConnection }) => { - logger.debug(`Adding zone on layer ${layer} for net ${net}`); - const result = await callKicadScript("add_zone", { - layer, - net, - points, - unit, - clearance, - minWidth, - padConnection - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Get Board Extents Tool - // ------------------------------------------------------ - server.tool( - "get_board_extents", - { - unit: z.enum(["mm", "inch"]).optional().describe("Unit of measurement for the result") - }, - async ({ unit }) => { - logger.debug('Getting board extents'); - const result = await callKicadScript("get_board_extents", { unit }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Get Board 2D View Tool - // ------------------------------------------------------ - server.tool( - "get_board_2d_view", - { - 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"), - height: z.number().optional().describe("Optional height of the image in pixels"), - format: z.enum(["png", "jpg", "svg"]).optional().describe("Image format") - }, - async ({ layers, width, height, format }) => { - logger.debug('Getting 2D board view'); - const result = await callKicadScript("get_board_2d_view", { - layers, - width, - height, - format - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - logger.info('Board management tools registered'); - - // Import SVG logo onto PCB layer (silkscreen) - server.tool( - "import_svg_logo", - "Imports an SVG file as filled graphic polygons onto a KiCAD PCB layer (default F.SilkS / front silkscreen). Curves are linearised automatically. Ideal for placing a company or project logo on the board.", - { - pcbPath: z.string().describe("Path to the .kicad_pcb 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"), - 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)"), - 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)"), - }, - 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); - if (result.success) { - return { - content: [{ - type: "text", - text: [ - result.message, - `Polygons: ${result.polygon_count}`, - `Size: ${result.logo_width_mm?.toFixed(2)} × ${result.logo_height_mm?.toFixed(2)} mm`, - `Layer: ${result.layer}`, - ].join("\n"), - }], - }; - } else { - return { - content: [{ type: "text", text: `SVG import failed: ${result.message || "Unknown error"}` }], - }; - } - }, - ); -} +/** + * Board management tools for KiCAD MCP server + * + * These tools handle board setup, layer management, and board properties + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; + +// Command function type for KiCAD script calls +type CommandFunction = (command: string, params: Record) => Promise; + +/** + * Register board management tools with the MCP server + * + * @param server MCP server instance + * @param callKicadScript Function to call KiCAD script commands + */ +export function registerBoardTools(server: McpServer, callKicadScript: CommandFunction): void { + logger.info("Registering board management tools"); + + // ------------------------------------------------------ + // Set Board Size Tool + // ------------------------------------------------------ + server.tool( + "set_board_size", + { + width: z.number().describe("Board width"), + height: z.number().describe("Board height"), + unit: z.enum(["mm", "inch"]).describe("Unit of measurement"), + }, + async ({ width, height, unit }) => { + logger.debug(`Setting board size to ${width}x${height} ${unit}`); + const result = await callKicadScript("set_board_size", { + width, + height, + unit, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Add Layer Tool + // ------------------------------------------------------ + server.tool( + "add_layer", + { + name: z.string().describe("Layer name"), + type: z.enum(["copper", "technical", "user", "signal"]).describe("Layer type"), + position: z.enum(["top", "bottom", "inner"]).describe("Layer position"), + number: z.number().optional().describe("Layer number (for inner layers)"), + }, + async ({ name, type, position, number }) => { + logger.debug(`Adding ${type} layer: ${name}`); + const result = await callKicadScript("add_layer", { + name, + type, + position, + number, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Set Active Layer Tool + // ------------------------------------------------------ + server.tool( + "set_active_layer", + { + layer: z.string().describe("Layer name to set as active"), + }, + async ({ layer }) => { + logger.debug(`Setting active layer to: ${layer}`); + const result = await callKicadScript("set_active_layer", { layer }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Get Board Info Tool + // ------------------------------------------------------ + server.tool("get_board_info", {}, async () => { + logger.debug("Getting board information"); + const result = await callKicadScript("get_board_info", {}); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }); + + // ------------------------------------------------------ + // Get Layer List Tool + // ------------------------------------------------------ + server.tool("get_layer_list", {}, async () => { + logger.debug("Getting layer list"); + const result = await callKicadScript("get_layer_list", {}); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }); + + // ------------------------------------------------------ + // Add Board Outline Tool + // ------------------------------------------------------ + server.tool( + "add_board_outline", + { + shape: z + .enum(["rectangle", "circle", "polygon", "rounded_rectangle"]) + .describe("Shape of the outline"), + params: z + .object({ + // For rectangle / rounded_rectangle + width: z.number().optional().describe("Width of rectangle"), + height: z.number().optional().describe("Height of rectangle"), + cornerRadius: z.number().optional().describe("Corner radius for rounded_rectangle (mm)"), + // For circle + radius: z.number().optional().describe("Radius of circle"), + // For polygon + points: z + .array( + z.object({ + x: z.number().describe("X coordinate"), + y: z.number().describe("Y coordinate"), + }), + ) + .optional() + .describe("Points of polygon"), + // 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)"), + y: z.number().describe("Y coordinate of top-left corner for rectangles (default: 0)"), + unit: z.enum(["mm", "inch"]).describe("Unit of measurement"), + }) + .describe("Parameters for the outline shape"), + }, + async ({ shape, params }) => { + logger.debug(`Adding ${shape} board outline`); + // Pass x/y as-is to Python; outline.py treats them as top-left corner + // and computes the center internally (center = x + width/2, y + height/2). + const result = await callKicadScript("add_board_outline", { + shape, + ...params, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Add Mounting Hole Tool + // ------------------------------------------------------ + server.tool( + "add_mounting_hole", + { + position: z + .object({ + x: z.number().describe("X coordinate"), + y: z.number().describe("Y coordinate"), + unit: z.enum(["mm", "inch"]).describe("Unit of measurement"), + }) + .describe("Position of the mounting hole"), + diameter: z.number().describe("Diameter of the hole"), + padDiameter: z.number().optional().describe("Optional diameter of the pad around the hole"), + }, + async ({ position, diameter, padDiameter }) => { + logger.debug(`Adding mounting hole at (${position.x},${position.y}) ${position.unit}`); + const result = await callKicadScript("add_mounting_hole", { + position, + diameter, + padDiameter, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Add Text Tool + // ------------------------------------------------------ + server.tool( + "add_board_text", + { + text: z.string().describe("Text content"), + position: z + .object({ + x: z.number().describe("X coordinate"), + y: z.number().describe("Y coordinate"), + unit: z.enum(["mm", "inch"]).describe("Unit of measurement"), + }) + .describe("Position of the text"), + layer: z.string().describe("Layer to place the text on"), + size: z.number().describe("Text size"), + thickness: z.number().optional().describe("Line thickness"), + rotation: z.number().optional().describe("Rotation angle in degrees"), + style: z.enum(["normal", "italic", "bold"]).optional().describe("Text style"), + }, + async ({ text, position, layer, size, thickness, rotation, style }) => { + logger.debug(`Adding text "${text}" at (${position.x},${position.y}) ${position.unit}`); + const result = await callKicadScript("add_board_text", { + text, + position, + layer, + size, + thickness, + rotation, + style, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Add Zone Tool + // ------------------------------------------------------ + server.tool( + "add_zone", + { + layer: z.string().describe("Layer for the zone"), + net: z.string().describe("Net name for the zone"), + points: z + .array( + z.object({ + x: z.number().describe("X coordinate"), + y: z.number().describe("Y coordinate"), + }), + ) + .describe("Points defining the zone outline"), + unit: z.enum(["mm", "inch"]).describe("Unit of measurement"), + clearance: z.number().optional().describe("Clearance value"), + minWidth: z.number().optional().describe("Minimum width"), + padConnection: z + .enum(["thermal", "solid", "none"]) + .optional() + .describe("Pad connection type"), + }, + async ({ layer, net, points, unit, clearance, minWidth, padConnection }) => { + logger.debug(`Adding zone on layer ${layer} for net ${net}`); + const result = await callKicadScript("add_zone", { + layer, + net, + points, + unit, + clearance, + minWidth, + padConnection, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Get Board Extents Tool + // ------------------------------------------------------ + server.tool( + "get_board_extents", + { + unit: z.enum(["mm", "inch"]).optional().describe("Unit of measurement for the result"), + }, + async ({ unit }) => { + logger.debug("Getting board extents"); + const result = await callKicadScript("get_board_extents", { unit }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Get Board 2D View Tool + // ------------------------------------------------------ + server.tool( + "get_board_2d_view", + { + 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"), + height: z.number().optional().describe("Optional height of the image in pixels"), + format: z.enum(["png", "jpg", "svg"]).optional().describe("Image format"), + }, + async ({ layers, width, height, format }) => { + logger.debug("Getting 2D board view"); + const result = await callKicadScript("get_board_2d_view", { + layers, + width, + height, + format, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + logger.info("Board management tools registered"); + + // Import SVG logo onto PCB layer (silkscreen) + server.tool( + "import_svg_logo", + "Imports an SVG file as filled graphic polygons onto a KiCAD PCB layer (default F.SilkS / front silkscreen). Curves are linearised automatically. Ideal for placing a company or project logo on the board.", + { + pcbPath: z.string().describe("Path to the .kicad_pcb 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"), + 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)"), + 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)"), + }, + 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); + if (result.success) { + return { + content: [ + { + type: "text", + text: [ + result.message, + `Polygons: ${result.polygon_count}`, + `Size: ${result.logo_width_mm?.toFixed(2)} × ${result.logo_height_mm?.toFixed(2)} mm`, + `Layer: ${result.layer}`, + ].join("\n"), + }, + ], + }; + } else { + return { + content: [ + { type: "text", text: `SVG import failed: ${result.message || "Unknown error"}` }, + ], + }; + } + }, + ); +} diff --git a/src/tools/component.ts b/src/tools/component.ts index e4da70f..6e7a699 100644 --- a/src/tools/component.ts +++ b/src/tools/component.ts @@ -7,10 +7,7 @@ import { z } from "zod"; import { logger } from "../logger.js"; // Command function type for KiCAD script calls -type CommandFunction = ( - command: string, - params: Record, -) => Promise; +type CommandFunction = (command: string, params: Record) => Promise; /** * Register component management tools with the MCP server @@ -18,10 +15,7 @@ type CommandFunction = ( * @param server MCP server instance * @param callKicadScript Function to call KiCAD script commands */ -export function registerComponentTools( - server: McpServer, - callKicadScript: CommandFunction, -): void { +export function registerComponentTools(server: McpServer, callKicadScript: CommandFunction): void { logger.info("Registering component management tools"); // ------------------------------------------------------ @@ -40,38 +34,19 @@ export function registerComponentTools( unit: z.enum(["mm", "inch"]).describe("Unit of measurement"), }) .describe("Position coordinates and unit"), - reference: z - .string() - .optional() - .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"), + reference: z.string().optional().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"), - layer: z - .string() - .optional() - .describe("Optional layer (e.g., 'F.Cu', 'B.SilkS')"), + layer: z.string().optional().describe("Optional layer (e.g., 'F.Cu', 'B.SilkS')"), boardPath: z .string() .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 ({ - componentId, - position, - reference, - value, - footprint, - rotation, - layer, - boardPath, - }) => { + async ({ componentId, position, reference, value, footprint, rotation, layer, boardPath }) => { logger.debug( `Placing component: ${componentId} at ${position.x},${position.y} ${position.unit}`, ); @@ -103,9 +78,7 @@ export function registerComponentTools( server.tool( "move_component", { - reference: z - .string() - .describe("Reference designator of the component (e.g., 'R5')"), + reference: z.string().describe("Reference designator of the component (e.g., 'R5')"), position: z .object({ x: z.number().describe("X coordinate"), @@ -113,10 +86,7 @@ export function registerComponentTools( unit: z.enum(["mm", "inch"]).describe("Unit of measurement"), }) .describe("New position coordinates and unit"), - rotation: z - .number() - .optional() - .describe("Optional new rotation in degrees"), + rotation: z.number().optional().describe("Optional new rotation in degrees"), layer: z .string() .optional() @@ -150,12 +120,8 @@ export function registerComponentTools( server.tool( "rotate_component", { - reference: z - .string() - .describe("Reference designator of the component (e.g., 'R5')"), - angle: z - .number() - .describe("Rotation angle in degrees (absolute, not relative)"), + reference: z.string().describe("Reference designator of the component (e.g., 'R5')"), + angle: z.number().describe("Rotation angle in degrees (absolute, not relative)"), }, async ({ reference, angle }) => { logger.debug(`Rotating component: ${reference} to ${angle} degrees`); @@ -183,9 +149,7 @@ export function registerComponentTools( { reference: z .string() - .describe( - "Reference designator of the component to delete (e.g., 'R5')", - ), + .describe("Reference designator of the component to delete (e.g., 'R5')"), }, async ({ reference }) => { logger.debug(`Deleting component: ${reference}`); @@ -208,13 +172,8 @@ export function registerComponentTools( server.tool( "edit_component", { - reference: z - .string() - .describe("Reference designator of the component (e.g., 'R5')"), - newReference: z - .string() - .optional() - .describe("Optional new reference designator"), + reference: z.string().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"), footprint: z.string().optional().describe("Optional new footprint"), }, @@ -244,10 +203,7 @@ export function registerComponentTools( server.tool( "find_component", { - reference: z - .string() - .optional() - .describe("Reference designator to search for"), + reference: z.string().optional().describe("Reference designator to search for"), value: z.string().optional().describe("Component value to search for"), }, async ({ reference, value }) => { @@ -276,9 +232,7 @@ export function registerComponentTools( server.tool( "get_component_properties", { - reference: z - .string() - .describe("Reference designator of the component (e.g., 'R5')"), + reference: z.string().describe("Reference designator of the component (e.g., 'R5')"), }, async ({ reference }) => { logger.debug(`Getting properties for component: ${reference}`); @@ -303,9 +257,7 @@ export function registerComponentTools( server.tool( "add_component_annotation", { - reference: z - .string() - .describe("Reference designator of the component (e.g., 'R5')"), + reference: z.string().describe("Reference designator of the component (e.g., 'R5')"), annotation: z.string().describe("Annotation or comment text to add"), visible: z .boolean() @@ -337,15 +289,11 @@ export function registerComponentTools( server.tool( "group_components", { - references: z - .array(z.string()) - .describe("Reference designators of components to group"), + references: z.array(z.string()).describe("Reference designators of components to group"), groupName: z.string().describe("Name for the component group"), }, async ({ references, groupName }) => { - logger.debug( - `Grouping components: ${references.join(", ")} as ${groupName}`, - ); + logger.debug(`Grouping components: ${references.join(", ")} as ${groupName}`); const result = await callKicadScript("group_components", { references, groupName, @@ -368,9 +316,7 @@ export function registerComponentTools( server.tool( "replace_component", { - reference: z - .string() - .describe("Reference designator of the component to replace"), + reference: z.string().describe("Reference designator of the component to replace"), newComponentId: z.string().describe("ID of the new component to use"), newFootprint: z.string().optional().describe("Optional new footprint"), newValue: z.string().optional().describe("Optional new component value"), @@ -401,13 +347,8 @@ export function registerComponentTools( server.tool( "get_component_pads", { - reference: z - .string() - .describe("Reference designator of the component (e.g., 'U1')"), - unit: z - .enum(["mm", "inch"]) - .optional() - .describe("Unit for coordinates (default: mm)"), + reference: z.string().describe("Reference designator of the component (e.g., 'U1')"), + unit: z.enum(["mm", "inch"]).optional().describe("Unit for coordinates (default: mm)"), }, async ({ reference, unit }) => { logger.debug(`Getting pads for component: ${reference}`); @@ -433,10 +374,7 @@ export function registerComponentTools( server.tool( "get_component_list", { - layer: z - .string() - .optional() - .describe("Filter by layer (e.g., 'F.Cu', 'B.Cu')"), + layer: z.string().optional().describe("Filter by layer (e.g., 'F.Cu', 'B.Cu')"), boundingBox: z .object({ x1: z.number(), @@ -447,10 +385,7 @@ export function registerComponentTools( }) .optional() .describe("Filter by bounding box region"), - unit: z - .enum(["mm", "inch"]) - .optional() - .describe("Unit for coordinates (default: mm)"), + unit: z.enum(["mm", "inch"]).optional().describe("Unit for coordinates (default: mm)"), }, async ({ layer, boundingBox, unit }) => { logger.debug("Getting component list"); @@ -477,14 +412,9 @@ export function registerComponentTools( server.tool( "get_pad_position", { - reference: z - .string() - .describe("Component reference designator (e.g., 'U1')"), + reference: z.string().describe("Component reference designator (e.g., 'U1')"), pad: z.string().describe("Pad number or name (e.g., '1', 'A1')"), - unit: z - .enum(["mm", "inch"]) - .optional() - .describe("Unit for coordinates (default: mm)"), + unit: z.enum(["mm", "inch"]).optional().describe("Unit for coordinates (default: mm)"), }, async ({ reference, pad, unit }) => { logger.debug(`Getting pad position for ${reference} pad ${pad}`); @@ -523,10 +453,7 @@ export function registerComponentTools( columns: z.number().describe("Number of columns"), rowSpacing: z.number().describe("Spacing between rows"), columnSpacing: z.number().describe("Spacing between columns"), - startReference: z - .string() - .optional() - .describe("Starting reference (e.g., 'R1')"), + startReference: z.string().optional().describe("Starting reference (e.g., 'R1')"), footprint: z.string().optional().describe("Footprint name"), value: z.string().optional().describe("Component value"), rotation: z.number().optional().describe("Rotation in degrees"), @@ -543,9 +470,7 @@ export function registerComponentTools( value, rotation, }) => { - logger.debug( - `Placing component array: ${rows}x${columns} of ${componentId}`, - ); + logger.debug(`Placing component array: ${rows}x${columns} of ${componentId}`); const result = await callKicadScript("place_component_array", { componentId, startPosition, @@ -576,20 +501,10 @@ export function registerComponentTools( server.tool( "align_components", { - references: z - .array(z.string()) - .describe("Array of component references to align"), - alignmentType: z - .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"), + references: z.array(z.string()).describe("Array of component references to align"), + alignmentType: z.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 }) => { logger.debug(`Aligning components: ${references.join(", ")}`); @@ -626,10 +541,7 @@ export function registerComponentTools( }) .describe("Offset from original position"), newReference: z.string().optional().describe("New reference designator"), - count: z - .number() - .optional() - .describe("Number of duplicates (default: 1)"), + count: z.number().optional().describe("Number of duplicates (default: 1)"), }, async ({ reference, offset, newReference, count }) => { logger.debug(`Duplicating component: ${reference}`); diff --git a/src/tools/datasheet.ts b/src/tools/datasheet.ts index 588b66c..94dffc6 100644 --- a/src/tools/datasheet.ts +++ b/src/tools/datasheet.ts @@ -8,10 +8,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; -export function registerDatasheetTools( - server: McpServer, - callKicadScript: Function, -) { +export function registerDatasheetTools(server: McpServer, callKicadScript: Function) { // ── enrich_datasheets ────────────────────────────────────────────────────── server.tool( "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.`, { - schematic_path: z - .string() - .describe("Path to the .kicad_sch file to enrich"), + schematic_path: z.string().describe("Path to the .kicad_sch file to enrich"), dry_run: z .boolean() .optional() .default(false) - .describe( - "If true, show what would be changed without writing to disk (default: false)", - ), + .describe("If true, show what would be changed without writing to disk (default: false)"), }, async (args: { schematic_path: string; dry_run?: boolean }) => { 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) { - lines.push( - "\nNo changes needed – all LCSC components already have a Datasheet URL.", - ); + lines.push("\nNo changes needed – all LCSC components already have a Datasheet URL."); } return { content: [{ type: "text", text: lines.join("\n") }] }; @@ -96,9 +87,7 @@ Example: get_datasheet_url("C179739") { lcsc: z .string() - .describe( - 'LCSC part number, with or without "C" prefix (e.g. "C179739" or "179739")', - ), + .describe('LCSC part number, with or without "C" prefix (e.g. "C179739" or "179739")'), }, async (args: { lcsc: string }) => { const result = await callKicadScript("get_datasheet_url", { lcsc: args.lcsc }); diff --git a/src/tools/design-rules.ts b/src/tools/design-rules.ts index 2f028d4..9b28cc9 100644 --- a/src/tools/design-rules.ts +++ b/src/tools/design-rules.ts @@ -1,261 +1,314 @@ -/** - * Design rules tools for KiCAD MCP server - * - * These tools handle design rule checking and configuration - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; - -// Command function type for KiCAD script calls -type CommandFunction = (command: string, params: Record) => Promise; - -/** - * Register design rule tools with the MCP server - * - * @param server MCP server instance - * @param callKicadScript Function to call KiCAD script commands - */ -export function registerDesignRuleTools(server: McpServer, callKicadScript: CommandFunction): void { - logger.info('Registering design rule tools'); - - // ------------------------------------------------------ - // Set Design Rules Tool - // ------------------------------------------------------ - server.tool( - "set_design_rules", - { - clearance: z.number().optional().describe("Minimum clearance between copper items (mm)"), - trackWidth: z.number().optional().describe("Default track width (mm)"), - viaDiameter: z.number().optional().describe("Default via diameter (mm)"), - viaDrill: z.number().optional().describe("Default via drill size (mm)"), - microViaDiameter: z.number().optional().describe("Default micro via diameter (mm)"), - microViaDrill: z.number().optional().describe("Default micro via drill size (mm)"), - minTrackWidth: z.number().optional().describe("Minimum track width (mm)"), - minViaDiameter: z.number().optional().describe("Minimum via diameter (mm)"), - minViaDrill: z.number().optional().describe("Minimum via drill size (mm)"), - minMicroViaDiameter: z.number().optional().describe("Minimum micro via diameter (mm)"), - minMicroViaDrill: z.number().optional().describe("Minimum micro via drill size (mm)"), - minHoleDiameter: z.number().optional().describe("Minimum hole diameter (mm)"), - requireCourtyard: z.boolean().optional().describe("Whether to require courtyards for all footprints"), - courtyardClearance: z.number().optional().describe("Minimum clearance between courtyards (mm)") - }, - async (params) => { - logger.debug('Setting design rules'); - const result = await callKicadScript("set_design_rules", params); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Get Design Rules Tool - // ------------------------------------------------------ - server.tool( - "get_design_rules", - {}, - async () => { - logger.debug('Getting design rules'); - const result = await callKicadScript("get_design_rules", {}); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Run DRC Tool - // ------------------------------------------------------ - server.tool( - "run_drc", - { - reportPath: z.string().optional().describe("Optional path to save the DRC report") - }, - async ({ reportPath }) => { - logger.debug('Running DRC check'); - const result = await callKicadScript("run_drc", { reportPath }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Add Net Class Tool - // ------------------------------------------------------ - server.tool( - "add_net_class", - { - name: z.string().describe("Name of the net class"), - description: z.string().optional().describe("Optional description of the net class"), - clearance: z.number().describe("Clearance for this net class (mm)"), - trackWidth: z.number().describe("Track width for this net class (mm)"), - viaDiameter: z.number().describe("Via diameter 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_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_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 }) => { - logger.debug(`Adding net class: ${name}`); - const result = await callKicadScript("add_net_class", { - name, - description, - clearance, - trackWidth, - viaDiameter, - viaDrill, - uvia_diameter, - uvia_drill, - diff_pair_width, - diff_pair_gap, - nets - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Assign Net to Class Tool - // ------------------------------------------------------ - server.tool( - "assign_net_to_class", - { - net: z.string().describe("Name of the net"), - netClass: z.string().describe("Name of the net class") - }, - async ({ net, netClass }) => { - logger.debug(`Assigning net ${net} to class ${netClass}`); - const result = await callKicadScript("assign_net_to_class", { - net, - netClass - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Set Layer Constraints Tool - // ------------------------------------------------------ - server.tool( - "set_layer_constraints", - { - layer: z.string().describe("Layer name (e.g., 'F.Cu')"), - minTrackWidth: z.number().optional().describe("Minimum track width 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)"), - minViaDrill: z.number().optional().describe("Minimum via drill size for this layer (mm)") - }, - async ({ layer, minTrackWidth, minClearance, minViaDiameter, minViaDrill }) => { - logger.debug(`Setting constraints for layer: ${layer}`); - const result = await callKicadScript("set_layer_constraints", { - layer, - minTrackWidth, - minClearance, - minViaDiameter, - minViaDrill - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Check Clearance Tool - // ------------------------------------------------------ - server.tool( - "check_clearance", - { - item1: z.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)"), - reference: z.string().optional().describe("Reference designator (for component)"), - position: z.object({ - x: z.number().optional(), - y: z.number().optional(), - unit: z.enum(["mm", "inch"]).optional() - }).optional().describe("Position to check (if ID not provided)") - }).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)"), - reference: z.string().optional().describe("Reference designator (for component)"), - position: z.object({ - x: z.number().optional(), - y: z.number().optional(), - unit: z.enum(["mm", "inch"]).optional() - }).optional().describe("Position to check (if ID not provided)") - }).describe("Second item to check") - }, - async ({ item1, item2 }) => { - logger.debug(`Checking clearance between ${item1.type} and ${item2.type}`); - const result = await callKicadScript("check_clearance", { - item1, - item2 - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Get DRC Violations Tool - // ------------------------------------------------------ - server.tool( - "get_drc_violations", - { - severity: z.enum(["error", "warning", "all"]).optional().describe("Filter violations by severity") - }, - async ({ severity }) => { - logger.debug('Getting DRC violations'); - const result = await callKicadScript("get_drc_violations", { severity }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - logger.info('Design rule tools registered'); -} +/** + * Design rules tools for KiCAD MCP server + * + * These tools handle design rule checking and configuration + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; + +// Command function type for KiCAD script calls +type CommandFunction = (command: string, params: Record) => Promise; + +/** + * Register design rule tools with the MCP server + * + * @param server MCP server instance + * @param callKicadScript Function to call KiCAD script commands + */ +export function registerDesignRuleTools(server: McpServer, callKicadScript: CommandFunction): void { + logger.info("Registering design rule tools"); + + // ------------------------------------------------------ + // Set Design Rules Tool + // ------------------------------------------------------ + server.tool( + "set_design_rules", + { + clearance: z.number().optional().describe("Minimum clearance between copper items (mm)"), + trackWidth: z.number().optional().describe("Default track width (mm)"), + viaDiameter: z.number().optional().describe("Default via diameter (mm)"), + viaDrill: z.number().optional().describe("Default via drill size (mm)"), + microViaDiameter: z.number().optional().describe("Default micro via diameter (mm)"), + microViaDrill: z.number().optional().describe("Default micro via drill size (mm)"), + minTrackWidth: z.number().optional().describe("Minimum track width (mm)"), + minViaDiameter: z.number().optional().describe("Minimum via diameter (mm)"), + minViaDrill: z.number().optional().describe("Minimum via drill size (mm)"), + minMicroViaDiameter: z.number().optional().describe("Minimum micro via diameter (mm)"), + minMicroViaDrill: z.number().optional().describe("Minimum micro via drill size (mm)"), + minHoleDiameter: z.number().optional().describe("Minimum hole diameter (mm)"), + requireCourtyard: z + .boolean() + .optional() + .describe("Whether to require courtyards for all footprints"), + courtyardClearance: z + .number() + .optional() + .describe("Minimum clearance between courtyards (mm)"), + }, + async (params) => { + logger.debug("Setting design rules"); + const result = await callKicadScript("set_design_rules", params); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Get Design Rules Tool + // ------------------------------------------------------ + server.tool("get_design_rules", {}, async () => { + logger.debug("Getting design rules"); + const result = await callKicadScript("get_design_rules", {}); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }); + + // ------------------------------------------------------ + // Run DRC Tool + // ------------------------------------------------------ + server.tool( + "run_drc", + { + reportPath: z.string().optional().describe("Optional path to save the DRC report"), + }, + async ({ reportPath }) => { + logger.debug("Running DRC check"); + const result = await callKicadScript("run_drc", { reportPath }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Add Net Class Tool + // ------------------------------------------------------ + server.tool( + "add_net_class", + { + name: z.string().describe("Name of the net class"), + description: z.string().optional().describe("Optional description of the net class"), + clearance: z.number().describe("Clearance for this net class (mm)"), + trackWidth: z.number().describe("Track width for this net class (mm)"), + viaDiameter: z.number().describe("Via diameter 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_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_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, + }) => { + logger.debug(`Adding net class: ${name}`); + const result = await callKicadScript("add_net_class", { + name, + description, + clearance, + trackWidth, + viaDiameter, + viaDrill, + uvia_diameter, + uvia_drill, + diff_pair_width, + diff_pair_gap, + nets, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Assign Net to Class Tool + // ------------------------------------------------------ + server.tool( + "assign_net_to_class", + { + net: z.string().describe("Name of the net"), + netClass: z.string().describe("Name of the net class"), + }, + async ({ net, netClass }) => { + logger.debug(`Assigning net ${net} to class ${netClass}`); + const result = await callKicadScript("assign_net_to_class", { + net, + netClass, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Set Layer Constraints Tool + // ------------------------------------------------------ + server.tool( + "set_layer_constraints", + { + layer: z.string().describe("Layer name (e.g., 'F.Cu')"), + minTrackWidth: z.number().optional().describe("Minimum track width 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)"), + minViaDrill: z.number().optional().describe("Minimum via drill size for this layer (mm)"), + }, + async ({ layer, minTrackWidth, minClearance, minViaDiameter, minViaDrill }) => { + logger.debug(`Setting constraints for layer: ${layer}`); + const result = await callKicadScript("set_layer_constraints", { + layer, + minTrackWidth, + minClearance, + minViaDiameter, + minViaDrill, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Check Clearance Tool + // ------------------------------------------------------ + server.tool( + "check_clearance", + { + item1: z + .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)"), + reference: z.string().optional().describe("Reference designator (for component)"), + position: z + .object({ + x: z.number().optional(), + y: z.number().optional(), + unit: z.enum(["mm", "inch"]).optional(), + }) + .optional() + .describe("Position to check (if ID not provided)"), + }) + .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)"), + reference: z.string().optional().describe("Reference designator (for component)"), + position: z + .object({ + x: z.number().optional(), + y: z.number().optional(), + unit: z.enum(["mm", "inch"]).optional(), + }) + .optional() + .describe("Position to check (if ID not provided)"), + }) + .describe("Second item to check"), + }, + async ({ item1, item2 }) => { + logger.debug(`Checking clearance between ${item1.type} and ${item2.type}`); + const result = await callKicadScript("check_clearance", { + item1, + item2, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Get DRC Violations Tool + // ------------------------------------------------------ + server.tool( + "get_drc_violations", + { + severity: z + .enum(["error", "warning", "all"]) + .optional() + .describe("Filter violations by severity"), + }, + async ({ severity }) => { + logger.debug("Getting DRC violations"); + const result = await callKicadScript("get_drc_violations", { severity }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + logger.info("Design rule tools registered"); +} diff --git a/src/tools/export.ts b/src/tools/export.ts index e51beff..0c6f524 100644 --- a/src/tools/export.ts +++ b/src/tools/export.ts @@ -1,260 +1,317 @@ -/** - * Export tools for KiCAD MCP server - * - * These tools handle exporting PCB data to various formats - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; - -// Command function type for KiCAD script calls -type CommandFunction = (command: string, params: Record) => Promise; - -/** - * Register export tools with the MCP server - * - * @param server MCP server instance - * @param callKicadScript Function to call KiCAD script commands - */ -export function registerExportTools(server: McpServer, callKicadScript: CommandFunction): void { - logger.info('Registering export tools'); - - // ------------------------------------------------------ - // Export Gerber Tool - // ------------------------------------------------------ - server.tool( - "export_gerber", - { - 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)"), - useProtelExtensions: z.boolean().optional().describe("Whether to use Protel filename extensions"), - generateDrillFiles: z.boolean().optional().describe("Whether to generate drill files"), - generateMapFile: z.boolean().optional().describe("Whether to generate a map file"), - useAuxOrigin: z.boolean().optional().describe("Whether to use auxiliary axis as origin") - }, - async ({ outputDir, layers, useProtelExtensions, generateDrillFiles, generateMapFile, useAuxOrigin }) => { - logger.debug(`Exporting Gerber files to: ${outputDir}`); - const result = await callKicadScript("export_gerber", { - outputDir, - layers, - useProtelExtensions, - generateDrillFiles, - generateMapFile, - useAuxOrigin - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Export PDF Tool - // ------------------------------------------------------ - server.tool( - "export_pdf", - { - 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)"), - blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"), - 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") - }, - async ({ outputPath, layers, blackAndWhite, frameReference, pageSize }) => { - logger.debug(`Exporting PDF to: ${outputPath}`); - const result = await callKicadScript("export_pdf", { - outputPath, - layers, - blackAndWhite, - frameReference, - pageSize - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Export SVG Tool - // ------------------------------------------------------ - server.tool( - "export_svg", - { - 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)"), - blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"), - includeComponents: z.boolean().optional().describe("Whether to include component outlines") - }, - async ({ outputPath, layers, blackAndWhite, includeComponents }) => { - logger.debug(`Exporting SVG to: ${outputPath}`); - const result = await callKicadScript("export_svg", { - outputPath, - layers, - blackAndWhite, - includeComponents - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Export 3D Model Tool - // ------------------------------------------------------ - server.tool( - "export_3d", - { - outputPath: z.string().describe("Path to save the 3D model file"), - format: z.enum(["STEP", "STL", "VRML", "OBJ"]).describe("3D model format"), - includeComponents: z.boolean().optional().describe("Whether to include 3D component models"), - includeCopper: z.boolean().optional().describe("Whether to include copper layers"), - includeSolderMask: z.boolean().optional().describe("Whether to include solder mask"), - includeSilkscreen: z.boolean().optional().describe("Whether to include silkscreen") - }, - async ({ outputPath, format, includeComponents, includeCopper, includeSolderMask, includeSilkscreen }) => { - logger.debug(`Exporting 3D model to: ${outputPath}`); - const result = await callKicadScript("export_3d", { - outputPath, - format, - includeComponents, - includeCopper, - includeSolderMask, - includeSilkscreen - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Export BOM Tool - // ------------------------------------------------------ - server.tool( - "export_bom", - { - outputPath: z.string().describe("Path to save the BOM file"), - format: z.enum(["CSV", "XML", "HTML", "JSON"]).describe("BOM file format"), - 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") - }, - async ({ outputPath, format, groupByValue, includeAttributes }) => { - logger.debug(`Exporting BOM to: ${outputPath}`); - const result = await callKicadScript("export_bom", { - outputPath, - format, - groupByValue, - includeAttributes - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Export Netlist Tool - // ------------------------------------------------------ - server.tool( - "export_netlist", - { - outputPath: z.string().describe("Path to save the netlist file"), - format: z.enum(["KiCad", "Spice", "Cadstar", "OrcadPCB2"]).optional().describe("Netlist format (default: KiCad)") - }, - async ({ outputPath, format }) => { - logger.debug(`Exporting netlist to: ${outputPath}`); - const result = await callKicadScript("export_netlist", { - outputPath, - format - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Export Position File Tool - // ------------------------------------------------------ - server.tool( - "export_position_file", - { - outputPath: z.string().describe("Path to save the position file"), - format: z.enum(["CSV", "ASCII"]).optional().describe("File format (default: CSV)"), - 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)") - }, - async ({ outputPath, format, units, side }) => { - logger.debug(`Exporting position file to: ${outputPath}`); - const result = await callKicadScript("export_position_file", { - outputPath, - format, - units, - side - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - // ------------------------------------------------------ - // Export VRML Tool - // ------------------------------------------------------ - server.tool( - "export_vrml", - { - outputPath: z.string().describe("Path to save the VRML file"), - includeComponents: z.boolean().optional().describe("Whether to include 3D component models"), - useRelativePaths: z.boolean().optional().describe("Whether to use relative paths for 3D models") - }, - async ({ outputPath, includeComponents, useRelativePaths }) => { - logger.debug(`Exporting VRML to: ${outputPath}`); - const result = await callKicadScript("export_vrml", { - outputPath, - includeComponents, - useRelativePaths - }); - - return { - content: [{ - type: "text", - text: JSON.stringify(result) - }] - }; - } - ); - - logger.info('Export tools registered'); -} +/** + * Export tools for KiCAD MCP server + * + * These tools handle exporting PCB data to various formats + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; + +// Command function type for KiCAD script calls +type CommandFunction = (command: string, params: Record) => Promise; + +/** + * Register export tools with the MCP server + * + * @param server MCP server instance + * @param callKicadScript Function to call KiCAD script commands + */ +export function registerExportTools(server: McpServer, callKicadScript: CommandFunction): void { + logger.info("Registering export tools"); + + // ------------------------------------------------------ + // Export Gerber Tool + // ------------------------------------------------------ + server.tool( + "export_gerber", + { + 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)"), + useProtelExtensions: z + .boolean() + .optional() + .describe("Whether to use Protel filename extensions"), + generateDrillFiles: z.boolean().optional().describe("Whether to generate drill files"), + generateMapFile: z.boolean().optional().describe("Whether to generate a map file"), + useAuxOrigin: z.boolean().optional().describe("Whether to use auxiliary axis as origin"), + }, + async ({ + outputDir, + layers, + useProtelExtensions, + generateDrillFiles, + generateMapFile, + useAuxOrigin, + }) => { + logger.debug(`Exporting Gerber files to: ${outputDir}`); + const result = await callKicadScript("export_gerber", { + outputDir, + layers, + useProtelExtensions, + generateDrillFiles, + generateMapFile, + useAuxOrigin, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Export PDF Tool + // ------------------------------------------------------ + server.tool( + "export_pdf", + { + 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)"), + blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"), + 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"), + }, + async ({ outputPath, layers, blackAndWhite, frameReference, pageSize }) => { + logger.debug(`Exporting PDF to: ${outputPath}`); + const result = await callKicadScript("export_pdf", { + outputPath, + layers, + blackAndWhite, + frameReference, + pageSize, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Export SVG Tool + // ------------------------------------------------------ + server.tool( + "export_svg", + { + 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)"), + blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"), + includeComponents: z.boolean().optional().describe("Whether to include component outlines"), + }, + async ({ outputPath, layers, blackAndWhite, includeComponents }) => { + logger.debug(`Exporting SVG to: ${outputPath}`); + const result = await callKicadScript("export_svg", { + outputPath, + layers, + blackAndWhite, + includeComponents, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Export 3D Model Tool + // ------------------------------------------------------ + server.tool( + "export_3d", + { + outputPath: z.string().describe("Path to save the 3D model file"), + format: z.enum(["STEP", "STL", "VRML", "OBJ"]).describe("3D model format"), + includeComponents: z.boolean().optional().describe("Whether to include 3D component models"), + includeCopper: z.boolean().optional().describe("Whether to include copper layers"), + includeSolderMask: z.boolean().optional().describe("Whether to include solder mask"), + includeSilkscreen: z.boolean().optional().describe("Whether to include silkscreen"), + }, + async ({ + outputPath, + format, + includeComponents, + includeCopper, + includeSolderMask, + includeSilkscreen, + }) => { + logger.debug(`Exporting 3D model to: ${outputPath}`); + const result = await callKicadScript("export_3d", { + outputPath, + format, + includeComponents, + includeCopper, + includeSolderMask, + includeSilkscreen, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Export BOM Tool + // ------------------------------------------------------ + server.tool( + "export_bom", + { + outputPath: z.string().describe("Path to save the BOM file"), + format: z.enum(["CSV", "XML", "HTML", "JSON"]).describe("BOM file format"), + 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"), + }, + async ({ outputPath, format, groupByValue, includeAttributes }) => { + logger.debug(`Exporting BOM to: ${outputPath}`); + const result = await callKicadScript("export_bom", { + outputPath, + format, + groupByValue, + includeAttributes, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Export Netlist Tool + // ------------------------------------------------------ + server.tool( + "export_netlist", + { + outputPath: z.string().describe("Path to save the netlist file"), + format: z + .enum(["KiCad", "Spice", "Cadstar", "OrcadPCB2"]) + .optional() + .describe("Netlist format (default: KiCad)"), + }, + async ({ outputPath, format }) => { + logger.debug(`Exporting netlist to: ${outputPath}`); + const result = await callKicadScript("export_netlist", { + outputPath, + format, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Export Position File Tool + // ------------------------------------------------------ + server.tool( + "export_position_file", + { + outputPath: z.string().describe("Path to save the position file"), + format: z.enum(["CSV", "ASCII"]).optional().describe("File format (default: CSV)"), + 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)"), + }, + async ({ outputPath, format, units, side }) => { + logger.debug(`Exporting position file to: ${outputPath}`); + const result = await callKicadScript("export_position_file", { + outputPath, + format, + units, + side, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + // ------------------------------------------------------ + // Export VRML Tool + // ------------------------------------------------------ + server.tool( + "export_vrml", + { + outputPath: z.string().describe("Path to save the VRML file"), + includeComponents: z.boolean().optional().describe("Whether to include 3D component models"), + useRelativePaths: z + .boolean() + .optional() + .describe("Whether to use relative paths for 3D models"), + }, + async ({ outputPath, includeComponents, useRelativePaths }) => { + logger.debug(`Exporting VRML to: ${outputPath}`); + const result = await callKicadScript("export_vrml", { + outputPath, + includeComponents, + useRelativePaths, + }); + + return { + content: [ + { + type: "text", + text: JSON.stringify(result), + }, + ], + }; + }, + ); + + logger.info("Export tools registered"); +} diff --git a/src/tools/footprint.ts b/src/tools/footprint.ts index c7d4afd..563904b 100644 --- a/src/tools/footprint.ts +++ b/src/tools/footprint.ts @@ -62,10 +62,7 @@ const RectSchema = z.object({ // ---- tool registration --------------------------------------------------- // -export function registerFootprintTools( - server: McpServer, - callKicadScript: Function, -) { +export function registerFootprintTools(server: McpServer, callKicadScript: Function) { // ── create_footprint ──────────────────────────────────────────────────── // server.tool( "create_footprint", @@ -80,10 +77,7 @@ export function registerFootprintTools( ), name: z.string().describe("Footprint name, e.g. 'R_0603_Custom'"), description: z.string().optional().describe("Human-readable description"), - tags: z - .string() - .optional() - .describe("Space-separated tag string, e.g. 'resistor SMD 0603'"), + tags: z.string().optional().describe("Space-separated tag string, e.g. 'resistor SMD 0603'"), pads: z .array(PadSchema) .optional() @@ -91,9 +85,7 @@ export function registerFootprintTools( courtyard: RectSchema.optional().describe( "Courtyard rectangle on F.CrtYd (recommended: 0.25 mm clearance around pads)", ), - silkscreen: RectSchema.optional().describe( - "Silkscreen rectangle on F.SilkS", - ), + silkscreen: RectSchema.optional().describe("Silkscreen rectangle on F.SilkS"), fabLayer: RectSchema.optional().describe( "Fab-layer rectangle on F.Fab (shows component body)", ), @@ -139,9 +131,7 @@ export function registerFootprintTools( footprintPath: z .string() .describe("Full path to the .kicad_mod file, e.g. C:/MyLib.pretty/R_Custom.kicad_mod"), - padNumber: z - .union([z.string(), z.number()]) - .describe("Pad number to edit, e.g. '1' or 2"), + padNumber: z.union([z.string(), z.number()]).describe("Pad number to edit, e.g. '1' or 2"), size: PadSize.optional().describe("New pad size in mm"), at: PadPosition.optional().describe("New pad position in mm"), drill: z @@ -151,10 +141,7 @@ export function registerFootprintTools( ]) .optional() .describe("New drill size (for THT pads)"), - shape: z - .enum(["rect", "circle", "oval", "roundrect"]) - .optional() - .describe("New pad shape"), + shape: z.enum(["rect", "circle", "oval", "roundrect"]).optional().describe("New pad shape"), }, async (args: { 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. " + "Run this after create_footprint when KiCAD shows 'library not found in footprint library table'.", { - libraryPath: z - .string() - .describe("Full path to the .pretty directory to register"), + libraryPath: z.string().describe("Full path to the .pretty directory to register"), libraryName: z .string() .optional() diff --git a/src/tools/freerouting.ts b/src/tools/freerouting.ts index f17d7ce..c1924ec 100644 --- a/src/tools/freerouting.ts +++ b/src/tools/freerouting.ts @@ -7,33 +7,21 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; -export function registerFreeroutingTools( - server: McpServer, - callKicadScript: Function, -) { +export function registerFreeroutingTools(server: McpServer, callKicadScript: Function) { // Full autoroute: export DSN -> run Freerouting -> import SES server.tool( "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).", { - boardPath: z - .string() - .optional() - .describe("Path to .kicad_pcb file (default: current board)"), + boardPath: z.string().optional().describe("Path to .kicad_pcb file (default: current board)"), freeroutingJar: z .string() .optional() .describe( "Path to freerouting.jar (default: ~/.kicad-mcp/freerouting.jar or FREEROUTING_JAR env)", ), - maxPasses: z - .number() - .optional() - .describe("Maximum routing passes (default: 20)"), - timeout: z - .number() - .optional() - .describe("Timeout in seconds (default: 300)"), + maxPasses: z.number().optional().describe("Maximum routing passes (default: 20)"), + timeout: z.number().optional().describe("Timeout in seconds (default: 300)"), }, async (args: any) => { const result = await callKicadScript("autoroute", args); @@ -53,10 +41,7 @@ export function registerFreeroutingTools( "export_dsn", "Export the current PCB to Specctra DSN format. Useful for manual Freerouting workflow or external autorouters.", { - boardPath: z - .string() - .optional() - .describe("Path to .kicad_pcb file (default: current board)"), + boardPath: z.string().optional().describe("Path to .kicad_pcb file (default: current board)"), outputPath: z .string() .optional() @@ -81,10 +66,7 @@ export function registerFreeroutingTools( "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"), - boardPath: z - .string() - .optional() - .describe("Path to .kicad_pcb file (default: current board)"), + boardPath: z.string().optional().describe("Path to .kicad_pcb file (default: current board)"), }, async (args: any) => { const result = await callKicadScript("import_ses", args); @@ -104,10 +86,7 @@ export function registerFreeroutingTools( "check_freerouting", "Check if Java and Freerouting JAR are available on the system. Run this before autoroute to verify prerequisites.", { - freeroutingJar: z - .string() - .optional() - .describe("Path to freerouting.jar to check"), + freeroutingJar: z.string().optional().describe("Path to freerouting.jar to check"), }, async (args: any) => { const result = await callKicadScript("check_freerouting", args); diff --git a/src/tools/jlcpcb-api.ts b/src/tools/jlcpcb-api.ts index 87f6eeb..286bc73 100644 --- a/src/tools/jlcpcb-api.ts +++ b/src/tools/jlcpcb-api.ts @@ -1,245 +1,295 @@ -/** - * JLCPCB API tools for KiCAD MCP server - * Provides access to JLCPCB's complete parts catalog via their API - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; - -export function registerJLCPCBApiTools(server: McpServer, callKicadScript: Function) { - // Download JLCPCB parts database - server.tool( - "download_jlcpcb_database", - `Download the complete JLCPCB parts catalog to local database. - -This is a one-time setup that downloads ~2.5M+ parts from JLCSearch API. -No API credentials required - uses public JLCSearch API. - -The download takes 5-10 minutes and creates a local SQLite database -for fast offline searching.`, - { - force: z.boolean().optional().default(false) - .describe("Force re-download even if database exists") - }, - async (args: { force?: boolean }) => { - const result = await callKicadScript("download_jlcpcb_database", args); - if (result.success) { - return { - content: [{ - type: "text", - text: `✓ Successfully downloaded JLCPCB parts database\n\n` + - `Total parts: ${result.total_parts}\n` + - `Basic parts: ${result.basic_parts}\n` + - `Extended parts: ${result.extended_parts}\n` + - `Database size: ${result.db_size_mb} MB\n` + - `Database path: ${result.db_path}` - }] - }; - } - return { - content: [{ - type: "text", - text: `✗ 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 - server.tool( - "search_jlcpcb_parts", - `Search JLCPCB parts catalog by specifications. - -Searches the local JLCPCB database (must be downloaded first with download_jlcpcb_database). -Provides real pricing, stock info, and library type (Basic parts = free assembly). - -Use this to find components with exact specifications and cost optimization.`, - { - query: z.string().optional() - .describe("Free-text search (e.g., '10k resistor 0603', 'ESP32', 'STM32F103')"), - category: z.string().optional() - .describe("Filter by category (e.g., 'Resistors', 'Capacitors', 'Microcontrollers')"), - package: z.string().optional() - .describe("Filter by package type (e.g., '0603', 'SOT-23', 'QFN-32')"), - library_type: z.enum(["Basic", "Extended", "Preferred", "All"]).optional().default("All") - .describe("Filter by library type (Basic = free assembly at JLCPCB)"), - manufacturer: z.string().optional() - .describe("Filter by manufacturer name"), - in_stock: z.boolean().optional().default(true) - .describe("Only show parts with available stock"), - limit: z.number().optional().default(20) - .describe("Maximum number of results to return") - }, - async (args: any) => { - const result = await callKicadScript("search_jlcpcb_parts", args); - if (result.success && result.parts) { - if (result.parts.length === 0) { - return { - content: [{ - type: "text", - text: `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 priceInfo = p.price_breaks && p.price_breaks.length > 0 - ? ` - $${p.price_breaks[0].price}/ea` - : ''; - 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}`; - }).join('\n'); - - return { - content: [{ - type: "text", - text: `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 { - content: [{ - type: "text", - text: `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 - server.tool( - "get_jlcpcb_part", - "Get detailed information about a specific JLCPCB part by LCSC number", - { - lcsc_number: z.string() - .describe("LCSC part number (e.g., 'C25804', 'C2286')") - }, - async (args: { lcsc_number: string }) => { - const result = await callKicadScript("get_jlcpcb_part", args); - if (result.success && result.part) { - const p = result.part; - const priceTable = p.price_breaks && p.price_breaks.length > 0 - ? '\n\nPrice Breaks:\n' + p.price_breaks.map((pb: any) => - ` ${pb.qty}+: $${pb.price}/ea` - ).join('\n') - : ''; - - const footprints = result.footprints && result.footprints.length > 0 - ? '\n\nSuggested KiCAD Footprints:\n' + result.footprints.map((f: string) => - ` - ${f}` - ).join('\n') - : ''; - - return { - content: [{ - type: "text", - text: `LCSC: ${p.lcsc}\n` + - `MFR Part: ${p.mfr_part}\n` + - `Manufacturer: ${p.manufacturer}\n` + - `Category: ${p.category} / ${p.subcategory}\n` + - `Package: ${p.package}\n` + - `Description: ${p.description}\n` + - `Library Type: ${p.library_type} ${p.library_type === 'Basic' ? '(Free assembly!)' : ''}\n` + - `Stock: ${p.stock}\n` + - (p.datasheet ? `Datasheet: ${p.datasheet}\n` : '') + - priceTable + - footprints - }] - }; - } - return { - content: [{ - type: "text", - text: `Part not found: ${args.lcsc_number}\n\n` + - `Make sure you've downloaded the JLCPCB database first.` - }] - }; - } - ); - - // Get JLCPCB database statistics - server.tool( - "get_jlcpcb_database_stats", - "Get statistics about the local JLCPCB parts database", - {}, - async () => { - const result = await callKicadScript("get_jlcpcb_database_stats", {}); - if (result.success) { - const stats = result.stats; - return { - content: [{ - type: "text", - text: `JLCPCB Database Statistics:\n\n` + - `Total parts: ${stats.total_parts.toLocaleString()}\n` + - `Basic parts: ${stats.basic_parts.toLocaleString()} (free assembly)\n` + - `Extended parts: ${stats.extended_parts.toLocaleString()} ($3 setup fee each)\n` + - `In stock: ${stats.in_stock.toLocaleString()}\n` + - `Database path: ${stats.db_path}` - }] - }; - } - return { - content: [{ - type: "text", - text: `JLCPCB database not found or empty.\n\n` + - `Run download_jlcpcb_database first to populate the database.` - }] - }; - } - ); - - // Suggest alternative parts - server.tool( - "suggest_jlcpcb_alternatives", - `Suggest alternative JLCPCB parts for a given component. - -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.`, - { - lcsc_number: z.string() - .describe("Reference LCSC part number to find alternatives for"), - limit: z.number().optional().default(5) - .describe("Maximum number of alternatives to return") - }, - async (args: { lcsc_number: string; limit?: number }) => { - const result = await callKicadScript("suggest_jlcpcb_alternatives", args); - if (result.success && result.alternatives) { - if (result.alternatives.length === 0) { - return { - content: [{ - type: "text", - text: `No alternatives found for ${args.lcsc_number}` - }] - }; - } - - const altsList = result.alternatives.map((p: any, i: number) => { - const priceInfo = p.price_breaks && p.price_breaks.length > 0 - ? ` - $${p.price_breaks[0].price}/ea` - : ''; - 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)` - : ''; - return `${i + 1}. ${p.lcsc}: ${p.mfr_part} [${p.library_type}]${priceInfo}${savings}\n ${p.description}\n Stock: ${p.stock}`; - }).join('\n\n'); - - return { - content: [{ - type: "text", - text: `Alternative parts for ${args.lcsc_number}:\n\n${altsList}` - }] - }; - } - return { - content: [{ - type: "text", - text: `Failed to find alternatives: ${result.message || 'Unknown error'}` - }] - }; - } - ); -} +/** + * JLCPCB API tools for KiCAD MCP server + * Provides access to JLCPCB's complete parts catalog via their API + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; + +export function registerJLCPCBApiTools(server: McpServer, callKicadScript: Function) { + // Download JLCPCB parts database + server.tool( + "download_jlcpcb_database", + `Download the complete JLCPCB parts catalog to local database. + +This is a one-time setup that downloads ~2.5M+ parts from JLCSearch API. +No API credentials required - uses public JLCSearch API. + +The download takes 5-10 minutes and creates a local SQLite database +for fast offline searching.`, + { + force: z + .boolean() + .optional() + .default(false) + .describe("Force re-download even if database exists"), + }, + async (args: { force?: boolean }) => { + const result = await callKicadScript("download_jlcpcb_database", args); + if (result.success) { + return { + content: [ + { + type: "text", + text: + `✓ Successfully downloaded JLCPCB parts database\n\n` + + `Total parts: ${result.total_parts}\n` + + `Basic parts: ${result.basic_parts}\n` + + `Extended parts: ${result.extended_parts}\n` + + `Database size: ${result.db_size_mb} MB\n` + + `Database path: ${result.db_path}`, + }, + ], + }; + } + return { + content: [ + { + type: "text", + text: + `✗ 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 + server.tool( + "search_jlcpcb_parts", + `Search JLCPCB parts catalog by specifications. + +Searches the local JLCPCB database (must be downloaded first with download_jlcpcb_database). +Provides real pricing, stock info, and library type (Basic parts = free assembly). + +Use this to find components with exact specifications and cost optimization.`, + { + query: z + .string() + .optional() + .describe("Free-text search (e.g., '10k resistor 0603', 'ESP32', 'STM32F103')"), + category: z + .string() + .optional() + .describe("Filter by category (e.g., 'Resistors', 'Capacitors', 'Microcontrollers')"), + package: z + .string() + .optional() + .describe("Filter by package type (e.g., '0603', 'SOT-23', 'QFN-32')"), + library_type: z + .enum(["Basic", "Extended", "Preferred", "All"]) + .optional() + .default("All") + .describe("Filter by library type (Basic = free assembly at JLCPCB)"), + manufacturer: z.string().optional().describe("Filter by manufacturer name"), + in_stock: z + .boolean() + .optional() + .default(true) + .describe("Only show parts with available stock"), + limit: z.number().optional().default(20).describe("Maximum number of results to return"), + }, + async (args: any) => { + const result = await callKicadScript("search_jlcpcb_parts", args); + if (result.success && result.parts) { + if (result.parts.length === 0) { + return { + content: [ + { + type: "text", + text: + `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 priceInfo = + p.price_breaks && p.price_breaks.length > 0 + ? ` - $${p.price_breaks[0].price}/ea` + : ""; + 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}`; + }) + .join("\n"); + + return { + content: [ + { + type: "text", + text: + `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 { + content: [ + { + type: "text", + text: + `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 + server.tool( + "get_jlcpcb_part", + "Get detailed information about a specific JLCPCB part by LCSC number", + { + lcsc_number: z.string().describe("LCSC part number (e.g., 'C25804', 'C2286')"), + }, + async (args: { lcsc_number: string }) => { + const result = await callKicadScript("get_jlcpcb_part", args); + if (result.success && result.part) { + const p = result.part; + const priceTable = + p.price_breaks && p.price_breaks.length > 0 + ? "\n\nPrice Breaks:\n" + + p.price_breaks.map((pb: any) => ` ${pb.qty}+: $${pb.price}/ea`).join("\n") + : ""; + + const footprints = + result.footprints && result.footprints.length > 0 + ? "\n\nSuggested KiCAD Footprints:\n" + + result.footprints.map((f: string) => ` - ${f}`).join("\n") + : ""; + + return { + content: [ + { + type: "text", + text: + `LCSC: ${p.lcsc}\n` + + `MFR Part: ${p.mfr_part}\n` + + `Manufacturer: ${p.manufacturer}\n` + + `Category: ${p.category} / ${p.subcategory}\n` + + `Package: ${p.package}\n` + + `Description: ${p.description}\n` + + `Library Type: ${p.library_type} ${p.library_type === "Basic" ? "(Free assembly!)" : ""}\n` + + `Stock: ${p.stock}\n` + + (p.datasheet ? `Datasheet: ${p.datasheet}\n` : "") + + priceTable + + footprints, + }, + ], + }; + } + return { + content: [ + { + type: "text", + text: + `Part not found: ${args.lcsc_number}\n\n` + + `Make sure you've downloaded the JLCPCB database first.`, + }, + ], + }; + }, + ); + + // Get JLCPCB database statistics + server.tool( + "get_jlcpcb_database_stats", + "Get statistics about the local JLCPCB parts database", + {}, + async () => { + const result = await callKicadScript("get_jlcpcb_database_stats", {}); + if (result.success) { + const stats = result.stats; + return { + content: [ + { + type: "text", + text: + `JLCPCB Database Statistics:\n\n` + + `Total parts: ${stats.total_parts.toLocaleString()}\n` + + `Basic parts: ${stats.basic_parts.toLocaleString()} (free assembly)\n` + + `Extended parts: ${stats.extended_parts.toLocaleString()} ($3 setup fee each)\n` + + `In stock: ${stats.in_stock.toLocaleString()}\n` + + `Database path: ${stats.db_path}`, + }, + ], + }; + } + return { + content: [ + { + type: "text", + text: + `JLCPCB database not found or empty.\n\n` + + `Run download_jlcpcb_database first to populate the database.`, + }, + ], + }; + }, + ); + + // Suggest alternative parts + server.tool( + "suggest_jlcpcb_alternatives", + `Suggest alternative JLCPCB parts for a given component. + +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.`, + { + lcsc_number: z.string().describe("Reference LCSC part number to find alternatives for"), + limit: z.number().optional().default(5).describe("Maximum number of alternatives to return"), + }, + async (args: { lcsc_number: string; limit?: number }) => { + const result = await callKicadScript("suggest_jlcpcb_alternatives", args); + if (result.success && result.alternatives) { + if (result.alternatives.length === 0) { + return { + content: [ + { + type: "text", + text: `No alternatives found for ${args.lcsc_number}`, + }, + ], + }; + } + + const altsList = result.alternatives + .map((p: any, i: number) => { + const priceInfo = + p.price_breaks && p.price_breaks.length > 0 + ? ` - $${p.price_breaks[0].price}/ea` + : ""; + 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)` + : ""; + return `${i + 1}. ${p.lcsc}: ${p.mfr_part} [${p.library_type}]${priceInfo}${savings}\n ${p.description}\n Stock: ${p.stock}`; + }) + .join("\n\n"); + + return { + content: [ + { + type: "text", + text: `Alternative parts for ${args.lcsc_number}:\n\n${altsList}`, + }, + ], + }; + } + return { + content: [ + { + type: "text", + text: `Failed to find alternatives: ${result.message || "Unknown error"}`, + }, + ], + }; + }, + ); +} diff --git a/src/tools/library-symbol.ts b/src/tools/library-symbol.ts index 8222a63..7b3cb14 100644 --- a/src/tools/library-symbol.ts +++ b/src/tools/library-symbol.ts @@ -3,8 +3,8 @@ * Provides search/browse access to local KiCad symbol libraries */ -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; export function registerSymbolLibraryTools(server: McpServer, callKicadScript: Function) { // List available symbol libraries @@ -19,20 +19,20 @@ export function registerSymbolLibraryTools(server: McpServer, callKicadScript: F content: [ { 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 { content: [ { 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 @@ -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.`, { - query: z.string() - .describe("Search query (e.g., 'ESP32', 'STM32F103', 'C8734' for LCSC ID)"), - library: z.string().optional() + query: z.string().describe("Search query (e.g., 'ESP32', 'STM32F103', 'C8734' for LCSC ID)"), + library: z + .string() + .optional() .describe("Optional: filter to specific library name pattern (e.g., 'JLCPCB')"), - limit: z.number().optional().default(20) - .describe("Maximum number of results to return") + limit: z.number().optional().default(20).describe("Maximum number of results to return"), }, async (args: { query: string; library?: string; limit?: number }) => { const result = await callKicadScript("search_symbols", args); @@ -60,38 +60,40 @@ Returns symbol references that can be used directly in schematics.`, content: [ { 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 parts = [`${s.full_ref}`]; - if (s.lcsc_id) parts.push(`LCSC: ${s.lcsc_id}`); - if (s.description) parts.push(s.description); - else if (s.value) parts.push(s.value); - return parts.join(' | '); - }).join('\n'); + const symbolList = result.symbols + .map((s: any) => { + const parts = [`${s.full_ref}`]; + if (s.lcsc_id) parts.push(`LCSC: ${s.lcsc_id}`); + if (s.description) parts.push(s.description); + else if (s.value) parts.push(s.value); + return parts.join(" | "); + }) + .join("\n"); return { content: [ { 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 { content: [ { 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 @@ -99,36 +101,37 @@ Returns symbol references that can be used directly in schematics.`, "list_library_symbols", "List all symbols in a specific KiCAD symbol library", { - library: z.string() - .describe("Library name (e.g., 'Device', 'PCM_JLCPCB-MCUs')") + library: z.string().describe("Library name (e.g., 'Device', 'PCM_JLCPCB-MCUs')"), }, async (args: { library: string }) => { const result = await callKicadScript("list_library_symbols", args); if (result.success && result.symbols) { - const symbolList = result.symbols.map((s: any) => { - const parts = [` - ${s.name}`]; - if (s.lcsc_id) parts.push(`(LCSC: ${s.lcsc_id})`); - return parts.join(' '); - }).join('\n'); + const symbolList = result.symbols + .map((s: any) => { + const parts = [` - ${s.name}`]; + if (s.lcsc_id) parts.push(`(LCSC: ${s.lcsc_id})`); + return parts.join(" "); + }) + .join("\n"); return { content: [ { type: "text", - text: `Library "${args.library}" contains ${result.count} symbols:\n${symbolList}` - } - ] + text: `Library "${args.library}" contains ${result.count} symbols:\n${symbolList}`, + }, + ], }; } return { content: [ { 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 @@ -136,8 +139,9 @@ Returns symbol references that can be used directly in schematics.`, "get_symbol_info", "Get detailed information about a specific symbol", { - symbol: z.string() - .describe("Symbol specification (e.g., 'Device:R' or 'PCM_JLCPCB-MCUs:STM32F103C8T6')") + symbol: z + .string() + .describe("Symbol specification (e.g., 'Device:R' or 'PCM_JLCPCB-MCUs:STM32F103C8T6')"), }, async (args: { symbol: string }) => { 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 details = [ `Symbol: ${info.full_ref}`, - info.value ? `Value: ${info.value}` : '', - info.description ? `Description: ${info.description}` : '', - info.lcsc_id ? `LCSC: ${info.lcsc_id}` : '', - info.manufacturer ? `Manufacturer: ${info.manufacturer}` : '', - info.mpn ? `MPN: ${info.mpn}` : '', - info.footprint ? `Footprint: ${info.footprint}` : '', - info.category ? `Category: ${info.category}` : '', - info.lib_class ? `Class: ${info.lib_class}` : '', - info.datasheet ? `Datasheet: ${info.datasheet}` : '', - ].filter(line => line).join('\n'); + info.value ? `Value: ${info.value}` : "", + info.description ? `Description: ${info.description}` : "", + info.lcsc_id ? `LCSC: ${info.lcsc_id}` : "", + info.manufacturer ? `Manufacturer: ${info.manufacturer}` : "", + info.mpn ? `MPN: ${info.mpn}` : "", + info.footprint ? `Footprint: ${info.footprint}` : "", + info.category ? `Category: ${info.category}` : "", + info.lib_class ? `Class: ${info.lib_class}` : "", + info.datasheet ? `Datasheet: ${info.datasheet}` : "", + ] + .filter((line) => line) + .join("\n"); return { content: [ { type: "text", - text: details - } - ] + text: details, + }, + ], }; } return { content: [ { type: "text", - text: `Failed to get symbol info: ${result.message || 'Unknown error'}` - } - ] + text: `Failed to get symbol info: ${result.message || "Unknown error"}`, + }, + ], }; - } + }, ); } diff --git a/src/tools/library.ts b/src/tools/library.ts index 2adeeac..386aba0 100644 --- a/src/tools/library.ts +++ b/src/tools/library.ts @@ -6,10 +6,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; -export function registerLibraryTools( - server: McpServer, - callKicadScript: Function, -) { +export function registerLibraryTools(server: McpServer, callKicadScript: Function) { // List available footprint libraries server.tool( "list_libraries", @@ -48,18 +45,9 @@ export function registerLibraryTools( "search_footprints", "Search for footprints matching a pattern across all libraries", { - search_term: z - .string() - .describe("Search term or pattern to match footprint names"), - library: z - .string() - .optional() - .describe("Optional specific library to search in"), - limit: z - .number() - .optional() - .default(50) - .describe("Maximum number of results to return"), + search_term: z.string().describe("Search term or pattern to match footprint names"), + 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 }) => { const result = await callKicadScript("search_footprints", { @@ -99,25 +87,14 @@ export function registerLibraryTools( "list_library_footprints", "List all footprints in a specific KiCAD library", { - library_name: z - .string() - .describe("Name of the library to list footprints from"), - filter: z - .string() - .optional() - .describe("Optional filter pattern for footprint names"), - limit: z - .number() - .optional() - .default(100) - .describe("Maximum number of footprints to list"), + library_name: z.string().describe("Name of the library to list footprints from"), + 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 }) => { const result = await callKicadScript("list_library_footprints", args); if (result.success && result.footprints) { - const footprintList = result.footprints - .map((fp: string) => ` - ${fp}`) - .join("\n"); + const footprintList = result.footprints.map((fp: string) => ` - ${fp}`).join("\n"); return { content: [ { @@ -143,12 +120,8 @@ export function registerLibraryTools( "get_footprint_info", "Get detailed information about a specific footprint", { - library_name: z - .string() - .describe("Name of the library containing the footprint"), - footprint_name: z - .string() - .describe("Name of the footprint to get information about"), + library_name: z.string().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 }) => { const result = await callKicadScript("get_footprint_info", args); @@ -156,15 +129,16 @@ export function registerLibraryTools( const info = result.info; // pads is a list of {number, type, shape} objects - const padsArray: Array<{ number: string; type: string; shape: string }> = - Array.isArray(info.pads) ? info.pads : []; + const padsArray: Array<{ number: string; type: string; shape: string }> = Array.isArray( + info.pads, + ) + ? info.pads + : []; const padsSummary = padsArray.length ? `${padsArray.length} pads: ${padsArray.map((p) => p.number).join(", ")}` : ""; const padsDetail = padsArray.length - ? padsArray - .map((p) => ` pad ${p.number}: ${p.type} ${p.shape}`) - .join("\n") + ? padsArray.map((p) => ` pad ${p.number}: ${p.type} ${p.shape}`).join("\n") : ""; const details = [ @@ -178,9 +152,7 @@ export function registerLibraryTools( info.courtyard ? `Courtyard size: ${info.courtyard.width}mm x ${info.courtyard.height}mm` : "", - info.attributes - ? `Attributes: ${JSON.stringify(info.attributes)}` - : "", + info.attributes ? `Attributes: ${JSON.stringify(info.attributes)}` : "", ] .filter((line) => line) .join("\n"); diff --git a/src/tools/project.ts b/src/tools/project.ts index 1e59179..edbbc93 100644 --- a/src/tools/project.ts +++ b/src/tools/project.ts @@ -1,99 +1,116 @@ -/** - * Project management tools for KiCAD MCP server - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; - -export function registerProjectTools(server: McpServer, callKicadScript: Function) { - // Create project tool - server.tool( - "create_project", - "Create a new KiCAD project", - { - path: z.string().describe("Project directory path"), - name: z.string().describe("Project name"), - }, - async (args: { path: string; name: string }) => { - const result = await callKicadScript("create_project", args); - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - // Open project tool - server.tool( - "open_project", - "Open an existing KiCAD project", - { - filename: z.string().describe("Path to .kicad_pro or .kicad_pcb file"), - }, - async (args: { filename: string }) => { - const result = await callKicadScript("open_project", args); - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - // Save project tool - server.tool( - "save_project", - "Save the current KiCAD project", - { - path: z.string().optional().describe("Optional new path to save to"), - }, - async (args: { path?: string }) => { - const result = await callKicadScript("save_project", args); - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - // Get project info tool - server.tool( - "get_project_info", - "Get information about the current KiCAD project", - {}, - async () => { - const result = await callKicadScript("get_project_info", {}); - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - // Snapshot project tool — saves a named checkpoint as PDF/image - server.tool( - "snapshot_project", - "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'"), - label: z.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 }) => { - const result = await callKicadScript("snapshot_project", args); - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); -} +/** + * Project management tools for KiCAD MCP server + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; + +export function registerProjectTools(server: McpServer, callKicadScript: Function) { + // Create project tool + server.tool( + "create_project", + "Create a new KiCAD project", + { + path: z.string().describe("Project directory path"), + name: z.string().describe("Project name"), + }, + async (args: { path: string; name: string }) => { + const result = await callKicadScript("create_project", args); + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); + + // Open project tool + server.tool( + "open_project", + "Open an existing KiCAD project", + { + filename: z.string().describe("Path to .kicad_pro or .kicad_pcb file"), + }, + async (args: { filename: string }) => { + const result = await callKicadScript("open_project", args); + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); + + // Save project tool + server.tool( + "save_project", + "Save the current KiCAD project", + { + path: z.string().optional().describe("Optional new path to save to"), + }, + async (args: { path?: string }) => { + const result = await callKicadScript("save_project", args); + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); + + // Get project info tool + server.tool( + "get_project_info", + "Get information about the current KiCAD project", + {}, + async () => { + const result = await callKicadScript("get_project_info", {}); + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); + + // Snapshot project tool — saves a named checkpoint as PDF/image + server.tool( + "snapshot_project", + "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'"), + label: z + .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 }) => { + const result = await callKicadScript("snapshot_project", args); + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); +} diff --git a/src/tools/registry.ts b/src/tools/registry.ts index 4799052..1ef1103 100644 --- a/src/tools/registry.ts +++ b/src/tools/registry.ts @@ -1,308 +1,295 @@ -/** - * Tool Registry for KiCAD MCP Server - * - * Centralizes all tool definitions and provides lookup/search functionality - */ - -import { z } from 'zod'; - -export interface ToolDefinition { - name: string; - description: string; - inputSchema: z.ZodObject | z.ZodType; - // Handler will be registered separately in the existing tool files -} - -export interface ToolCategory { - name: string; - description: string; - tools: string[]; // Tool names in this category -} - -/** - * Tool category definitions - * Each category groups related tools for better organization - */ -export const toolCategories: ToolCategory[] = [ - { - name: "board", - description: "Board configuration: layers, mounting holes, zones, visualization", - tools: [ - "add_layer", - "set_active_layer", - "get_layer_list", - "add_mounting_hole", - "add_board_text", - "add_zone", - "get_board_extents", - "get_board_2d_view", - "launch_kicad_ui" - ] - }, - { - name: "component", - description: "Advanced component operations: edit, delete, search, group, annotate", - tools: [ - "rotate_component", - "delete_component", - "edit_component", - "find_component", - "get_component_properties", - "add_component_annotation", - "group_components", - "replace_component" - ] - }, - { - name: "export", - description: "File export for fabrication and documentation: Gerber, PDF, BOM, 3D models", - tools: [ - "export_gerber", - "export_pdf", - "export_svg", - "export_3d", - "export_bom", - "export_netlist", - "export_position_file", - "export_vrml" - ] - }, - { - name: "drc", - description: "Design rule checking and electrical validation: DRC, net classes, clearances", - tools: [ - "set_design_rules", - "get_design_rules", - "run_drc", - "add_net_class", - "assign_net_to_class", - "set_layer_constraints", - "check_clearance", - "get_drc_violations" - ] - }, - { - name: "schematic", - description: "Schematic operations: create, inspect, add/edit/delete components, wire connections, netlists, annotation", - tools: [ - "create_schematic", - "add_schematic_component", - "list_schematic_components", - "move_schematic_component", - "rotate_schematic_component", - "annotate_schematic", - "add_schematic_wire", - "delete_schematic_wire", - "add_schematic_junction", - "add_schematic_net_label", - "delete_schematic_net_label", - "connect_to_net", - "connect_passthrough", - "get_net_connections", - "list_schematic_nets", - "list_schematic_wires", - "list_schematic_labels", - "get_wire_connections", - "generate_netlist", - "sync_schematic_to_board", - "get_schematic_view", - "export_schematic_svg", - "export_schematic_pdf" - ] - }, - { - name: "library", - description: "Footprint library access: search, browse, get footprint information", - tools: [ - "list_libraries", - "search_footprints", - "list_library_footprints", - "get_footprint_info" - ] - }, - { - name: "routing", - description: "Advanced routing operations: vias, copper pours", - tools: [ - "add_via", - "add_copper_pour" - ] - }, - { - name: "autoroute", - description: "Freerouting autorouter: automatic PCB routing via Specctra DSN/SES", - tools: [ - "autoroute", - "export_dsn", - "import_ses", - "check_freerouting" - ] - } -]; - -/** - * Direct tools that are always visible (not routed) - * These are the most frequently used tools - */ -export const directToolNames = [ - // Project lifecycle - "create_project", - "open_project", - "save_project", - "snapshot_project", - "get_project_info", - - // Core PCB operations - "place_component", - "move_component", - "add_net", - "route_trace", - "get_board_info", - "set_board_size", - - // Board setup - "add_board_outline", - - // Schematic essentials (always visible so AI uses them correctly) - "add_schematic_component", - "list_schematic_components", - "annotate_schematic", - "connect_passthrough", - "connect_to_net", - "add_schematic_net_label", - - // Schematic <-> PCB sync (F8 equivalent) - "sync_schematic_to_board", - - // UI management - "check_kicad_ui" -]; - -// Build lookup maps at module load time -const categoryMap = new Map(); -const toolCategoryMap = new Map(); - -export function initializeRegistry() { - // Build category map - for (const category of toolCategories) { - categoryMap.set(category.name, category); - - // Build tool -> category map - for (const toolName of category.tools) { - toolCategoryMap.set(toolName, category.name); - } - } -} - -/** - * Get a category by name - */ -export function getCategory(name: string): ToolCategory | undefined { - return categoryMap.get(name); -} - -/** - * Get the category name for a tool - */ -export function getToolCategory(toolName: string): string | undefined { - return toolCategoryMap.get(toolName); -} - -/** - * Get all categories - */ -export function getAllCategories(): ToolCategory[] { - return toolCategories; -} - -/** - * Get all routed tool names (excludes direct tools) - */ -export function getRoutedToolNames(): string[] { - const allRoutedTools: string[] = []; - for (const category of toolCategories) { - allRoutedTools.push(...category.tools); - } - return allRoutedTools; -} - -/** - * Check if a tool is a direct tool - */ -export function isDirectTool(toolName: string): boolean { - return directToolNames.includes(toolName); -} - -/** - * Check if a tool is a routed tool - */ -export function isRoutedTool(toolName: string): boolean { - return toolCategoryMap.has(toolName); -} - -/** - * Search for tools by keyword - * Searches tool names, descriptions, and category names - */ -export interface SearchResult { - category: string; - tool: string; - description: string; -} - -export function searchTools(query: string): SearchResult[] { - const q = query.toLowerCase(); - const matches: SearchResult[] = []; - - // Search direct tools first - for (const toolName of directToolNames) { - if (toolName.toLowerCase().includes(q)) { - matches.push({ - category: "direct", - tool: toolName, - description: `${toolName} (direct tool — call directly, no execute_tool needed)` - }); - } - } - - // Search routed tools by name and category - for (const category of toolCategories) { - const categoryMatch = - category.name.toLowerCase().includes(q) || - category.description.toLowerCase().includes(q); - - for (const toolName of category.tools) { - if (toolName.toLowerCase().includes(q) || categoryMatch) { - matches.push({ - category: category.name, - tool: toolName, - description: `${toolName} (${category.name})` - }); - } - } - } - - return matches.slice(0, 20); // Limit results -} - -/** - * Get statistics about the tool registry - */ -export function getRegistryStats() { - const routedToolCount = getRoutedToolNames().length; - const directToolCount = directToolNames.length; - - return { - total_categories: toolCategories.length, - total_routed_tools: routedToolCount, - total_direct_tools: directToolCount, - total_tools: routedToolCount + directToolCount, - categories: toolCategories.map(c => ({ - name: c.name, - tool_count: c.tools.length - })) - }; -} - -// Initialize on module load -initializeRegistry(); +/** + * Tool Registry for KiCAD MCP Server + * + * Centralizes all tool definitions and provides lookup/search functionality + */ + +import { z } from "zod"; + +export interface ToolDefinition { + name: string; + description: string; + inputSchema: z.ZodObject | z.ZodType; + // Handler will be registered separately in the existing tool files +} + +export interface ToolCategory { + name: string; + description: string; + tools: string[]; // Tool names in this category +} + +/** + * Tool category definitions + * Each category groups related tools for better organization + */ +export const toolCategories: ToolCategory[] = [ + { + name: "board", + description: "Board configuration: layers, mounting holes, zones, visualization", + tools: [ + "add_layer", + "set_active_layer", + "get_layer_list", + "add_mounting_hole", + "add_board_text", + "add_zone", + "get_board_extents", + "get_board_2d_view", + "launch_kicad_ui", + ], + }, + { + name: "component", + description: "Advanced component operations: edit, delete, search, group, annotate", + tools: [ + "rotate_component", + "delete_component", + "edit_component", + "find_component", + "get_component_properties", + "add_component_annotation", + "group_components", + "replace_component", + ], + }, + { + name: "export", + description: "File export for fabrication and documentation: Gerber, PDF, BOM, 3D models", + tools: [ + "export_gerber", + "export_pdf", + "export_svg", + "export_3d", + "export_bom", + "export_netlist", + "export_position_file", + "export_vrml", + ], + }, + { + name: "drc", + description: "Design rule checking and electrical validation: DRC, net classes, clearances", + tools: [ + "set_design_rules", + "get_design_rules", + "run_drc", + "add_net_class", + "assign_net_to_class", + "set_layer_constraints", + "check_clearance", + "get_drc_violations", + ], + }, + { + name: "schematic", + description: + "Schematic operations: create, inspect, add/edit/delete components, wire connections, netlists, annotation", + tools: [ + "create_schematic", + "add_schematic_component", + "list_schematic_components", + "move_schematic_component", + "rotate_schematic_component", + "annotate_schematic", + "add_schematic_wire", + "delete_schematic_wire", + "add_schematic_junction", + "add_schematic_net_label", + "delete_schematic_net_label", + "connect_to_net", + "connect_passthrough", + "get_net_connections", + "list_schematic_nets", + "list_schematic_wires", + "list_schematic_labels", + "get_wire_connections", + "generate_netlist", + "sync_schematic_to_board", + "get_schematic_view", + "export_schematic_svg", + "export_schematic_pdf", + ], + }, + { + name: "library", + description: "Footprint library access: search, browse, get footprint information", + tools: ["list_libraries", "search_footprints", "list_library_footprints", "get_footprint_info"], + }, + { + name: "routing", + description: "Advanced routing operations: vias, copper pours", + tools: ["add_via", "add_copper_pour"], + }, + { + name: "autoroute", + description: "Freerouting autorouter: automatic PCB routing via Specctra DSN/SES", + tools: ["autoroute", "export_dsn", "import_ses", "check_freerouting"], + }, +]; + +/** + * Direct tools that are always visible (not routed) + * These are the most frequently used tools + */ +export const directToolNames = [ + // Project lifecycle + "create_project", + "open_project", + "save_project", + "snapshot_project", + "get_project_info", + + // Core PCB operations + "place_component", + "move_component", + "add_net", + "route_trace", + "get_board_info", + "set_board_size", + + // Board setup + "add_board_outline", + + // Schematic essentials (always visible so AI uses them correctly) + "add_schematic_component", + "list_schematic_components", + "annotate_schematic", + "connect_passthrough", + "connect_to_net", + "add_schematic_net_label", + + // Schematic <-> PCB sync (F8 equivalent) + "sync_schematic_to_board", + + // UI management + "check_kicad_ui", +]; + +// Build lookup maps at module load time +const categoryMap = new Map(); +const toolCategoryMap = new Map(); + +export function initializeRegistry() { + // Build category map + for (const category of toolCategories) { + categoryMap.set(category.name, category); + + // Build tool -> category map + for (const toolName of category.tools) { + toolCategoryMap.set(toolName, category.name); + } + } +} + +/** + * Get a category by name + */ +export function getCategory(name: string): ToolCategory | undefined { + return categoryMap.get(name); +} + +/** + * Get the category name for a tool + */ +export function getToolCategory(toolName: string): string | undefined { + return toolCategoryMap.get(toolName); +} + +/** + * Get all categories + */ +export function getAllCategories(): ToolCategory[] { + return toolCategories; +} + +/** + * Get all routed tool names (excludes direct tools) + */ +export function getRoutedToolNames(): string[] { + const allRoutedTools: string[] = []; + for (const category of toolCategories) { + allRoutedTools.push(...category.tools); + } + return allRoutedTools; +} + +/** + * Check if a tool is a direct tool + */ +export function isDirectTool(toolName: string): boolean { + return directToolNames.includes(toolName); +} + +/** + * Check if a tool is a routed tool + */ +export function isRoutedTool(toolName: string): boolean { + return toolCategoryMap.has(toolName); +} + +/** + * Search for tools by keyword + * Searches tool names, descriptions, and category names + */ +export interface SearchResult { + category: string; + tool: string; + description: string; +} + +export function searchTools(query: string): SearchResult[] { + const q = query.toLowerCase(); + const matches: SearchResult[] = []; + + // Search direct tools first + for (const toolName of directToolNames) { + if (toolName.toLowerCase().includes(q)) { + matches.push({ + category: "direct", + tool: toolName, + description: `${toolName} (direct tool — call directly, no execute_tool needed)`, + }); + } + } + + // Search routed tools by name and category + for (const category of toolCategories) { + const categoryMatch = + category.name.toLowerCase().includes(q) || category.description.toLowerCase().includes(q); + + for (const toolName of category.tools) { + if (toolName.toLowerCase().includes(q) || categoryMatch) { + matches.push({ + category: category.name, + tool: toolName, + description: `${toolName} (${category.name})`, + }); + } + } + } + + return matches.slice(0, 20); // Limit results +} + +/** + * Get statistics about the tool registry + */ +export function getRegistryStats() { + const routedToolCount = getRoutedToolNames().length; + const directToolCount = directToolNames.length; + + return { + total_categories: toolCategories.length, + total_routed_tools: routedToolCount, + total_direct_tools: directToolCount, + total_tools: routedToolCount + directToolCount, + categories: toolCategories.map((c) => ({ + name: c.name, + tool_count: c.tools.length, + })), + }; +} + +// Initialize on module load +initializeRegistry(); diff --git a/src/tools/router.ts b/src/tools/router.ts index 8a1d060..437aa51 100644 --- a/src/tools/router.ts +++ b/src/tools/router.ts @@ -1,251 +1,296 @@ -/** - * Router Tools for KiCAD MCP Server - * - * Provides discovery and execution of routed tools - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; -import { - getAllCategories, - getCategory, - getToolCategory, - searchTools as registrySearchTools, - getRegistryStats -} from './registry.js'; - -// Command function type for KiCAD script calls -type CommandFunction = (command: string, params: Record) => Promise; - -// Map to store tool execution handlers -// This will be populated by registerToolHandler() -const toolHandlers = new Map Promise>(); - -/** - * Register a tool handler for execution via execute_tool - * This should be called by each tool registration function - */ -export function registerToolHandler( - toolName: string, - handler: (params: any) => Promise -): void { - toolHandlers.set(toolName, handler); - logger.debug(`Registered handler for routed tool: ${toolName}`); -} - -/** - * Register all router tools with the MCP server - */ -export function registerRouterTools(server: McpServer, callKicadScript: CommandFunction): void { - logger.info('Registering router tools'); - - // ============================================================================ - // list_tool_categories - // ============================================================================ - server.tool( - "list_tool_categories", - { - // No parameters - }, - async () => { - logger.debug('Listing tool categories'); - - const stats = getRegistryStats(); - const categories = getAllCategories(); - - const result = { - total_categories: stats.total_categories, - total_routed_tools: stats.total_routed_tools, - total_direct_tools: stats.total_direct_tools, - note: "Use get_category_tools to see tools in each category. Direct tools are always available.", - categories: categories.map(c => ({ - name: c.name, - description: c.description, - tool_count: c.tools.length - })) - }; - - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - // ============================================================================ - // get_category_tools - // ============================================================================ - server.tool( - "get_category_tools", - { - category: z.string().describe("Category name from list_tool_categories") - }, - async ({ category }) => { - logger.debug(`Getting tools for category: ${category}`); - - const categoryData = getCategory(category); - - if (!categoryData) { - const availableCategories = getAllCategories().map(c => c.name); - return { - content: [{ - type: "text", - text: JSON.stringify({ - error: `Unknown category: ${category}`, - available_categories: availableCategories - }, null, 2) - }] - }; - } - - // Return tool names and basic info - // Full schema is available via tool introspection once tool is called - const result = { - category: categoryData.name, - description: categoryData.description, - tool_count: categoryData.tools.length, - tools: categoryData.tools.map(toolName => ({ - name: toolName, - 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" - }; - - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - // ============================================================================ - // execute_tool - // ============================================================================ - server.tool( - "execute_tool", - { - tool_name: z.string().describe("Tool name from get_category_tools"), - params: z.record(z.unknown()).optional().describe("Tool parameters (optional)") - }, - async ({ tool_name, params }) => { - logger.info(`Executing routed tool: ${tool_name}`); - - // Check if tool exists in registry - const category = getToolCategory(tool_name); - - if (!category) { - return { - content: [{ - type: "text", - text: JSON.stringify({ - error: `Unknown tool: ${tool_name}`, - hint: "Use list_tool_categories and get_category_tools to find available tools" - }, null, 2) - }] - }; - } - - // Get the handler - const handler = toolHandlers.get(tool_name); - - if (!handler) { - // Tool is in registry but handler not registered yet - // This means the tool exists but hasn't been migrated to router pattern yet - // Fall back to calling KiCAD script directly - logger.warn(`Tool ${tool_name} in registry but no handler registered, falling back to direct call`); - - try { - const result = await callKicadScript(tool_name, params || {}); - return { - content: [{ - type: "text", - text: JSON.stringify({ - tool: tool_name, - category: category, - result: result - }, null, 2) - }] - }; - } catch (error) { - return { - content: [{ - type: "text", - text: JSON.stringify({ - error: `Tool execution failed: ${(error as Error).message}`, - tool: tool_name, - category: category - }, null, 2) - }] - }; - } - } - - // Execute the tool via its handler - try { - const result = await handler(params || {}); - - // The handler already returns MCP-formatted response - // Just add metadata - return { - content: [{ - type: "text", - text: JSON.stringify({ - tool: tool_name, - category: category, - ...result - }, null, 2) - }] - }; - } catch (error) { - return { - content: [{ - type: "text", - text: JSON.stringify({ - error: `Tool execution failed: ${(error as Error).message}`, - tool: tool_name, - category: category - }, null, 2) - }] - }; - } - } - ); - - // ============================================================================ - // search_tools - // ============================================================================ - server.tool( - "search_tools", - { - query: z.string().describe("Search term (e.g., 'gerber', 'zone', 'export', 'drc')") - }, - async ({ query }) => { - logger.debug(`Searching tools for: ${query}`); - - const matches = registrySearchTools(query); - - const result = { - query: query, - count: matches.length, - matches: matches, - note: matches.length > 0 - ? "Use execute_tool with the tool name to run it" - : "No tools found matching your query. Try list_tool_categories to browse all categories." - }; - - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - logger.info('Router tools registered successfully'); -} +/** + * Router Tools for KiCAD MCP Server + * + * Provides discovery and execution of routed tools + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; +import { + getAllCategories, + getCategory, + getToolCategory, + searchTools as registrySearchTools, + getRegistryStats, +} from "./registry.js"; + +// Command function type for KiCAD script calls +type CommandFunction = (command: string, params: Record) => Promise; + +// Map to store tool execution handlers +// This will be populated by registerToolHandler() +const toolHandlers = new Map Promise>(); + +/** + * Register a tool handler for execution via execute_tool + * This should be called by each tool registration function + */ +export function registerToolHandler( + toolName: string, + handler: (params: any) => Promise, +): void { + toolHandlers.set(toolName, handler); + logger.debug(`Registered handler for routed tool: ${toolName}`); +} + +/** + * Register all router tools with the MCP server + */ +export function registerRouterTools(server: McpServer, callKicadScript: CommandFunction): void { + logger.info("Registering router tools"); + + // ============================================================================ + // list_tool_categories + // ============================================================================ + server.tool( + "list_tool_categories", + { + // No parameters + }, + async () => { + logger.debug("Listing tool categories"); + + const stats = getRegistryStats(); + const categories = getAllCategories(); + + const result = { + total_categories: stats.total_categories, + total_routed_tools: stats.total_routed_tools, + total_direct_tools: stats.total_direct_tools, + note: "Use get_category_tools to see tools in each category. Direct tools are always available.", + categories: categories.map((c) => ({ + name: c.name, + description: c.description, + tool_count: c.tools.length, + })), + }; + + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); + + // ============================================================================ + // get_category_tools + // ============================================================================ + server.tool( + "get_category_tools", + { + category: z.string().describe("Category name from list_tool_categories"), + }, + async ({ category }) => { + logger.debug(`Getting tools for category: ${category}`); + + const categoryData = getCategory(category); + + if (!categoryData) { + const availableCategories = getAllCategories().map((c) => c.name); + return { + content: [ + { + type: "text", + text: JSON.stringify( + { + error: `Unknown category: ${category}`, + available_categories: availableCategories, + }, + null, + 2, + ), + }, + ], + }; + } + + // Return tool names and basic info + // Full schema is available via tool introspection once tool is called + const result = { + category: categoryData.name, + description: categoryData.description, + tool_count: categoryData.tools.length, + tools: categoryData.tools.map((toolName) => ({ + name: toolName, + 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", + }; + + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); + + // ============================================================================ + // execute_tool + // ============================================================================ + server.tool( + "execute_tool", + { + tool_name: z.string().describe("Tool name from get_category_tools"), + params: z.record(z.unknown()).optional().describe("Tool parameters (optional)"), + }, + async ({ tool_name, params }) => { + logger.info(`Executing routed tool: ${tool_name}`); + + // Check if tool exists in registry + const category = getToolCategory(tool_name); + + if (!category) { + return { + content: [ + { + type: "text", + text: JSON.stringify( + { + error: `Unknown tool: ${tool_name}`, + hint: "Use list_tool_categories and get_category_tools to find available tools", + }, + null, + 2, + ), + }, + ], + }; + } + + // Get the handler + const handler = toolHandlers.get(tool_name); + + if (!handler) { + // Tool is in registry but handler not registered yet + // This means the tool exists but hasn't been migrated to router pattern yet + // Fall back to calling KiCAD script directly + logger.warn( + `Tool ${tool_name} in registry but no handler registered, falling back to direct call`, + ); + + try { + const result = await callKicadScript(tool_name, params || {}); + return { + content: [ + { + type: "text", + text: JSON.stringify( + { + tool: tool_name, + category: category, + result: result, + }, + null, + 2, + ), + }, + ], + }; + } catch (error) { + return { + content: [ + { + type: "text", + text: JSON.stringify( + { + error: `Tool execution failed: ${(error as Error).message}`, + tool: tool_name, + category: category, + }, + null, + 2, + ), + }, + ], + }; + } + } + + // Execute the tool via its handler + try { + const result = await handler(params || {}); + + // The handler already returns MCP-formatted response + // Just add metadata + return { + content: [ + { + type: "text", + text: JSON.stringify( + { + tool: tool_name, + category: category, + ...result, + }, + null, + 2, + ), + }, + ], + }; + } catch (error) { + return { + content: [ + { + type: "text", + text: JSON.stringify( + { + error: `Tool execution failed: ${(error as Error).message}`, + tool: tool_name, + category: category, + }, + null, + 2, + ), + }, + ], + }; + } + }, + ); + + // ============================================================================ + // search_tools + // ============================================================================ + server.tool( + "search_tools", + { + query: z.string().describe("Search term (e.g., 'gerber', 'zone', 'export', 'drc')"), + }, + async ({ query }) => { + logger.debug(`Searching tools for: ${query}`); + + const matches = registrySearchTools(query); + + const result = { + query: query, + count: matches.length, + matches: matches, + note: + matches.length > 0 + ? "Use execute_tool with the tool name to run it" + : "No tools found matching your query. Try list_tool_categories to browse all categories.", + }; + + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); + + logger.info("Router tools registered successfully"); +} diff --git a/src/tools/routing.ts b/src/tools/routing.ts index 309bd2d..3ead958 100644 --- a/src/tools/routing.ts +++ b/src/tools/routing.ts @@ -5,10 +5,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; -export function registerRoutingTools( - server: McpServer, - callKicadScript: Function, -) { +export function registerRoutingTools(server: McpServer, callKicadScript: Function) { // Add net tool server.tool( "add_net", @@ -79,10 +76,7 @@ export function registerRoutingTools( }) .describe("Via position"), net: z.string().describe("Net name"), - viaType: z - .string() - .optional() - .describe("Via type (through, blind, buried)"), + viaType: z.string().optional().describe("Via type (through, blind, buried)"), }, async (args: any) => { const result = await callKicadScript("add_via", args); @@ -130,10 +124,7 @@ export function registerRoutingTools( "delete_trace", "Delete traces from the PCB. Can delete by UUID, position, or bulk-delete all traces on a net.", { - traceUuid: z - .string() - .optional() - .describe("UUID of a specific trace to delete"), + traceUuid: z.string().optional().describe("UUID of a specific trace to delete"), position: z .object({ x: z.number(), @@ -142,18 +133,9 @@ export function registerRoutingTools( }) .optional() .describe("Delete trace nearest to this position"), - net: z - .string() - .optional() - .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"), + net: z.string().optional().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) => { const result = await callKicadScript("delete_trace", args); @@ -209,10 +191,7 @@ export function registerRoutingTools( .boolean() .optional() .describe("Include statistics (track count, total length, etc.)"), - unit: z - .enum(["mm", "inch"]) - .optional() - .describe("Unit for length measurements"), + unit: z.enum(["mm", "inch"]).optional().describe("Unit for length measurements"), }, async (args: any) => { 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.", { 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')"), - 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)"), 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)"), @@ -362,10 +345,7 @@ export function registerRoutingTools( .describe( "References of the target components in same order as sourceRefs (e.g. ['U2', 'R2', 'C2'])", ), - includeVias: z - .boolean() - .optional() - .describe("Also copy vias (default: true)"), + includeVias: z.boolean().optional().describe("Also copy vias (default: true)"), traceWidth: z .number() .optional() diff --git a/src/tools/schematic.ts b/src/tools/schematic.ts index 1fcf905..ad75abd 100644 --- a/src/tools/schematic.ts +++ b/src/tools/schematic.ts @@ -5,10 +5,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; -export function registerSchematicTools( - server: McpServer, - callKicadScript: Function, -) { +export function registerSchematicTools(server: McpServer, callKicadScript: Function) { // Create schematic tool server.tool( "create_schematic", @@ -38,9 +35,7 @@ export function registerSchematicTools( schematicPath: z.string().describe("Path to the schematic file"), symbol: z .string() - .describe( - "Symbol library:name reference (e.g., Device:R, EDA-MCP:ESP32-C3)", - ), + .describe("Symbol library:name reference (e.g., Device:R, EDA-MCP:ESP32-C3)"), reference: z.string().describe("Component reference (e.g., R1, U1)"), value: z.string().optional().describe("Component value"), footprint: z @@ -82,10 +77,7 @@ export function registerSchematicTools( }, }; - const result = await callKicadScript( - "add_schematic_component", - transformed, - ); + const result = await callKicadScript("add_schematic_component", transformed); if (result.success) { return { 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"), reference: z .string() - .describe( - "Reference designator of the component to remove (e.g. R1, U3)", - ), + .describe("Reference designator of the component to remove (e.g. R1, U3)"), }, async (args: { schematicPath: string; reference: string }) => { 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"), 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)"), - newReference: z.string().optional().describe("Rename the reference designator (e.g. R1 → R10)"), - fieldPositions: z.record(z.object({ - x: z.number(), - y: z.number(), - 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}})"), + newReference: z + .string() + .optional() + .describe("Rename the reference designator (e.g. R1 → R10)"), + fieldPositions: z + .record( + z.object({ + x: z.number(), + y: z.number(), + 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}})', + ), }, async (args: { schematicPath: string; @@ -220,20 +223,24 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp : "unknown"; const fieldLines = Object.entries(result.fields ?? {}).map( ([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 { - content: [{ - type: "text", - text: `Component ${result.reference} at ${pos}\nFields:\n${fieldLines.join("\n")}`, - }], + content: [ + { + type: "text", + text: `Component ${result.reference} at ${pos}\nFields:\n${fieldLines.join("\n")}`, + }, + ], }; } return { - content: [{ - type: "text", - text: `Failed to get component: ${result.message || "Unknown error"}`, - }], + content: [ + { + type: "text", + 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 .boolean() .optional() - .describe( - "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)"), + .describe("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)"), }, async (args: { 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.", { schematicPath: z.string().describe("Path to the .kicad_sch file"), - position: z - .array(z.number()) - .length(2) - .describe("Junction position [x, y] in mm"), + position: z.array(z.number()).length(2).describe("Junction position [x, y] in mm"), }, async (args: { schematicPath: string; position: number[] }) => { 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", { schematicPath: z.string().describe("Path to the schematic file"), - netName: z - .string() - .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"), + netName: z.string().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: { - schematicPath: string; - netName: string; - position: number[]; - }) => { + async (args: { schematicPath: string; netName: string; position: number[] }) => { const result = await callKicadScript("add_schematic_net_label", args); if (result.success) { 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 }) => { const result = await callKicadScript("get_wire_connections", args); if (result.success && result.pins) { - const pinList = result.pins - .map((p: any) => ` - ${p.component}/${p.pin}`) - .join("\n"); + const pinList = result.pins.map((p: any) => ` - ${p.component}/${p.pin}`).join("\n"); const wireList = (result.wires ?? []) .map((w: any) => ` - (${w.start.x},${w.start.y}) → (${w.end.x},${w.end.y})`) .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.", { schematicPath: z.string().describe("Path to the schematic file"), - reference: z - .string() - .describe("Component reference designator (e.g. U1, R1, J2)"), + reference: z.string().describe("Component reference designator (e.g. U1, R1, J2)"), }, async (args: { schematicPath: string; reference: string }) => { 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; }) => { const result = await callKicadScript("connect_passthrough", args); - if ( - result.success !== false || - (result.connected && result.connected.length > 0) - ) { + if (result.success !== false || (result.connected && result.connected.length > 0)) { const lines: string[] = []; if (result.connected?.length) lines.push( `Connected (${result.connected.length}): ${result.connected.slice(0, 5).join(", ")}${result.connected.length > 5 ? " ..." : ""}`, ); if (result.failed?.length) - lines.push( - `Failed (${result.failed.length}): ${result.failed.join(", ")}`, - ); + lines.push(`Failed (${result.failed.length}): ${result.failed.join(", ")}`); return { - content: [ - { type: "text", text: result.message + "\n" + lines.join("\n") }, - ], + content: [{ type: "text", text: result.message + "\n" + lines.join("\n") }], }; } else { return { @@ -581,7 +560,10 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp filter: z .object({ 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() .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 conns = (n.connections || []) - .map((c: any) => `${c.component}/${c.pin}`) - .join(", "); + const conns = (n.connections || []).map((c: any) => `${c.component}/${c.pin}`).join(", "); return ` ${n.name}: ${conns || "(no connections)"}`; }); return { @@ -680,8 +660,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp }; } const lines = wires.map( - (w: any) => - ` (${w.start.x}, ${w.start.y}) → (${w.end.x}, ${w.end.y})`, + (w: any) => ` (${w.start.x}, ${w.start.y}) → (${w.end.x}, ${w.end.y})`, ); return { content: [ @@ -718,8 +697,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp }; } const lines = labels.map( - (l: any) => - ` [${l.type}] ${l.name} at (${l.position.x}, ${l.position.y})`, + (l: any) => ` [${l.type}] ${l.name} at (${l.position.x}, ${l.position.y})`, ); return { 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"), reference: z.string().describe("Reference designator (e.g., R1, U1)"), angle: z.number().describe("Rotation angle in degrees (0, 90, 180, 270)"), - mirror: z - .enum(["x", "y"]) - .optional() - .describe("Optional mirror axis"), + mirror: z.enum(["x", "y"]).optional().describe("Optional mirror axis"), }, async (args: { 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 || []; if (annotated.length === 0) { return { - content: [ - { type: "text", text: "All components are already annotated." }, - ], + content: [{ type: "text", text: "All components are already annotated." }], }; } - const lines = annotated.map( - (a: any) => ` ${a.oldReference} → ${a.newReference}`, - ); + const lines = annotated.map((a: any) => ` ${a.oldReference} → ${a.newReference}`); return { 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.", { schematicPath: z.string().describe("Path to the .kicad_sch file"), - start: z - .object({ x: z.number(), y: z.number() }) - .describe("Wire start position"), - end: z - .object({ x: z.number(), y: z.number() }) - .describe("Wire end position"), + start: z.object({ x: z.number(), y: z.number() }).describe("Wire start position"), + end: z.object({ x: z.number(), y: z.number() }).describe("Wire end position"), }, async (args: { 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"), outputPath: z.string().describe("Output SVG file path"), - blackAndWhite: z - .boolean() - .optional() - .describe("Export in black and white"), + blackAndWhite: z.boolean().optional().describe("Export in black and white"), }, - async (args: { - schematicPath: string; - outputPath: string; - blackAndWhite?: boolean; - }) => { + async (args: { schematicPath: string; outputPath: string; blackAndWhite?: boolean }) => { const result = await callKicadScript("export_schematic_svg", args); if (result.success) { 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"), outputPath: z.string().describe("Output PDF file path"), - blackAndWhite: z - .boolean() - .optional() - .describe("Export in black and white"), + blackAndWhite: z.boolean().optional().describe("Export in black and white"), }, - async (args: { - schematicPath: string; - outputPath: string; - blackAndWhite?: boolean; - }) => { + async (args: { schematicPath: string; outputPath: string; blackAndWhite?: boolean }) => { const result = await callKicadScript("export_schematic_pdf", args); if (result.success) { 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.", { schematicPath: z.string().describe("Path to the .kicad_sch file"), - format: z - .enum(["png", "svg"]) - .optional() - .describe("Output format (default: png)"), + format: z.enum(["png", "svg"]).optional().describe("Output format (default: png)"), width: z.number().optional().describe("Image width in pixels (default: 1200)"), 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", "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 - .string() - .describe("Path to the .kicad_sch schematic file"), + schematicPath: z.string().describe("Path to the .kicad_sch schematic file"), }, async (args: { schematicPath: string }) => { const result = await callKicadScript("run_erc", args); if (result.success) { const violations: any[] = result.violations || []; - const lines: string[] = [ - `ERC result: ${violations.length} violation(s)`, - ]; + const lines: string[] = [`ERC result: ${violations.length} violation(s)`]; if (result.summary?.by_severity) { const s = result.summary.by_severity; 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", "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 - .string() - .describe("Absolute path to the .kicad_sch schematic file"), - boardPath: z - .string() - .describe("Absolute path to the .kicad_pcb board file"), + schematicPath: z.string().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 }) => { 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: { schematicPath: string; - x1: number; y1: number; x2: number; y2: number; - format?: string; width?: number; height?: number; + x1: number; + y1: number; + x2: number; + y2: number; + format?: string; + width?: number; + height?: number; }) => { const result = await callKicadScript("get_schematic_view_region", args); 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: "image", - data: result.imageData, - mimeType: "image/png", - }], + content: [ + { + type: "image", + data: result.imageData, + mimeType: "image/png", + }, + ], }; } return { @@ -1240,14 +1189,18 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp }, ); - // Find overlapping elements server.tool( "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.", { 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 }) => { 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) { lines.push(`\nOverlapping symbols (${syms.length}):`); 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) { @@ -1271,7 +1226,9 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp if (wires.length) { lines.push(`\nOverlapping wires (${wires.length}):`); 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") }] }; @@ -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"), y2: z.number().describe("Bottom Y coordinate of the region in mm"), }, - async (args: { - schematicPath: string; - x1: number; y1: number; x2: number; y2: number; - }) => { + async (args: { schematicPath: string; x1: number; y1: number; x2: number; y2: number }) => { const result = await callKicadScript("get_elements_in_region", args); if (result.success) { 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 || []; if (syms.length) { lines.push("\nSymbols:"); syms.forEach((s: any) => { 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 || []; @@ -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:`]; collisions.slice(0, 30).forEach((c: any, i: number) => { 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`); diff --git a/src/tools/symbol-creator.ts b/src/tools/symbol-creator.ts index 046021e..d634407 100644 --- a/src/tools/symbol-creator.ts +++ b/src/tools/symbol-creator.ts @@ -15,45 +15,67 @@ const PinSchema = z.object({ number: z.union([z.string(), z.number()]).describe("Pin number, e.g. '1', '2', 'A1'"), type: z .enum([ - "input", "output", "bidirectional", "tri_state", "passive", - "free", "unspecified", "power_in", "power_out", - "open_collector", "open_emitter", "no_connect", + "input", + "output", + "bidirectional", + "tri_state", + "passive", + "free", + "unspecified", + "power_in", + "power_out", + "open_collector", + "open_emitter", + "no_connect", ]) .describe("Electrical pin type"), - at: z.object({ - x: z.number().describe("X position in mm"), - y: z.number().describe("Y position in mm"), - angle: z.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)"), + at: z + .object({ + x: z.number().describe("X position in mm"), + y: z.number().describe("Y position in mm"), + angle: z + .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)"), length: z.number().optional().describe("Pin length in mm (default 2.54)"), shape: z - .enum(["line", "inverted", "clock", "inverted_clock", "input_low", - "clock_low", "output_low", "falling_edge_clock", "non_logic"]) + .enum([ + "line", + "inverted", + "clock", + "inverted_clock", + "input_low", + "clock_low", + "output_low", + "falling_edge_clock", + "non_logic", + ]) .optional() .describe("Pin graphic shape (default: line)"), }); const RectSchema = z.object({ - x1: z.number(), y1: z.number(), - x2: z.number(), y2: z.number(), + x1: z.number(), + y1: z.number(), + x2: z.number(), + y2: z.number(), 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)"), }); const PolylineSchema = z.object({ - points: z.array(z.object({ x: z.number(), y: z.number() })) - .describe("List of XY points in mm"), + points: z.array(z.object({ x: z.number(), y: z.number() })).describe("List of XY points in mm"), width: z.number().optional().describe("Stroke width in mm (default 0.254)"), fill: z.enum(["none", "outline", "background"]).optional(), }); -export function registerSymbolCreatorTools( - server: McpServer, - callKicadScript: Function, -) { +export function registerSymbolCreatorTools(server: McpServer, callKicadScript: Function) { // ── create_symbol ────────────────────────────────────────────────────── // server.tool( "create_symbol", @@ -68,14 +90,14 @@ export function registerSymbolCreatorTools( "- 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", { - libraryPath: z - .string() - .describe("Path to the .kicad_sym file (created if missing)"), + libraryPath: z.string().describe("Path to the .kicad_sym file (created if missing)"), name: z.string().describe("Symbol name, e.g. 'TMC2209', 'MyOpAmp'"), referencePrefix: z .string() .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"), keywords: z.string().optional().describe("Space-separated search keywords"), 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. " + "Run this after create_symbol when KiCAD shows 'library not found'.", { - libraryPath: z - .string() - .describe("Full path to the .kicad_sym file"), + libraryPath: z.string().describe("Full path to the .kicad_sym file"), libraryName: z .string() .optional() diff --git a/src/tools/ui.ts b/src/tools/ui.ts index 8ce9d2a..561110b 100644 --- a/src/tools/ui.ts +++ b/src/tools/ui.ts @@ -1,48 +1,52 @@ -/** - * UI/Process management tools for KiCAD MCP server - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; -import { logger } from '../logger.js'; - -export function registerUITools(server: McpServer, callKicadScript: Function) { - // Check if KiCAD UI is running - server.tool( - "check_kicad_ui", - "Check if KiCAD UI is currently running", - {}, - async () => { - logger.info('Checking KiCAD UI status'); - const result = await callKicadScript("check_kicad_ui", {}); - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - // Launch KiCAD UI - server.tool( - "launch_kicad_ui", - "Launch KiCAD UI, optionally with a project file", - { - 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)") - }, - async (args: { projectPath?: string; autoLaunch?: boolean }) => { - logger.info(`Launching KiCAD UI${args.projectPath ? ' with project: ' + args.projectPath : ''}`); - const result = await callKicadScript("launch_kicad_ui", args); - return { - content: [{ - type: "text", - text: JSON.stringify(result, null, 2) - }] - }; - } - ); - - logger.info('UI management tools registered'); -} +/** + * UI/Process management tools for KiCAD MCP server + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import { logger } from "../logger.js"; + +export function registerUITools(server: McpServer, callKicadScript: Function) { + // Check if KiCAD UI is running + server.tool("check_kicad_ui", "Check if KiCAD UI is currently running", {}, async () => { + logger.info("Checking KiCAD UI status"); + const result = await callKicadScript("check_kicad_ui", {}); + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }); + + // Launch KiCAD UI + server.tool( + "launch_kicad_ui", + "Launch KiCAD UI, optionally with a project file", + { + 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)"), + }, + async (args: { projectPath?: string; autoLaunch?: boolean }) => { + logger.info( + `Launching KiCAD UI${args.projectPath ? " with project: " + args.projectPath : ""}`, + ); + const result = await callKicadScript("launch_kicad_ui", args); + return { + content: [ + { + type: "text", + text: JSON.stringify(result, null, 2), + }, + ], + }; + }, + ); + + logger.info("UI management tools registered"); +} diff --git a/src/utils/resource-helpers.ts b/src/utils/resource-helpers.ts index fa795c0..7c5c308 100644 --- a/src/utils/resource-helpers.ts +++ b/src/utils/resource-helpers.ts @@ -1,61 +1,71 @@ -/** - * Resource helper utilities for MCP resources - */ - -/** - * Create a JSON response for MCP resources - * - * @param data Data to serialize as JSON - * @param uri Optional URI for the resource - * @returns MCP resource response object - */ -export function createJsonResponse(data: any, uri?: string) { - return { - contents: [{ - uri: uri || "data:application/json", - mimeType: "application/json", - text: JSON.stringify(data, null, 2) - }] - }; -} - -/** - * Create a binary response for MCP resources - * - * @param data Binary data (Buffer or base64 string) - * @param mimeType MIME type of the binary data - * @param uri Optional URI for the resource - * @returns MCP resource response object - */ -export function createBinaryResponse(data: Buffer | string, mimeType: string, uri?: string) { - const blob = typeof data === 'string' ? data : data.toString('base64'); - - return { - contents: [{ - uri: uri || `data:${mimeType}`, - mimeType: mimeType, - blob: blob - }] - }; -} - -/** - * Create an error response for MCP resources - * - * @param error Error message - * @param details Optional error details - * @param uri Optional URI for the resource - * @returns MCP resource error response - */ -export function createErrorResponse(error: string, details?: string, uri?: string) { - return { - contents: [{ - uri: uri || "data:application/json", - mimeType: "application/json", - text: JSON.stringify({ - error, - details - }, null, 2) - }] - }; -} +/** + * Resource helper utilities for MCP resources + */ + +/** + * Create a JSON response for MCP resources + * + * @param data Data to serialize as JSON + * @param uri Optional URI for the resource + * @returns MCP resource response object + */ +export function createJsonResponse(data: any, uri?: string) { + return { + contents: [ + { + uri: uri || "data:application/json", + mimeType: "application/json", + text: JSON.stringify(data, null, 2), + }, + ], + }; +} + +/** + * Create a binary response for MCP resources + * + * @param data Binary data (Buffer or base64 string) + * @param mimeType MIME type of the binary data + * @param uri Optional URI for the resource + * @returns MCP resource response object + */ +export function createBinaryResponse(data: Buffer | string, mimeType: string, uri?: string) { + const blob = typeof data === "string" ? data : data.toString("base64"); + + return { + contents: [ + { + uri: uri || `data:${mimeType}`, + mimeType: mimeType, + blob: blob, + }, + ], + }; +} + +/** + * Create an error response for MCP resources + * + * @param error Error message + * @param details Optional error details + * @param uri Optional URI for the resource + * @returns MCP resource error response + */ +export function createErrorResponse(error: string, details?: string, uri?: string) { + return { + contents: [ + { + uri: uri || "data:application/json", + mimeType: "application/json", + text: JSON.stringify( + { + error, + details, + }, + null, + 2, + ), + }, + ], + }; +} diff --git a/tsconfig.json b/tsconfig.json index 8ef3a49..31fdce7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,14 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "NodeNext", - "moduleResolution": "NodeNext", - "esModuleInterop": true, - "strict": true, - "outDir": "dist", - "declaration": true, - "sourceMap": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -} +{ + "compilerOptions": { + "target": "ES2020", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "strict": true, + "outDir": "dist", + "declaration": true, + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}