#
tokens: 48848/50000 59/94 files (page 1/4)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 4. Use http://codebase.md/mixelpixx/kicad-mcp-server?page={x} to view the full context.

# Directory Structure

```
├── .github
│   └── workflows
│       └── ci.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CHANGELOG_2025-10-26.md
├── CHANGELOG_2025-11-01.md
├── CHANGELOG_2025-11-05.md
├── CHANGELOG_2025-11-30.md
├── config
│   ├── claude-desktop-config.json
│   ├── default-config.json
│   ├── linux-config.example.json
│   ├── macos-config.example.json
│   └── windows-config.example.json
├── CONTRIBUTING.md
├── docs
│   ├── BUILD_AND_TEST_SESSION.md
│   ├── CLIENT_CONFIGURATION.md
│   ├── IPC_API_MIGRATION_PLAN.md
│   ├── IPC_BACKEND_STATUS.md
│   ├── JLCPCB_INTEGRATION_PLAN.md
│   ├── KNOWN_ISSUES.md
│   ├── LIBRARY_INTEGRATION.md
│   ├── LINUX_COMPATIBILITY_AUDIT.md
│   ├── PLATFORM_GUIDE.md
│   ├── REALTIME_WORKFLOW.md
│   ├── ROADMAP.md
│   ├── STATUS_SUMMARY.md
│   ├── UI_AUTO_LAUNCH.md
│   ├── VISUAL_FEEDBACK.md
│   ├── WEEK1_SESSION1_SUMMARY.md
│   ├── WEEK1_SESSION2_SUMMARY.md
│   └── WINDOWS_TROUBLESHOOTING.md
├── LICENSE
├── package-json.json
├── package-lock.json
├── package.json
├── pytest.ini
├── python
│   ├── commands
│   │   ├── __init__.py
│   │   ├── board
│   │   │   ├── __init__.py
│   │   │   ├── layers.py
│   │   │   ├── outline.py
│   │   │   ├── size.py
│   │   │   └── view.py
│   │   ├── board.py
│   │   ├── component_schematic.py
│   │   ├── component.py
│   │   ├── connection_schematic.py
│   │   ├── design_rules.py
│   │   ├── export.py
│   │   ├── library_schematic.py
│   │   ├── library.py
│   │   ├── project.py
│   │   ├── routing.py
│   │   └── schematic.py
│   ├── kicad_api
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── factory.py
│   │   ├── ipc_backend.py
│   │   └── swig_backend.py
│   ├── kicad_interface.py
│   ├── requirements.txt
│   ├── resources
│   │   ├── __init__.py
│   │   └── resource_definitions.py
│   ├── schemas
│   │   ├── __init__.py
│   │   └── tool_schemas.py
│   ├── test_ipc_backend.py
│   └── utils
│       ├── __init__.py
│       ├── kicad_process.py
│       └── platform_helper.py
├── README.md
├── requirements-dev.txt
├── requirements.txt
├── scripts
│   ├── auto_refresh_kicad.sh
│   └── install-linux.sh
├── setup-windows.ps1
├── src
│   ├── config.ts
│   ├── index.ts
│   ├── kicad-server.ts
│   ├── logger.ts
│   ├── prompts
│   │   ├── component.ts
│   │   ├── design.ts
│   │   ├── index.ts
│   │   └── routing.ts
│   ├── resources
│   │   ├── board.ts
│   │   ├── component.ts
│   │   ├── index.ts
│   │   ├── library.ts
│   │   └── project.ts
│   ├── server.ts
│   ├── tools
│   │   ├── board.ts
│   │   ├── component.ts
│   │   ├── component.txt
│   │   ├── design-rules.ts
│   │   ├── export.ts
│   │   ├── index.ts
│   │   ├── library.ts
│   │   ├── project.ts
│   │   ├── routing.ts
│   │   ├── schematic.ts
│   │   └── ui.ts
│   └── utils
│       └── resource-helpers.ts
├── tests
│   ├── __init__.py
│   └── test_platform_helper.py
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
dist/
.npm
.eslintcache

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
.pytest_cache/
.coverage
htmlcov/
.tox/
.hypothesis/
*.cover
.mypy_cache/
.dmypy.json
dmypy.json

# Virtual Environments
venv/
env/
ENV/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Logs
logs/
*.log
~/.kicad-mcp/

# Environment
.env
.env.local
.env.*.local

# KiCAD
*.kicad_pcb-bak
*.kicad_sch-bak
*.kicad_pro-bak
*.kicad_prl
*-backups/
fp-info-cache

# Testing
test_output/
schematic_test_output/
coverage.xml
.coverage.*

# OS
Thumbs.db
Desktop.ini

```

--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------

```yaml
# Pre-commit hooks configuration
# See https://pre-commit.com for more information

repos:
  # Python code formatting
  - repo: https://github.com/psf/black
    rev: 23.7.0
    hooks:
      - id: black
        language_version: python3
        files: ^python/

  # Python import sorting
  - repo: https://github.com/pycqa/isort
    rev: 5.12.0
    hooks:
      - id: isort
        files: ^python/
        args: ["--profile", "black"]

  # Python type checking
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.5.0
    hooks:
      - id: mypy
        files: ^python/
        args: [--ignore-missing-imports]

  # Python linting
  - repo: https://github.com/pycqa/flake8
    rev: 6.1.0
    hooks:
      - id: flake8
        files: ^python/
        args: [--max-line-length=100, --extend-ignore=E203]

  # TypeScript/JavaScript formatting
  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.0.3
    hooks:
      - id: prettier
        types_or: [javascript, typescript, json, yaml, markdown]
        files: \.(ts|js|json|ya?ml|md)$

  # General file checks
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-json
      - id: check-added-large-files
        args: [--maxkb=500]
      - id: check-merge-conflict
      - id: detect-private-key

  # Python security checks
  - repo: https://github.com/PyCQA/bandit
    rev: 1.7.5
    hooks:
      - id: bandit
        args: [-c, pyproject.toml]
        files: ^python/

  # Markdown linting
  - repo: https://github.com/igorshubovych/markdownlint-cli
    rev: v0.37.0
    hooks:
      - id: markdownlint
        args: [--fix]

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# 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:**
- 52 fully-documented tools with JSON Schema validation
- 8 dynamic resources exposing project state
- 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

## What's New in v2.1.0

### 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.

### 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 52 tools organized into functional categories:

### Project Management (4 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

### Board Operations (9 tools)
- `set_board_size` - Configure PCB dimensions
- `add_board_outline` - Create board edge (rectangle, circle, polygon)
- `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
- `add_mounting_hole` - Place mounting holes
- `add_board_text` - Add text annotations

### Component Placement (10 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
- `get_component_properties` - Query component details
- `get_component_list` - List all placed components
- `place_component_array` - Create component grids/patterns
- `align_components` - Align multiple components
- `duplicate_component` - Copy existing component

### Routing & Nets (8 tools)
- `add_net` - Create electrical net
- `route_trace` - Route copper traces
- `add_via` - Place vias for layer transitions
- `delete_trace` - Remove traces
- `get_nets_list` - List all nets
- `create_netclass` - Define net class with rules
- `add_copper_pour` - Create copper zones/pours
- `route_differential_pair` - Route differential signals

### Library Management (4 tools)
- `list_libraries` - List available footprint libraries
- `search_footprints` - Search for footprints
- `list_library_footprints` - List footprints in library
- `get_footprint_info` - Get footprint details

### Design Rules (4 tools)
- `set_design_rules` - Configure DRC parameters
- `get_design_rules` - Retrieve current rules
- `run_drc` - Execute design rule check
- `get_drc_violations` - Get DRC error report

### Export (5 tools)
- `export_gerber` - Generate Gerber fabrication files
- `export_pdf` - Export PDF documentation
- `export_svg` - Create SVG vector graphics
- `export_3d` - Generate 3D models (STEP/VRML)
- `export_bom` - Produce bill of materials

### Schematic Design (6 tools)
- `create_schematic` - Initialize new schematic
- `load_schematic` - Open existing schematic
- `add_schematic_component` - Place symbols
- `add_schematic_wire` - Connect component pins
- `list_schematic_libraries` - List symbol libraries
- `export_schematic_pdf` - Export schematic PDF

### 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

```bash
# Install KiCAD 9.0 from kicad.org/download/macos

# Install Node.js
brew install node@20

# 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
```

## 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`

### 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.

## 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.
```

### 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.
```

## Architecture

### MCP Protocol Layer
- **JSON-RPC 2.0 Transport:** Bi-directional communication via STDIO
- **Protocol Version:** MCP 2025-06-18
- **Capabilities:** Tools (52), Resources (8)
- **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

### 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

### 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.1.0-alpha

**Working Features:**
- Project creation and management
- Board outline and sizing
- Layer management
- Component placement with footprint library loading
- Mounting holes and text annotations
- Design rule checking
- Export to Gerber, PDF, SVG, 3D
- Schematic creation and editing
- UI auto-launch
- Full MCP protocol compliance

**Under Active Development (IPC Backend):**
- Real-time UI synchronization via KiCAD 9.0 IPC API
- IPC-enabled commands: route_trace, add_via, place_component, move_component, delete_component, add_copper_pour, refill_zones, add_board_outline, add_mounting_hole, and more
- Hybrid footprint loading (SWIG for library access, IPC for placement)
- Zone/copper pour support via IPC

Note: IPC features are experimental and under testing. Some commands may not work as expected in all scenarios.

**Planned:**
- JLCPCB parts integration
- Digikey API integration
- Advanced routing algorithms
- Smart BOM management
- AI-assisted component selection
- Design pattern library (Arduino shields, RPi HATs)

See [ROADMAP.md](docs/ROADMAP.md) for detailed development timeline.

## 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

## 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.1.0-alpha}
}
```


```

--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
# 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)
- [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
```

---

## 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!

```

--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------

```python
"""Tests for KiCAD MCP Server"""

```

--------------------------------------------------------------------------------
/python/utils/__init__.py:
--------------------------------------------------------------------------------

```python
"""Utility modules for KiCAD MCP Server"""

```

--------------------------------------------------------------------------------
/python/schemas/__init__.py:
--------------------------------------------------------------------------------

```python
"""
Tool schema definitions for KiCAD MCP Server
"""

from .tool_schemas import TOOL_SCHEMAS

__all__ = ['TOOL_SCHEMAS']

```

--------------------------------------------------------------------------------
/python/requirements.txt:
--------------------------------------------------------------------------------

```
# KiCAD MCP Python Interface Requirements

# Image processing
Pillow>=9.0.0
cairosvg>=2.7.0

# Type hints
typing-extensions>=4.0.0

# Logging
colorlog>=6.7.0

kicad-skip

```

--------------------------------------------------------------------------------
/config/default-config.json:
--------------------------------------------------------------------------------

```json
{
  "name": "kicad-mcp-server",
  "version": "1.0.0",
  "description": "MCP server for KiCAD PCB design operations",
  "pythonPath": "",
  "kicadPath": "",
  "logLevel": "info",
  "logDir": ""
}

```

--------------------------------------------------------------------------------
/python/resources/__init__.py:
--------------------------------------------------------------------------------

```python
"""
Resource definitions for KiCAD MCP Server
"""

from .resource_definitions import RESOURCE_DEFINITIONS, handle_resource_read

__all__ = ['RESOURCE_DEFINITIONS', 'handle_resource_read']

```

--------------------------------------------------------------------------------
/src/prompts/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Prompts index for KiCAD MCP server
 * 
 * Exports all prompt registration functions
 */

export { registerComponentPrompts } from './component.js';
export { registerRoutingPrompts } from './routing.js';
export { registerDesignPrompts } from './design.js';

```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "dist",
    "declaration": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

```

--------------------------------------------------------------------------------
/config/claude-desktop-config.json:
--------------------------------------------------------------------------------

```json
{
  "mcpServers": {
    "kicad_helper": {
      "command": "node",
      "args": ["dist/index.js"],
      "cwd": "c:/repo/KiCAD-MCP",
      "env": {
        "NODE_ENV": "production",
        "PYTHONPATH": "C:/Program Files/KiCad/9.0/lib/python3/dist-packages"
      },
      "description": "KiCAD PCB Design Assistant"
    }
  }
}

```

--------------------------------------------------------------------------------
/python/commands/board.py:
--------------------------------------------------------------------------------

```python
"""
Board-related command implementations for KiCAD interface

This file is maintained for backward compatibility.
It imports and re-exports the BoardCommands class from the board package.
"""

from commands.board import BoardCommands

# Re-export the BoardCommands class for backward compatibility
__all__ = ['BoardCommands']

```

--------------------------------------------------------------------------------
/src/resources/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * 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';

```

--------------------------------------------------------------------------------
/python/commands/__init__.py:
--------------------------------------------------------------------------------

```python
"""
KiCAD command implementations package
"""

from .project import ProjectCommands
from .board import BoardCommands
from .component import ComponentCommands
from .routing import RoutingCommands
from .design_rules import DesignRuleCommands
from .export import ExportCommands

__all__ = [
    'ProjectCommands',
    'BoardCommands',
    'ComponentCommands',
    'RoutingCommands',
    'DesignRuleCommands',
    'ExportCommands'
]

```

--------------------------------------------------------------------------------
/config/windows-config.example.json:
--------------------------------------------------------------------------------

```json
{
  "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"
      },
      "description": "KiCAD PCB Design Assistant - Note: PYTHONPATH auto-detected if venv exists"
    }
  }
}

```

--------------------------------------------------------------------------------
/config/linux-config.example.json:
--------------------------------------------------------------------------------

```json
{
  "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"
    }
  }
}

```

--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------

```
# KiCAD MCP Server - Development Dependencies
# Testing, linting, and development tools

# Include production dependencies
-r requirements.txt

# Testing framework
pytest>=7.4.0
pytest-cov>=4.1.0
pytest-asyncio>=0.21.0
pytest-mock>=3.11.0

# Code quality
black>=23.7.0
mypy>=1.5.0
pylint>=2.17.0
flake8>=6.1.0
isort>=5.12.0

# Type stubs
types-requests>=2.31.0
types-Pillow>=10.0.0

# Pre-commit hooks
pre-commit>=3.3.0

# Development utilities
ipython>=8.14.0
ipdb>=0.13.13

```

--------------------------------------------------------------------------------
/config/macos-config.example.json:
--------------------------------------------------------------------------------

```json
{
  "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"
    }
  }
}

```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
# KiCAD MCP Server - Python Dependencies
# Production dependencies only

# KiCAD Python API (IPC - for future migration)
# kicad-python>=0.5.0  # Uncomment when migrating to IPC API

# Schematic manipulation
kicad-skip>=0.1.0

# Image processing for board rendering
Pillow>=9.0.0

# SVG rendering
cairosvg>=2.7.0

# Colored logging
colorlog>=6.7.0

# Data validation (for future features)
pydantic>=2.5.0

# HTTP requests (for JLCPCB/Digikey APIs - future)
requests>=2.32.5

# Environment variable management
python-dotenv>=1.0.0

```

--------------------------------------------------------------------------------
/src/tools/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Tools index for KiCAD MCP server
 * 
 * Exports all tool registration functions
 */

export { registerProjectTools } from './project.js';
export { registerBoardTools } from './board.js';
export { registerComponentTools } from './component.js';
export { registerRoutingTools } from './routing.js';
export { registerDesignRuleTools } from './design-rules.js';
export { registerExportTools } from './export.js';
export { registerSchematicTools } from './schematic.js';
export { registerLibraryTools } from './library.js';
export { registerUITools } from './ui.js';

```

--------------------------------------------------------------------------------
/scripts/auto_refresh_kicad.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash
# Auto-refresh KiCAD when .kicad_pcb files change
# Usage: ./auto_refresh_kicad.sh /path/to/project.kicad_pcb

if [ -z "$1" ]; then
    echo "Usage: $0 <path-to-kicad-pcb-file>"
    exit 1
fi

PCB_FILE="$1"

if [ ! -f "$PCB_FILE" ]; then
    echo "Error: File not found: $PCB_FILE"
    exit 1
fi

echo "Monitoring: $PCB_FILE"
echo "When changes are saved, KiCAD will detect them and prompt to reload."
echo "Press Ctrl+C to stop monitoring."

# Watch for file changes
inotifywait -m -e modify "$PCB_FILE" |
while read path action file; do
    echo "[$(date '+%H:%M:%S')] File changed - KiCAD should prompt to reload"
    # KiCAD automatically detects file changes in most versions
done

```

--------------------------------------------------------------------------------
/package-json.json:
--------------------------------------------------------------------------------

```json
{
  "name": "kicad-mcp",
  "version": "1.0.0",
  "description": "Model Context Protocol server for KiCAD PCB design",
  "type": "module",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc -w & nodemon dist/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "kicad",
    "mcp",
    "model-context-protocol",
    "pcb-design",
    "ai",
    "claude"
  ],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.10.0",
    "dotenv": "^16.0.3",
    "zod": "^3.22.2"
  },
  "devDependencies": {
    "@types/node": "^20.5.6",
    "nodemon": "^3.0.1",
    "typescript": "^5.2.2"
  }
}

```

--------------------------------------------------------------------------------
/python/kicad_api/__init__.py:
--------------------------------------------------------------------------------

```python
"""
KiCAD API Abstraction Layer

This module provides a unified interface to KiCAD's Python APIs,
supporting both the legacy SWIG bindings and the new IPC API.

Usage:
    from kicad_api import create_backend

    # Auto-detect best available backend
    backend = create_backend()

    # Or specify explicitly
    backend = create_backend('ipc')  # Use IPC API
    backend = create_backend('swig')  # Use legacy SWIG

    # Connect and use
    if backend.connect():
        board = backend.get_board()
        board.set_size(100, 80)
"""

from kicad_api.factory import create_backend
from kicad_api.base import KiCADBackend

__all__ = ['create_backend', 'KiCADBackend']
__version__ = '2.0.0-alpha.1'

```

--------------------------------------------------------------------------------
/src/tools/component.txt:
--------------------------------------------------------------------------------

```
/**
 * Component management tools for KiCAD MCP server
 */

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: any) => Promise<any>;

/**
 * Register component management tools with the MCP server
 * 
 * @param server MCP server instance
 * @param callKicadScript Function to call KiCAD script commands
 */
export function registerComponentTools(server: McpServer, callKicadScript: CommandFunction): void {
  logger.info('Registering component management tools');
  
  // ------------------------------------------------------
  // Place Component Tool
  // ------------------------------------------------------
  server.registerTool({
    name: "place_component",
    description: "Places a component on the PCB at the specified location",
```

--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------

```
[pytest]
# Pytest configuration for KiCAD MCP Server

# Test discovery patterns
python_files = test_*.py *_test.py
python_classes = Test*
python_functions = test_*

# Test paths
testpaths = tests python/tests

# Minimum Python version
minversion = 6.0

# Additional options
addopts =
    -ra
    --strict-markers
    --strict-config
    --showlocals
    --tb=short
    --cov=python
    --cov-report=term-missing
    --cov-report=html
    --cov-report=xml
    --cov-branch

# Markers for organizing tests
markers =
    unit: Unit tests (fast, no external dependencies)
    integration: Integration tests (requires KiCAD)
    slow: Slow-running tests
    linux: Linux-specific tests
    windows: Windows-specific tests
    macos: macOS-specific tests

# Ignore patterns
norecursedirs = .git .tox dist build *.egg node_modules

# Coverage settings
[coverage:run]
source = python
omit =
    */tests/*
    */test_*.py
    */__pycache__/*
    */site-packages/*

[coverage:report]
precision = 2
show_missing = True
skip_covered = False

```

--------------------------------------------------------------------------------
/src/tools/ui.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * 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');
}

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "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"
  }
}

```

--------------------------------------------------------------------------------
/src/utils/resource-helpers.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * 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)
    }]
  };
}

```

--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * 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';

// 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');

/**
 * 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'),
  pythonPath: z.string().optional(),
  kicadPath: z.string().optional(),
  logLevel: z.enum(['error', 'warn', 'info', 'debug']).default('info'),
  logDir: z.string().optional()
});

/**
 * Server configuration type
 */
export type Config = z.infer<typeof ConfigSchema>;

/**
 * Load configuration from file
 * 
 * @param configPath Path to the configuration file (optional)
 * @returns Loaded and validated configuration
 */
export async function loadConfig(configPath?: string): Promise<Config> {
  try {
    // Determine which config file to load
    const filePath = configPath || DEFAULT_CONFIG_PATH;
    
    // Check if file exists
    if (!existsSync(filePath)) {
      logger.warn(`Configuration file not found: ${filePath}, using defaults`);
      return ConfigSchema.parse({});
    }
    
    // Read and parse configuration
    const configData = await readFile(filePath, 'utf-8');
    const config = JSON.parse(configData);
    
    // Validate configuration
    return ConfigSchema.parse(config);
  } catch (error) {
    logger.error(`Error loading configuration: ${error}`);
    
    // Return default configuration
    return ConfigSchema.parse({});
  }
}

```

--------------------------------------------------------------------------------
/src/tools/project.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * 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)
        }]
      };
    }
  );
}

```

--------------------------------------------------------------------------------
/python/commands/board/size.py:
--------------------------------------------------------------------------------

```python
"""
Board size command implementations for KiCAD interface
"""

import pcbnew
import logging
from typing import Dict, Any, Optional

logger = logging.getLogger('kicad_interface')

class BoardSizeCommands:
    """Handles board size operations"""

    def __init__(self, board: Optional[pcbnew.BOARD] = None):
        """Initialize with optional board instance"""
        self.board = board

    def set_board_size(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Set the size of the PCB board by creating edge cuts outline"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            width = params.get("width")
            height = params.get("height")
            unit = params.get("unit", "mm")

            if width is None or height is None:
                return {
                    "success": False,
                    "message": "Missing dimensions",
                    "errorDetails": "Both width and height are required"
                }

            # Create board outline using BoardOutlineCommands
            # This properly creates edge cuts on Edge.Cuts layer
            from commands.board.outline import BoardOutlineCommands
            outline_commands = BoardOutlineCommands(self.board)

            # Create rectangular outline centered at origin
            result = outline_commands.add_board_outline({
                "shape": "rectangle",
                "centerX": width / 2,      # Center X
                "centerY": height / 2,     # Center Y
                "width": width,
                "height": height,
                "unit": unit
            })

            if result.get("success"):
                return {
                    "success": True,
                    "message": f"Created board outline: {width}x{height} {unit}",
                    "size": {
                        "width": width,
                        "height": height,
                        "unit": unit
                    }
                }
            else:
                return result

        except Exception as e:
            logger.error(f"Error setting board size: {str(e)}")
            return {
                "success": False,
                "message": "Failed to set board size",
                "errorDetails": str(e)
            }

```

--------------------------------------------------------------------------------
/src/logger.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Logger for KiCAD MCP server
 */

import { existsSync, mkdirSync, appendFileSync } from 'fs';
import { join } from 'path';
import * as os from 'os';

// Log levels
type LogLevel = 'error' | 'warn' | 'info' | 'debug';

// Default log directory
const DEFAULT_LOG_DIR = join(os.homedir(), '.kicad-mcp', 'logs');

/**
 * Logger class for KiCAD MCP server
 */
class Logger {
  private logLevel: LogLevel = 'info';
  private logDir: string = DEFAULT_LOG_DIR;
  
  /**
   * Set the log level
   * @param level Log level to set
   */
  setLogLevel(level: LogLevel): void {
    this.logLevel = level;
  }
  
  /**
   * Set the log directory
   * @param dir Directory to store log files
   */
  setLogDir(dir: string): void {
    this.logDir = dir;
    
    // Ensure log directory exists
    if (!existsSync(this.logDir)) {
      mkdirSync(this.logDir, { recursive: true });
    }
  }
  
  /**
   * Log an error message
   * @param message Message to log
   */
  error(message: string): void {
    this.log('error', message);
  }
  
  /**
   * Log a warning message
   * @param message Message to log
   */
  warn(message: string): void {
    if (['error', 'warn', 'info', 'debug'].includes(this.logLevel)) {
      this.log('warn', message);
    }
  }
  
  /**
   * Log an info message
   * @param message Message to log
   */
  info(message: string): void {
    if (['info', 'debug'].includes(this.logLevel)) {
      this.log('info', message);
    }
  }
  
  /**
   * Log a debug message
   * @param message Message to log
   */
  debug(message: string): void {
    if (this.logLevel === 'debug') {
      this.log('debug', message);
    }
  }
  
  /**
   * Log a message with the specified level
   * @param level Log level
   * @param message Message to log
   */
  private log(level: LogLevel, message: string): void {
    const timestamp = new Date().toISOString();
    const formattedMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;

    // Log to console.error (stderr) only - stdout is reserved for MCP protocol
    // All log levels go to stderr to avoid corrupting STDIO MCP transport
    console.error(formattedMessage);
    
    // Log to file
    try {
      // Ensure log directory exists
      if (!existsSync(this.logDir)) {
        mkdirSync(this.logDir, { recursive: true });
      }
      
      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}`);
    }
  }
}

// Create and export logger instance
export const logger = new Logger();

```

--------------------------------------------------------------------------------
/src/tools/routing.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Routing tools for KiCAD MCP server
 */

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

export function registerRoutingTools(server: McpServer, callKicadScript: Function) {
  // Add net tool
  server.tool(
    "add_net",
    "Create a new net on the PCB",
    {
      name: z.string().describe("Net name"),
      netClass: z.string().optional().describe("Net class name"),
    },
    async (args: { name: string; netClass?: string }) => {
      const result = await callKicadScript("add_net", args);
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result, null, 2)
        }]
      };
    }
  );

  // Route trace tool
  server.tool(
    "route_trace",
    "Route a trace between two points",
    {
      start: z.object({
        x: z.number(),
        y: z.number(),
        unit: z.string().optional()
      }).describe("Start position"),
      end: z.object({
        x: z.number(),
        y: z.number(),
        unit: z.string().optional()
      }).describe("End position"),
      layer: z.string().describe("PCB layer"),
      width: z.number().describe("Trace width in mm"),
      net: z.string().describe("Net name"),
    },
    async (args: any) => {
      const result = await callKicadScript("route_trace", args);
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result, null, 2)
        }]
      };
    }
  );

  // Add via tool
  server.tool(
    "add_via",
    "Add a via to the PCB",
    {
      position: z.object({
        x: z.number(),
        y: z.number(),
        unit: z.string().optional()
      }).describe("Via position"),
      net: z.string().describe("Net name"),
      viaType: z.string().optional().describe("Via type (through, blind, buried)"),
    },
    async (args: any) => {
      const result = await callKicadScript("add_via", args);
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result, null, 2)
        }]
      };
    }
  );

  // Add copper pour tool
  server.tool(
    "add_copper_pour",
    "Add a copper pour (ground/power plane) to the PCB",
    {
      layer: z.string().describe("PCB layer"),
      net: z.string().describe("Net name"),
      clearance: z.number().optional().describe("Clearance in mm"),
    },
    async (args: any) => {
      const result = await callKicadScript("add_copper_pour", args);
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result, null, 2)
        }]
      };
    }
  );
}

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * KiCAD Model Context Protocol Server
 * 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';

// Get the current directory
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

/**
 * Main function to start the KiCAD MCP server
 */
async function main() {
  try {
    // Parse command line arguments
    const args = process.argv.slice(2);
    const options = parseCommandLineArgs(args);
    
    // Load configuration
    const config = await loadConfig(options.configPath);
    
    // Path to the Python script that interfaces with KiCAD
    const kicadScriptPath = join(dirname(__dirname), 'python', 'kicad_interface.py');
    
    // Create the server
    const server = new KiCADMcpServer(
      kicadScriptPath,
      config.logLevel
    );
    
    // Start the server
    await server.start();
    
    // Setup graceful shutdown
    setupGracefulShutdown(server);
    
    logger.info('KiCAD MCP server started with STDIO transport');
    
  } catch (error) {
    logger.error(`Failed to start KiCAD MCP server: ${error}`);
    process.exit(1);
  }
}

/**
 * Parse command line arguments
 */
function parseCommandLineArgs(args: string[]) {
  let configPath = undefined;
  
  for (let i = 0; i < args.length; i++) {
    if (args[i] === '--config' && i + 1 < args.length) {
      configPath = args[i + 1];
      i++;
    }
  }
  
  return { configPath };
}

/**
 * Setup graceful shutdown handlers
 */
function setupGracefulShutdown(server: KiCADMcpServer) {
  // Handle termination signals
  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...');
    await shutdownServer(server);
  });
  
  // Handle uncaught exceptions
  process.on('uncaughtException', async (error) => {
    logger.error(`Uncaught exception: ${error}`);
    await shutdownServer(server);
  });
  
  // Handle unhandled promise rejections
  process.on('unhandledRejection', async (reason) => {
    logger.error(`Unhandled promise rejection: ${reason}`);
    await shutdownServer(server);
  });
}

/**
 * Shut down the server and exit
 */
async function shutdownServer(server: KiCADMcpServer) {
  try {
    logger.info('Shutting down KiCAD MCP server...');
    await server.stop();
    logger.info('Server shutdown complete. Exiting...');
    process.exit(0);
  } catch (error) {
    logger.error(`Error during shutdown: ${error}`);
    process.exit(1);
  }
}

// Run the main function - always run when imported as module entry point
// The import.meta.url check was failing on Windows due to path separators
main().catch((error) => {
  console.error(`Unhandled error in main: ${error}`);
  process.exit(1);
});

// For testing and programmatic usage
export { KiCADMcpServer };

```

--------------------------------------------------------------------------------
/CHANGELOG_2025-11-30.md:
--------------------------------------------------------------------------------

```markdown
# Changelog - 2025-11-30

## IPC Backend Implementation - Real-time UI Synchronization

This release implements the **KiCAD IPC API backend**, enabling real-time UI synchronization between the MCP server and KiCAD. Changes made through MCP tools now appear **instantly** in the KiCAD UI without requiring manual reload.

### Major Features

#### Real-time UI Sync via IPC API
- **Instant updates**: Tracks, vias, components, and text appear immediately in KiCAD
- **No reload required**: Eliminates the manual File > Reload workflow
- **Transaction support**: Operations can be grouped for single undo/redo steps
- **Auto-detection**: Server automatically uses IPC when KiCAD is running with IPC enabled

#### Automatic Backend Selection
- IPC backend is now the **default** when available
- Transparent fallback to SWIG when IPC unavailable
- Environment variable `KICAD_BACKEND` for explicit control:
  - `auto` (default): Try IPC first, fall back to SWIG
  - `ipc`: Force IPC only
  - `swig`: Force SWIG only (deprecated)

#### Commands with IPC Support
The following commands now automatically use IPC for real-time updates:

| Command | Description |
|---------|-------------|
| `route_trace` | Add traces with instant UI update |
| `add_via` | Add vias with instant UI update |
| `add_text` / `add_board_text` | Add text with instant UI update |
| `set_board_size` | Set board size with instant outline update |
| `get_board_info` | Read live board data |
| `place_component` | Place components with instant UI update |
| `move_component` | Move components with instant UI update |
| `delete_component` | Delete components with instant UI update |
| `get_component_list` | Read live component list |
| `save_project` | Save via IPC |

### New Files

- `python/kicad_api/ipc_backend.py` - Complete IPC backend implementation (~870 lines)
- `python/test_ipc_backend.py` - Test script for IPC functionality
- `docs/IPC_BACKEND_STATUS.md` - Implementation status documentation

### Modified Files

- `python/kicad_interface.py` - Added IPC integration and automatic command routing
- `python/kicad_api/base.py` - Added routing and transaction methods to base class
- `python/kicad_api/factory.py` - Fixed kipy module detection
- `docs/ROADMAP.md` - Updated Week 3 status to complete

### Dependencies

- Added `kicad-python>=0.5.0` - Official KiCAD IPC API Python library

### Requirements

To use real-time mode:
1. KiCAD 9.0+ must be running
2. Enable IPC API: `Preferences > Plugins > Enable IPC API Server`
3. Have a board open in PCB editor

### Deprecation Notice

The **SWIG backend is now deprecated**:
- Will continue to work as fallback
- No new features will be added to SWIG path
- Will be removed when KiCAD 10.0 drops SWIG support

### Testing

Run the IPC test script:
```bash
./venv/bin/python python/test_ipc_backend.py
```

Or test individual commands:
```bash
echo '{"command": "get_backend_info", "params": {}}' | \
  PYTHONPATH=python ./venv/bin/python python/kicad_interface.py
```

### Breaking Changes

None. All existing commands continue to work. IPC is used transparently when available.

---

**Version:** 2.1.0-alpha
**Date:** 2025-11-30

```

--------------------------------------------------------------------------------
/python/commands/board/__init__.py:
--------------------------------------------------------------------------------

```python
"""
Board-related command implementations for KiCAD interface
"""

import pcbnew
import logging
from typing import Dict, Any, Optional

# Import specialized modules
from .size import BoardSizeCommands
from .layers import BoardLayerCommands
from .outline import BoardOutlineCommands
from .view import BoardViewCommands

logger = logging.getLogger('kicad_interface')

class BoardCommands:
    """Handles board-related KiCAD operations"""

    def __init__(self, board: Optional[pcbnew.BOARD] = None):
        """Initialize with optional board instance"""
        self.board = board
        
        # Initialize specialized command classes
        self.size_commands = BoardSizeCommands(board)
        self.layer_commands = BoardLayerCommands(board)
        self.outline_commands = BoardOutlineCommands(board)
        self.view_commands = BoardViewCommands(board)
    
    # Delegate board size commands
    def set_board_size(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Set the size of the PCB board"""
        self.size_commands.board = self.board
        return self.size_commands.set_board_size(params)
    
    # Delegate layer commands
    def add_layer(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Add a new layer to the PCB"""
        self.layer_commands.board = self.board
        return self.layer_commands.add_layer(params)
    
    def set_active_layer(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Set the active layer for PCB operations"""
        self.layer_commands.board = self.board
        return self.layer_commands.set_active_layer(params)
    
    def get_layer_list(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get a list of all layers in the PCB"""
        self.layer_commands.board = self.board
        return self.layer_commands.get_layer_list(params)
    
    # Delegate board outline commands
    def add_board_outline(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Add a board outline to the PCB"""
        self.outline_commands.board = self.board
        return self.outline_commands.add_board_outline(params)
    
    def add_mounting_hole(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Add a mounting hole to the PCB"""
        self.outline_commands.board = self.board
        return self.outline_commands.add_mounting_hole(params)
    
    def add_text(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Add text annotation to the PCB"""
        self.outline_commands.board = self.board
        return self.outline_commands.add_text(params)
    
    # Delegate view commands
    def get_board_info(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get information about the current board"""
        self.view_commands.board = self.board
        return self.view_commands.get_board_info(params)
    
    def get_board_2d_view(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get a 2D image of the PCB"""
        self.view_commands.board = self.board
        return self.view_commands.get_board_2d_view(params)

    def get_board_extents(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get the bounding box extents of the board"""
        self.view_commands.board = self.board
        return self.view_commands.get_board_extents(params)

```

--------------------------------------------------------------------------------
/python/commands/schematic.py:
--------------------------------------------------------------------------------

```python
from skip import Schematic
import os
import logging

logger = logging.getLogger('kicad_interface')

class SchematicManager:
    """Core schematic operations using kicad-skip"""

    @staticmethod
    def create_schematic(name, metadata=None):
        """Create a new empty schematic"""
        # kicad-skip requires a filepath to create a schematic
        # We'll create a blank schematic file by loading an existing file
        # or we can create a template file first.
        
        # Create an empty template file first
        temp_path = f"{name}_template.kicad_sch"
        with open(temp_path, 'w') as f:
            # Write minimal schematic file content
            f.write("(kicad_sch (version 20230121) (generator \"KiCAD-MCP-Server\"))\n")
        
        # Now load it
        sch = Schematic(temp_path)
        sch.version = "20230121"  # Set appropriate version
        sch.generator = "KiCAD-MCP-Server"
        
        # Clean up the template
        os.remove(temp_path)
        # Add metadata if provided
        if metadata:
            for key, value in metadata.items():
                 # kicad-skip doesn't have a direct metadata property on Schematic,
                 # but we can add properties to the root sheet if needed, or
                 # include it in the file path/name convention.
                 # For now, we'll just create the schematic.
                 pass # Placeholder for potential metadata handling

        logger.info(f"Created new schematic: {name}")
        return sch

    @staticmethod
    def load_schematic(file_path):
        """Load an existing schematic"""
        if not os.path.exists(file_path):
            logger.error(f"Schematic file not found at {file_path}")
            return None
        try:
            sch = Schematic(file_path)
            logger.info(f"Loaded schematic from: {file_path}")
            return sch
        except Exception as e:
            logger.error(f"Error loading schematic from {file_path}: {e}")
            return None

    @staticmethod
    def save_schematic(schematic, file_path):
        """Save a schematic to file"""
        try:
            # kicad-skip uses write method, not save
            schematic.write(file_path)
            logger.info(f"Saved schematic to: {file_path}")
            return True
        except Exception as e:
            logger.error(f"Error saving schematic to {file_path}: {e}")
            return False

    @staticmethod
    def get_schematic_metadata(schematic):
        """Extract metadata from schematic"""
        # kicad-skip doesn't expose a direct metadata object on Schematic.
        # We can return basic info like version and generator.
        metadata = {
            "version": schematic.version,
            "generator": schematic.generator,
            # Add other relevant properties if needed
        }
        logger.debug("Extracted schematic metadata")
        return metadata

if __name__ == '__main__':
    # Example Usage (for testing)
    # Create a new schematic
    new_sch = SchematicManager.create_schematic("MyTestSchematic")

    # Save the schematic
    test_file = "test_schematic.kicad_sch"
    SchematicManager.save_schematic(new_sch, test_file)

    # Load the schematic
    loaded_sch = SchematicManager.load_schematic(test_file)
    if loaded_sch:
        metadata = SchematicManager.get_schematic_metadata(loaded_sch)
        print(f"Loaded schematic metadata: {metadata}")

    # Clean up test file
    if os.path.exists(test_file):
        os.remove(test_file)
        print(f"Cleaned up {test_file}")

```

--------------------------------------------------------------------------------
/src/tools/library.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Library tools for KiCAD MCP server
 * Provides access to KiCAD footprint libraries and symbols
 */

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

export function registerLibraryTools(server: McpServer, callKicadScript: Function) {
  // List available footprint libraries
  server.tool(
    "list_libraries",
    "List all available KiCAD footprint libraries",
    {
      search_paths: z.array(z.string()).optional()
        .describe("Optional additional search paths for libraries")
    },
    async (args: { search_paths?: string[] }) => {
      const result = await callKicadScript("list_libraries", args);
      if (result.success && result.libraries) {
        return {
          content: [
            {
              type: "text",
              text: `Found ${result.libraries.length} footprint libraries:\n${result.libraries.join('\n')}`
            }
          ]
        };
      }
      return {
        content: [
          {
            type: "text",
            text: `Failed to list libraries: ${result.message || 'Unknown error'}`
          }
        ]
      };
    }
  );

  // Search for footprints across all libraries
  server.tool(
    "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")
    },
    async (args: { search_term: string; library?: string; limit?: number }) => {
      const result = await callKicadScript("search_footprints", args);
      if (result.success && result.footprints) {
        const footprintList = result.footprints.map((fp: any) =>
          `${fp.library}:${fp.name}${fp.description ? ' - ' + fp.description : ''}`
        ).join('\n');
        return {
          content: [
            {
              type: "text",
              text: `Found ${result.footprints.length} matching footprints:\n${footprintList}`
            }
          ]
        };
      }
      return {
        content: [
          {
            type: "text",
            text: `Failed to search footprints: ${result.message || 'Unknown error'}`
          }
        ]
      };
    }
  );

  // List footprints in a specific library
  server.tool(
    "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")
    },
    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');
        return {
          content: [
            {
              type: "text",
              text: `Library ${args.library_name} contains ${result.footprints.length} footprints:\n${footprintList}`
            }
          ]
        };
      }
      return {
        content: [
          {
            type: "text",
            text: `Failed to list footprints in library ${args.library_name}: ${result.message || 'Unknown error'}`
          }
        ]
      };
    }
  );

  // Get detailed information about a specific footprint
  server.tool(
    "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")
    },
    async (args: { library_name: string; footprint_name: string }) => {
      const result = await callKicadScript("get_footprint_info", args);
      if (result.success && result.info) {
        const info = result.info;
        const details = [
          `Footprint: ${info.name}`,
          `Library: ${info.library}`,
          info.description ? `Description: ${info.description}` : '',
          info.keywords ? `Keywords: ${info.keywords}` : '',
          info.pads ? `Number of pads: ${info.pads}` : '',
          info.layers ? `Layers used: ${info.layers.join(', ')}` : '',
          info.courtyard ? `Courtyard size: ${info.courtyard.width}mm x ${info.courtyard.height}mm` : '',
          info.attributes ? `Attributes: ${JSON.stringify(info.attributes)}` : ''
        ].filter(line => line).join('\n');

        return {
          content: [
            {
              type: "text",
              text: details
            }
          ]
        };
      }
      return {
        content: [
          {
            type: "text",
            text: `Failed to get footprint info: ${result.message || 'Unknown error'}`
          }
        ]
      };
    }
  );
}
```

--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------

```yaml
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 "✗ {}"'

```

--------------------------------------------------------------------------------
/docs/KNOWN_ISSUES.md:
--------------------------------------------------------------------------------

```markdown
# Known Issues & Workarounds

**Last Updated:** 2025-12-02
**Version:** 2.1.0-alpha

This document tracks known issues and provides workarounds where available.

---

## Current Issues

### 1. `get_board_info` KiCAD 9.0 API Issue

**Status:** KNOWN - Non-critical

**Symptoms:**
```
AttributeError: 'BOARD' object has no attribute 'LT_USER'
```

**Root Cause:** KiCAD 9.0 changed layer enumeration constants

**Workaround:** Use `get_project_info` instead for basic project details

**Impact:** Low - informational command only

---

### 2. Zone Filling via SWIG Causes Segfault

**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

**Impact:** Medium - affects copper pour visualization until opened in KiCAD

---

### 3. UI Manual Reload Required (SWIG Backend)

**Status:** BY DESIGN - Fixed by IPC

**Symptoms:**
- MCP makes changes via SWIG backend
- KiCAD doesn't show changes until file is reloaded

**Current Workflow:**
```
1. MCP makes change via SWIG
2. KiCAD shows: "File has been modified. Reload? [Yes] [No]"
3. User clicks "Yes"
4. Changes appear in UI
```

**Why:** SWIG-based backend requires file I/O, can't push changes to running UI

**Fix:** Use IPC backend for real-time updates (requires KiCAD to be running with IPC enabled)

**Workaround:** Click reload prompt or use File > Revert

---

### 4. IPC Backend Experimental

**Status:** UNDER DEVELOPMENT

**Description:**
The IPC backend is currently being implemented and tested. Some commands may not work as expected in all scenarios.

**Known IPC Limitations:**
- KiCAD must be running with IPC enabled
- Some commands fall back to SWIG (e.g., delete_trace)
- Footprint loading uses hybrid approach (SWIG for library, IPC for placement)
- Error handling may not be comprehensive in all cases

**Workaround:** If IPC fails, the server automatically falls back to SWIG backend

---

### 5. Schematic Support Limited

**Status:** KNOWN - Partial support

**Description:**
Schematic operations use the kicad-skip library which has some limitations with KiCAD 9.0 file format changes.

**Affected Commands:**
- `create_schematic`
- `add_schematic_component`
- `add_schematic_wire`

**Workaround:** Manual schematic creation may be more reliable for complex designs

---

## Recently Fixed

### Component Library Integration (Fixed 2025-11-01)

**Was:** Could not find footprint libraries
**Now:** Auto-discovers 153 KiCAD footprint libraries, search and list working

### Routing Operations KiCAD 9.0 (Fixed 2025-11-01)

**Was:** Multiple API compatibility issues with KiCAD 9.0
**Now:** All routing commands tested and working:
- `netinfo.FindNet()` -> `netinfo.NetsByName()[name]`
- `zone.SetPriority()` -> `zone.SetAssignedPriority()`
- `ZONE_FILL_MODE_POLYGON` -> `ZONE_FILL_MODE_POLYGONS`

### KiCAD Process Detection (Fixed 2025-10-26)

**Was:** `check_kicad_ui` detected MCP server's own processes
**Now:** Properly filters to only detect actual KiCAD binaries

### set_board_size KiCAD 9.0 (Fixed 2025-10-26)

**Was:** Failed with `BOX2I_SetSize` type error
**Now:** Works with KiCAD 9.0 API

### add_board_text KiCAD 9.0 (Fixed 2025-10-26)

**Was:** Failed with `EDA_ANGLE` type error
**Now:** Works with KiCAD 9.0 API

### Schematic Parameter Mismatch (Fixed 2025-12-02)

**Was:** `create_schematic` failed due to parameter name differences between TypeScript and Python
**Now:** Accepts multiple parameter naming conventions (`name`, `projectName`, `title`, `filename`)

---

## Reporting New Issues

If you encounter an issue not listed here:

1. **Check MCP logs:** `~/.kicad-mcp/logs/kicad_interface.log`
2. **Check KiCAD version:** `python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"` (must be 9.0+)
3. **Try the operation in KiCAD directly** - is it a KiCAD issue?
4. **Open GitHub issue** with:
   - Error message
   - Log excerpt
   - Steps to reproduce
   - KiCAD version
   - OS and version

---

## Priority Matrix

| Issue | Priority | Impact | Status |
|-------|----------|--------|--------|
| IPC Backend Testing | High | Medium | In Progress |
| get_board_info Fix | Low | Low | Known |
| Zone Filling (SWIG) | Medium | Medium | Workaround Available |
| Schematic Support | Medium | Medium | Partial |

---

## General Workarounds

### Server Won't Start
```bash
# Check Python can import pcbnew
python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"

# Check paths
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 Doesn't Show Changes (SWIG Mode)
```
# File > Revert (or click reload prompt)
# Or: Close and reopen file in KiCAD
# Or: Use IPC backend for automatic updates
```

### IPC Not Connecting
```
# Ensure KiCAD is running
# Enable IPC: Preferences > Plugins > Enable IPC API Server
# Have a board open in PCB editor
# Check socket exists: ls /tmp/kicad/api.sock
```

---

**Need Help?**
- Check [IPC_BACKEND_STATUS.md](IPC_BACKEND_STATUS.md) for IPC details
- Check [REALTIME_WORKFLOW.md](REALTIME_WORKFLOW.md) for workflow tips
- Check logs: `~/.kicad-mcp/logs/kicad_interface.log`
- Open an issue on GitHub

```

--------------------------------------------------------------------------------
/CHANGELOG_2025-11-05.md:
--------------------------------------------------------------------------------

```markdown
# Changelog - November 5, 2025

## Windows Support Package

**Focus:** Comprehensive Windows support improvements and platform documentation

**Status:** Complete

---

## New Features

### Windows Automated Setup
- **setup-windows.ps1** - PowerShell script for one-command setup
  - Auto-detects KiCAD installation and version
  - Validates all prerequisites (Node.js, Python, pcbnew)
  - Installs dependencies automatically
  - Builds TypeScript project
  - Generates MCP configuration
  - Runs comprehensive diagnostic tests
  - Provides colored output with clear success/failure indicators
  - Generates detailed error reports with solutions

### Enhanced Error Diagnostics
- **Python Interface** (kicad_interface.py)
  - Windows-specific environment diagnostics on startup
  - Auto-detects KiCAD installations in standard Windows locations
  - Lists found KiCAD versions and Python paths
  - Platform-specific error messages with actionable troubleshooting steps
  - Detailed logging of PYTHONPATH and system PATH

- **Server Startup Validation** (src/server.ts)
  - New `validatePrerequisites()` method
  - Tests pcbnew import before starting Python process
  - Validates Python executable exists
  - Checks project build status
  - Catches configuration errors early
  - Writes errors to both log file and stderr (visible in Claude Desktop)
  - Platform-specific troubleshooting hints in error messages

### Documentation

- **WINDOWS_TROUBLESHOOTING.md** - Comprehensive Windows guide
  - 8 common issues with step-by-step solutions
  - Configuration examples for Claude Desktop and Cline
  - Manual testing procedures
  - Advanced diagnostics section
  - Success checklist
  - Known limitations

- **PLATFORM_GUIDE.md** - Linux vs Windows comparison
  - Detailed comparison table
  - Installation differences explained
  - Path handling conventions
  - Python environment differences
  - Testing and debugging workflows
  - Platform-specific best practices
  - Migration guidance

- **README.md** - Updated Windows section
  - Automated setup prominently featured
  - Honest status: "Supported (community tested)"
  - Links to troubleshooting resources
  - Both automated and manual setup paths
  - Clear verification steps

### Documentation Cleanup
- Removed all emojis from documentation (per project guidelines)
- Updated STATUS_SUMMARY.md Windows status from "UNTESTED" to "SUPPORTED"
- Consistent formatting across all documentation files

---

## Bug Fixes

### Startup Reliability
- Server no longer fails silently on Windows
- Prerequisite validation catches common configuration errors before they cause crashes
- Clear error messages guide users to solutions

### Path Handling
- Improved path handling for Windows (backslash and forward slash support)
- Better documentation of path escaping in JSON configuration files

---

## Improvements

### GitHub Issue Support
- Responded to Issue #5 with initial troubleshooting steps
- Posted comprehensive update announcing all Windows improvements
- Provided clear next steps for affected users

### Testing
- TypeScript build verified with new validation code
- All changes compile without errors or warnings

---

## Files Changed

### New Files
- `setup-windows.ps1` - Automated Windows setup script (500+ lines)
- `docs/WINDOWS_TROUBLESHOOTING.md` - Windows troubleshooting guide
- `docs/PLATFORM_GUIDE.md` - Linux vs Windows comparison
- `CHANGELOG_2025-11-05.md` - This changelog

### Modified Files
- `README.md` - Updated Windows installation section
- `docs/STATUS_SUMMARY.md` - Updated Windows status and removed emojis
- `docs/ROADMAP.md` - Removed emojis
- `python/kicad_interface.py` - Added Windows diagnostics
- `src/server.ts` - Added startup validation

---

## Breaking Changes

None. All changes are backward compatible.

---

## Known Issues

### Not Fixed
- JLCPCB integration still in planning phase (not implemented)
- macOS remains untested
- `get_board_info` layer constants issue (low priority)
- Zone filling disabled due to SWIG API segfault

---

## Migration Notes

### Upgrading from Previous Version

**For Windows users:**
1. Pull latest changes
2. Run `setup-windows.ps1`
3. Update your MCP client configuration if prompted
4. Restart your MCP client

**For Linux users:**
1. Pull latest changes
2. Run `npm install` and `npm run build`
3. No configuration changes needed

---

## Testing Performed

- PowerShell script tested on Windows 10 (simulated)
- TypeScript compilation verified
- Documentation reviewed for consistency
- Path handling verified in configuration examples
- Startup validation logic tested

---

## Next Steps

### Week 2 Completion
- Consider JLCPCB integration implementation
- Create example projects (LED blinker)
- Windows community testing and feedback

### Week 3 Planning
- IPC Backend implementation for real-time UI updates
- Fix remaining minor issues
- macOS testing and support

---

## Contributors

- mixelpixx (Chris) - Windows support implementation
- spplecxer - Issue #5 report (Windows crash)

---

## References

- Issue #5: https://github.com/mixelpixx/KiCAD-MCP-Server/issues/5
- Windows Installation Guide: [README.md](README.md#windows-1011)
- Troubleshooting: [docs/WINDOWS_TROUBLESHOOTING.md](docs/WINDOWS_TROUBLESHOOTING.md)
- Platform Comparison: [docs/PLATFORM_GUIDE.md](docs/PLATFORM_GUIDE.md)

---

**Summary:** This release significantly improves Windows support with automated setup, comprehensive diagnostics, and detailed documentation. Windows users now have a smooth onboarding experience comparable to Linux users.

```

--------------------------------------------------------------------------------
/python/kicad_api/factory.py:
--------------------------------------------------------------------------------

```python
"""
Backend factory for creating appropriate KiCAD API backend

Auto-detects available backends and provides fallback mechanism.
"""
import os
import logging
from typing import Optional
from pathlib import Path

from kicad_api.base import KiCADBackend, APINotAvailableError

logger = logging.getLogger(__name__)


def create_backend(backend_type: Optional[str] = None) -> KiCADBackend:
    """
    Create appropriate KiCAD backend

    Args:
        backend_type: Backend to use:
            - 'ipc': Use IPC API (recommended)
            - 'swig': Use legacy SWIG bindings
            - None or 'auto': Auto-detect (try IPC first, fall back to SWIG)

    Returns:
        KiCADBackend instance

    Raises:
        APINotAvailableError: If no backend is available

    Environment Variables:
        KICAD_BACKEND: Override backend selection ('ipc', 'swig', or 'auto')
    """
    # Check environment variable override
    if backend_type is None:
        backend_type = os.environ.get('KICAD_BACKEND', 'auto').lower()

    logger.info(f"Requested backend: {backend_type}")

    # Try specific backend if requested
    if backend_type == 'ipc':
        return _create_ipc_backend()
    elif backend_type == 'swig':
        return _create_swig_backend()
    elif backend_type == 'auto':
        return _auto_detect_backend()
    else:
        raise ValueError(f"Unknown backend type: {backend_type}")


def _create_ipc_backend() -> KiCADBackend:
    """
    Create IPC backend

    Returns:
        IPCBackend instance

    Raises:
        APINotAvailableError: If kicad-python not available
    """
    try:
        from kicad_api.ipc_backend import IPCBackend
        logger.info("Creating IPC backend")
        return IPCBackend()
    except ImportError as e:
        logger.error(f"IPC backend not available: {e}")
        raise APINotAvailableError(
            "IPC backend requires 'kicad-python' package. "
            "Install with: pip install kicad-python"
        ) from e


def _create_swig_backend() -> KiCADBackend:
    """
    Create SWIG backend

    Returns:
        SWIGBackend instance

    Raises:
        APINotAvailableError: If pcbnew not available
    """
    try:
        from kicad_api.swig_backend import SWIGBackend
        logger.info("Creating SWIG backend")
        logger.warning(
            "SWIG backend is DEPRECATED and will be removed in KiCAD 10.0. "
            "Please migrate to IPC backend."
        )
        return SWIGBackend()
    except ImportError as e:
        logger.error(f"SWIG backend not available: {e}")
        raise APINotAvailableError(
            "SWIG backend requires 'pcbnew' module. "
            "Ensure KiCAD Python module is in PYTHONPATH."
        ) from e


def _auto_detect_backend() -> KiCADBackend:
    """
    Auto-detect best available backend

    Priority:
        1. IPC API (if kicad-python available and KiCAD running)
        2. SWIG API (if pcbnew available)

    Returns:
        Best available KiCADBackend

    Raises:
        APINotAvailableError: If no backend available
    """
    logger.info("Auto-detecting available KiCAD backend...")

    # Try IPC first (preferred)
    try:
        backend = _create_ipc_backend()
        # Test connection
        if backend.connect():
            logger.info("✓ IPC backend available and connected")
            return backend
        else:
            logger.warning("IPC backend available but connection failed")
    except (ImportError, APINotAvailableError) as e:
        logger.debug(f"IPC backend not available: {e}")

    # Fall back to SWIG
    try:
        backend = _create_swig_backend()
        logger.warning(
            "Using deprecated SWIG backend. "
            "For best results, use IPC API with KiCAD running."
        )
        return backend
    except (ImportError, APINotAvailableError) as e:
        logger.error(f"SWIG backend not available: {e}")

    # No backend available
    raise APINotAvailableError(
        "No KiCAD backend available. Please install either:\n"
        "  - kicad-python (recommended): pip install kicad-python\n"
        "  - Ensure KiCAD Python module (pcbnew) is in PYTHONPATH"
    )


def get_available_backends() -> dict:
    """
    Check which backends are available

    Returns:
        Dictionary with backend availability:
            {
                'ipc': {'available': bool, 'version': str or None},
                'swig': {'available': bool, 'version': str or None}
            }
    """
    results = {}

    # Check IPC (kicad-python uses 'kipy' module name)
    try:
        import kipy
        results['ipc'] = {
            'available': True,
            'version': getattr(kipy, '__version__', 'unknown')
        }
    except ImportError:
        results['ipc'] = {'available': False, 'version': None}

    # Check SWIG
    try:
        import pcbnew
        results['swig'] = {
            'available': True,
            'version': pcbnew.GetBuildVersion()
        }
    except ImportError:
        results['swig'] = {'available': False, 'version': None}

    return results


if __name__ == "__main__":
    # Quick diagnostic
    import json
    print("KiCAD Backend Availability:")
    print(json.dumps(get_available_backends(), indent=2))

    print("\nAttempting to create backend...")
    try:
        backend = create_backend()
        print(f"✓ Created backend: {type(backend).__name__}")
        if backend.connect():
            print(f"✓ Connected to KiCAD: {backend.get_version()}")
        else:
            print("✗ Failed to connect to KiCAD")
    except Exception as e:
        print(f"✗ Error: {e}")

```

--------------------------------------------------------------------------------
/tests/test_platform_helper.py:
--------------------------------------------------------------------------------

```python
"""
Tests for platform_helper utility

These are unit tests that work on all platforms.
"""
import pytest
import platform
from pathlib import Path
import sys
import os

# Add parent directory to path to import utils
sys.path.insert(0, str(Path(__file__).parent.parent / "python"))

from utils.platform_helper import PlatformHelper, detect_platform


class TestPlatformDetection:
    """Test platform detection functions"""

    def test_exactly_one_platform_detected(self):
        """Ensure exactly one platform is detected"""
        platforms = [
            PlatformHelper.is_windows(),
            PlatformHelper.is_linux(),
            PlatformHelper.is_macos(),
        ]
        assert sum(platforms) == 1, "Exactly one platform should be detected"

    def test_platform_name_is_valid(self):
        """Test platform name is human-readable"""
        name = PlatformHelper.get_platform_name()
        assert name in ["Windows", "Linux", "macOS"], f"Unknown platform: {name}"

    def test_platform_name_matches_detection(self):
        """Ensure platform name matches detection functions"""
        name = PlatformHelper.get_platform_name()
        if name == "Windows":
            assert PlatformHelper.is_windows()
        elif name == "Linux":
            assert PlatformHelper.is_linux()
        elif name == "macOS":
            assert PlatformHelper.is_macos()


class TestPathGeneration:
    """Test path generation functions"""

    def test_config_dir_exists_after_ensure(self):
        """Test that config directory is created"""
        PlatformHelper.ensure_directories()
        config_dir = PlatformHelper.get_config_dir()
        assert config_dir.exists(), f"Config dir should exist: {config_dir}"
        assert config_dir.is_dir(), f"Config dir should be a directory: {config_dir}"

    def test_log_dir_exists_after_ensure(self):
        """Test that log directory is created"""
        PlatformHelper.ensure_directories()
        log_dir = PlatformHelper.get_log_dir()
        assert log_dir.exists(), f"Log dir should exist: {log_dir}"
        assert log_dir.is_dir(), f"Log dir should be a directory: {log_dir}"

    def test_cache_dir_exists_after_ensure(self):
        """Test that cache directory is created"""
        PlatformHelper.ensure_directories()
        cache_dir = PlatformHelper.get_cache_dir()
        assert cache_dir.exists(), f"Cache dir should exist: {cache_dir}"
        assert cache_dir.is_dir(), f"Cache dir should be a directory: {cache_dir}"

    def test_config_dir_is_platform_appropriate(self):
        """Test that config directory follows platform conventions"""
        config_dir = PlatformHelper.get_config_dir()

        if PlatformHelper.is_linux():
            # Should be ~/.config/kicad-mcp or $XDG_CONFIG_HOME/kicad-mcp
            if "XDG_CONFIG_HOME" in os.environ:
                expected = Path(os.environ["XDG_CONFIG_HOME"]) / "kicad-mcp"
            else:
                expected = Path.home() / ".config" / "kicad-mcp"
            assert config_dir == expected

        elif PlatformHelper.is_windows():
            # Should be %USERPROFILE%\.kicad-mcp
            expected = Path.home() / ".kicad-mcp"
            assert config_dir == expected

        elif PlatformHelper.is_macos():
            # Should be ~/Library/Application Support/kicad-mcp
            expected = Path.home() / "Library" / "Application Support" / "kicad-mcp"
            assert config_dir == expected

    def test_python_executable_is_valid(self):
        """Test that Python executable path is valid"""
        exe = PlatformHelper.get_python_executable()
        assert exe.exists(), f"Python executable should exist: {exe}"
        assert str(exe) == sys.executable

    def test_kicad_library_search_paths_returns_list(self):
        """Test that library search paths returns a list"""
        paths = PlatformHelper.get_kicad_library_search_paths()
        assert isinstance(paths, list)
        assert len(paths) > 0
        # All paths should be strings (glob patterns)
        assert all(isinstance(p, str) for p in paths)


class TestDetectPlatform:
    """Test the detect_platform convenience function"""

    def test_detect_platform_returns_dict(self):
        """Test that detect_platform returns a dictionary"""
        info = detect_platform()
        assert isinstance(info, dict)

    def test_detect_platform_has_required_keys(self):
        """Test that detect_platform includes all required keys"""
        info = detect_platform()
        required_keys = [
            "system",
            "platform",
            "is_windows",
            "is_linux",
            "is_macos",
            "python_version",
            "python_executable",
            "config_dir",
            "log_dir",
            "cache_dir",
            "kicad_python_paths",
        ]
        for key in required_keys:
            assert key in info, f"Missing key: {key}"

    def test_detect_platform_python_version_format(self):
        """Test that Python version is in correct format"""
        info = detect_platform()
        version = info["python_version"]
        # Should be like "3.12.3"
        parts = version.split(".")
        assert len(parts) == 3
        assert all(p.isdigit() for p in parts)


@pytest.mark.integration
class TestKiCADPathDetection:
    """Tests that require KiCAD to be installed"""

    def test_kicad_python_paths_exist(self):
        """Test that at least one KiCAD Python path exists (if KiCAD is installed)"""
        paths = PlatformHelper.get_kicad_python_paths()
        # This test only makes sense if KiCAD is installed
        # In CI, KiCAD should be installed
        if paths:
            assert all(p.exists() for p in paths), "All returned paths should exist"

    def test_can_import_pcbnew_after_adding_paths(self):
        """Test that pcbnew can be imported after adding KiCAD paths"""
        PlatformHelper.add_kicad_to_python_path()
        try:
            import pcbnew
            # If we get here, pcbnew is available
            assert pcbnew is not None
            version = pcbnew.GetBuildVersion()
            assert version is not None
            print(f"Found KiCAD version: {version}")
        except ImportError:
            pytest.skip("KiCAD pcbnew module not available (KiCAD not installed)")


if __name__ == "__main__":
    # Run tests with pytest
    pytest.main([__file__, "-v"])

```

--------------------------------------------------------------------------------
/python/commands/library_schematic.py:
--------------------------------------------------------------------------------

```python
from skip import Schematic
# Symbol class might not be directly importable in the current version
import os
import glob

class LibraryManager:
    """Manage symbol libraries"""

    @staticmethod
    def list_available_libraries(search_paths=None):
        """List all available symbol libraries"""
        if search_paths is None:
            # Default library paths based on common KiCAD installations
            # This would need to be configured for the specific environment
            search_paths = [
                "C:/Program Files/KiCad/*/share/kicad/symbols/*.kicad_sym",  # Windows path pattern
                "/usr/share/kicad/symbols/*.kicad_sym",                      # Linux path pattern
                "/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/*.kicad_sym",  # macOS path pattern
                os.path.expanduser("~/Documents/KiCad/*/symbols/*.kicad_sym")  # User libraries pattern
            ]

        libraries = []
        for path_pattern in search_paths:
            try:
                # Use glob to find all matching files
                matching_libs = glob.glob(path_pattern, recursive=True)
                libraries.extend(matching_libs)
            except Exception as e:
                print(f"Error searching for libraries at {path_pattern}: {e}")

        # Extract library names from paths
        library_names = [os.path.splitext(os.path.basename(lib))[0] for lib in libraries]
        print(f"Found {len(library_names)} libraries: {', '.join(library_names[:10])}{'...' if len(library_names) > 10 else ''}")
        
        # Return both full paths and library names
        return {"paths": libraries, "names": library_names}

    @staticmethod
    def list_library_symbols(library_path):
        """List all symbols in a library"""
        try:
            # kicad-skip doesn't provide a direct way to simply list symbols in a library
            # without loading each one. We might need to implement this using KiCAD's Python API
            # directly, or by using a different approach.
            # For now, this is a placeholder implementation.
            
            # A potential approach would be to load the library file using KiCAD's Python API
            # or by parsing the library file format.
            # KiCAD symbol libraries are .kicad_sym files which are S-expression format
            print(f"Attempted to list symbols in library {library_path}. This requires advanced implementation.")
            return []
        except Exception as e:
            print(f"Error listing symbols in library {library_path}: {e}")
            return []

    @staticmethod
    def get_symbol_details(library_path, symbol_name):
        """Get detailed information about a symbol"""
        try:
            # Similar to list_library_symbols, this might require a more direct approach
            # using KiCAD's Python API or by parsing the symbol library.
            print(f"Attempted to get details for symbol {symbol_name} in library {library_path}. This requires advanced implementation.")
            return {}
        except Exception as e:
            print(f"Error getting symbol details for {symbol_name} in {library_path}: {e}")
            return {}

    @staticmethod
    def search_symbols(query, search_paths=None):
        """Search for symbols matching criteria"""
        try:
            # This would typically involve:
            # 1. Getting a list of all libraries using list_available_libraries
            # 2. For each library, getting a list of all symbols
            # 3. Filtering symbols based on the query
            
            # For now, this is a placeholder implementation
            libraries = LibraryManager.list_available_libraries(search_paths)
            
            results = []
            print(f"Searched for symbols matching '{query}'. This requires advanced implementation.")
            return results
        except Exception as e:
            print(f"Error searching for symbols matching '{query}': {e}")
            return []
            
    @staticmethod
    def get_default_symbol_for_component_type(component_type, search_paths=None):
        """Get a recommended default symbol for a given component type"""
        # This method provides a simplified way to get a symbol for common component types
        # It's useful when the user doesn't specify a particular library/symbol
        
        # Define common mappings from component type to library/symbol
        common_mappings = {
            "resistor": {"library": "Device", "symbol": "R"},
            "capacitor": {"library": "Device", "symbol": "C"},
            "inductor": {"library": "Device", "symbol": "L"},
            "diode": {"library": "Device", "symbol": "D"},
            "led": {"library": "Device", "symbol": "LED"},
            "transistor_npn": {"library": "Device", "symbol": "Q_NPN_BCE"},
            "transistor_pnp": {"library": "Device", "symbol": "Q_PNP_BCE"},
            "opamp": {"library": "Amplifier_Operational", "symbol": "OpAmp_Dual_Generic"},
            "microcontroller": {"library": "MCU_Module", "symbol": "Arduino_UNO_R3"},
            # Add more common components as needed
        }
        
        # Normalize input to lowercase
        component_type_lower = component_type.lower()
        
        # Try direct match first
        if component_type_lower in common_mappings:
            return common_mappings[component_type_lower]
            
        # Try partial matches
        for key, value in common_mappings.items():
            if component_type_lower in key or key in component_type_lower:
                return value
                
        # Default fallback
        return {"library": "Device", "symbol": "R"}

if __name__ == '__main__':
    # Example Usage (for testing)
    # List available libraries
    libraries = LibraryManager.list_available_libraries()
    if libraries["paths"]:
        first_lib = libraries["paths"][0]
        lib_name = libraries["names"][0]
        print(f"Testing with first library: {lib_name} ({first_lib})")
        
        # List symbols in the first library
        symbols = LibraryManager.list_library_symbols(first_lib)
        # This will report that it requires advanced implementation
        
    # Get default symbol for a component type
    resistor_sym = LibraryManager.get_default_symbol_for_component_type("resistor")
    print(f"Default symbol for resistor: {resistor_sym['library']}/{resistor_sym['symbol']}")
    
    # Try a partial match
    cap_sym = LibraryManager.get_default_symbol_for_component_type("cap")
    print(f"Default symbol for 'cap': {cap_sym['library']}/{cap_sym['symbol']}")

```

--------------------------------------------------------------------------------
/python/commands/board/layers.py:
--------------------------------------------------------------------------------

```python
"""
Board layer command implementations for KiCAD interface
"""

import pcbnew
import logging
from typing import Dict, Any, Optional

logger = logging.getLogger('kicad_interface')

class BoardLayerCommands:
    """Handles board layer operations"""

    def __init__(self, board: Optional[pcbnew.BOARD] = None):
        """Initialize with optional board instance"""
        self.board = board

    def add_layer(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Add a new layer to the PCB"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            name = params.get("name")
            layer_type = params.get("type")
            position = params.get("position")
            number = params.get("number")

            if not name or not layer_type or not position:
                return {
                    "success": False,
                    "message": "Missing parameters",
                    "errorDetails": "name, type, and position are required"
                }

            # Get layer stack
            layer_stack = self.board.GetLayerStack()

            # Determine layer ID based on position and number
            layer_id = None
            if position == "inner":
                if number is None:
                    return {
                        "success": False,
                        "message": "Missing layer number",
                        "errorDetails": "number is required for inner layers"
                    }
                layer_id = pcbnew.In1_Cu + (number - 1)
            elif position == "top":
                layer_id = pcbnew.F_Cu
            elif position == "bottom":
                layer_id = pcbnew.B_Cu

            if layer_id is None:
                return {
                    "success": False,
                    "message": "Invalid layer position",
                    "errorDetails": "position must be 'top', 'bottom', or 'inner'"
                }

            # Set layer properties
            layer_stack.SetLayerName(layer_id, name)
            layer_stack.SetLayerType(layer_id, self._get_layer_type(layer_type))
            
            # Enable the layer
            self.board.SetLayerEnabled(layer_id, True)

            return {
                "success": True,
                "message": f"Added layer: {name}",
                "layer": {
                    "name": name,
                    "type": layer_type,
                    "position": position,
                    "number": number
                }
            }

        except Exception as e:
            logger.error(f"Error adding layer: {str(e)}")
            return {
                "success": False,
                "message": "Failed to add layer",
                "errorDetails": str(e)
            }

    def set_active_layer(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Set the active layer for PCB operations"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            layer = params.get("layer")
            if not layer:
                return {
                    "success": False,
                    "message": "No layer specified",
                    "errorDetails": "layer parameter is required"
                }

            # Find layer ID by name
            layer_id = self.board.GetLayerID(layer)
            if layer_id < 0:
                return {
                    "success": False,
                    "message": "Layer not found",
                    "errorDetails": f"Layer '{layer}' does not exist"
                }

            # Set active layer
            self.board.SetActiveLayer(layer_id)

            return {
                "success": True,
                "message": f"Set active layer to: {layer}",
                "layer": {
                    "name": layer,
                    "id": layer_id
                }
            }

        except Exception as e:
            logger.error(f"Error setting active layer: {str(e)}")
            return {
                "success": False,
                "message": "Failed to set active layer",
                "errorDetails": str(e)
            }

    def get_layer_list(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get a list of all layers in the PCB"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            layers = []
            for layer_id in range(pcbnew.PCB_LAYER_ID_COUNT):
                if self.board.IsLayerEnabled(layer_id):
                    layers.append({
                        "name": self.board.GetLayerName(layer_id),
                        "type": self._get_layer_type_name(self.board.GetLayerType(layer_id)),
                        "id": layer_id
                        # Note: isActive removed - GetActiveLayer() doesn't exist in KiCAD 9.0
                        # Active layer is a UI concept not applicable to headless scripting
                    })

            return {
                "success": True,
                "layers": layers
            }

        except Exception as e:
            logger.error(f"Error getting layer list: {str(e)}")
            return {
                "success": False,
                "message": "Failed to get layer list",
                "errorDetails": str(e)
            }
    
    def _get_layer_type(self, type_name: str) -> int:
        """Convert layer type name to KiCAD layer type constant"""
        type_map = {
            "copper": pcbnew.LT_SIGNAL,
            "technical": pcbnew.LT_SIGNAL,
            "user": pcbnew.LT_SIGNAL,  # LT_USER removed in KiCAD 9.0, use LT_SIGNAL instead
            "signal": pcbnew.LT_SIGNAL
        }
        return type_map.get(type_name.lower(), pcbnew.LT_SIGNAL)

    def _get_layer_type_name(self, type_id: int) -> str:
        """Convert KiCAD layer type constant to name"""
        type_map = {
            pcbnew.LT_SIGNAL: "signal",
            pcbnew.LT_POWER: "power",
            pcbnew.LT_MIXED: "mixed",
            pcbnew.LT_JUMPER: "jumper"
        }
        # Note: LT_USER was removed in KiCAD 9.0
        return type_map.get(type_id, "unknown")

```

--------------------------------------------------------------------------------
/python/kicad_api/swig_backend.py:
--------------------------------------------------------------------------------

```python
"""
SWIG Backend (Legacy - DEPRECATED)

Uses the legacy SWIG-based pcbnew Python bindings.
This backend wraps the existing implementation for backward compatibility.

WARNING: SWIG bindings are deprecated as of KiCAD 9.0
         and will be removed in KiCAD 10.0.
         Please migrate to IPC backend.
"""
import logging
from pathlib import Path
from typing import Optional, Dict, Any, List

from kicad_api.base import (
    KiCADBackend,
    BoardAPI,
    ConnectionError,
    APINotAvailableError
)

logger = logging.getLogger(__name__)


class SWIGBackend(KiCADBackend):
    """
    Legacy SWIG-based backend

    Wraps existing commands/project.py, commands/component.py, etc.
    for compatibility during migration period.
    """

    def __init__(self):
        self._connected = False
        self._pcbnew = None
        logger.warning(
            "⚠️ Using DEPRECATED SWIG backend. "
            "This will be removed in KiCAD 10.0. "
            "Please migrate to IPC API."
        )

    def connect(self) -> bool:
        """
        'Connect' to SWIG API (just validates pcbnew import)

        Returns:
            True if pcbnew module available
        """
        try:
            import pcbnew
            self._pcbnew = pcbnew
            version = pcbnew.GetBuildVersion()
            logger.info(f"✓ Connected to pcbnew (SWIG): {version}")
            self._connected = True
            return True
        except ImportError as e:
            logger.error("pcbnew module not found")
            raise APINotAvailableError(
                "SWIG backend requires pcbnew module. "
                "Ensure KiCAD Python module is in PYTHONPATH."
            ) from e

    def disconnect(self) -> None:
        """Disconnect from SWIG API (no-op)"""
        self._connected = False
        self._pcbnew = None
        logger.info("Disconnected from SWIG backend")

    def is_connected(self) -> bool:
        """Check if connected"""
        return self._connected

    def get_version(self) -> str:
        """Get KiCAD version"""
        if not self.is_connected():
            raise ConnectionError("Not connected")

        return self._pcbnew.GetBuildVersion()

    # Project Operations
    def create_project(self, path: Path, name: str) -> Dict[str, Any]:
        """Create project using existing SWIG implementation"""
        if not self.is_connected():
            raise ConnectionError("Not connected")

        # Import existing implementation
        from commands.project import ProjectCommands

        try:
            result = ProjectCommands.create_project(str(path), name)
            return result
        except Exception as e:
            logger.error(f"Failed to create project: {e}")
            raise

    def open_project(self, path: Path) -> Dict[str, Any]:
        """Open project using existing SWIG implementation"""
        if not self.is_connected():
            raise ConnectionError("Not connected")

        from commands.project import ProjectCommands

        try:
            result = ProjectCommands.open_project(str(path))
            return result
        except Exception as e:
            logger.error(f"Failed to open project: {e}")
            raise

    def save_project(self, path: Optional[Path] = None) -> Dict[str, Any]:
        """Save project using existing SWIG implementation"""
        if not self.is_connected():
            raise ConnectionError("Not connected")

        from commands.project import ProjectCommands

        try:
            path_str = str(path) if path else None
            result = ProjectCommands.save_project(path_str)
            return result
        except Exception as e:
            logger.error(f"Failed to save project: {e}")
            raise

    def close_project(self) -> None:
        """Close project (SWIG doesn't have explicit close)"""
        logger.info("Closing project (SWIG backend)")
        # SWIG backend doesn't maintain project state,
        # so this is essentially a no-op

    # Board Operations
    def get_board(self) -> BoardAPI:
        """Get board API"""
        if not self.is_connected():
            raise ConnectionError("Not connected")

        return SWIGBoardAPI(self._pcbnew)


class SWIGBoardAPI(BoardAPI):
    """Board API implementation wrapping SWIG/pcbnew"""

    def __init__(self, pcbnew_module):
        self.pcbnew = pcbnew_module
        self._board = None

    def set_size(self, width: float, height: float, unit: str = "mm") -> bool:
        """Set board size using existing implementation"""
        from commands.board import BoardCommands

        try:
            result = BoardCommands.set_board_size(width, height, unit)
            return result.get("success", False)
        except Exception as e:
            logger.error(f"Failed to set board size: {e}")
            return False

    def get_size(self) -> Dict[str, float]:
        """Get board size"""
        # TODO: Implement using existing SWIG code
        raise NotImplementedError("get_size not yet wrapped")

    def add_layer(self, layer_name: str, layer_type: str) -> bool:
        """Add layer using existing implementation"""
        from commands.board import BoardCommands

        try:
            result = BoardCommands.add_layer(layer_name, layer_type)
            return result.get("success", False)
        except Exception as e:
            logger.error(f"Failed to add layer: {e}")
            return False

    def list_components(self) -> List[Dict[str, Any]]:
        """List components using existing implementation"""
        from commands.component import ComponentCommands

        try:
            result = ComponentCommands.get_component_list()
            if result.get("success"):
                return result.get("components", [])
            return []
        except Exception as e:
            logger.error(f"Failed to list components: {e}")
            return []

    def place_component(
        self,
        reference: str,
        footprint: str,
        x: float,
        y: float,
        rotation: float = 0,
        layer: str = "F.Cu"
    ) -> bool:
        """Place component using existing implementation"""
        from commands.component import ComponentCommands

        try:
            result = ComponentCommands.place_component(
                component_id=footprint,
                position={"x": x, "y": y, "unit": "mm"},
                reference=reference,
                rotation=rotation,
                layer=layer
            )
            return result.get("success", False)
        except Exception as e:
            logger.error(f"Failed to place component: {e}")
            return False


# This backend serves as a wrapper during the migration period.
# Once IPC backend is fully implemented, this can be deprecated.

```

--------------------------------------------------------------------------------
/python/kicad_api/base.py:
--------------------------------------------------------------------------------

```python
"""
Abstract base class for KiCAD API backends

Defines the interface that all KiCAD backends must implement.
"""
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Optional, Dict, Any, List
import logging

logger = logging.getLogger(__name__)


class KiCADBackend(ABC):
    """Abstract base class for KiCAD API backends"""

    @abstractmethod
    def connect(self) -> bool:
        """
        Connect to KiCAD

        Returns:
            True if connection successful, False otherwise
        """
        pass

    @abstractmethod
    def disconnect(self) -> None:
        """Disconnect from KiCAD and clean up resources"""
        pass

    @abstractmethod
    def is_connected(self) -> bool:
        """
        Check if currently connected to KiCAD

        Returns:
            True if connected, False otherwise
        """
        pass

    @abstractmethod
    def get_version(self) -> str:
        """
        Get KiCAD version

        Returns:
            Version string (e.g., "9.0.0")
        """
        pass

    # Project Operations
    @abstractmethod
    def create_project(self, path: Path, name: str) -> Dict[str, Any]:
        """
        Create a new KiCAD project

        Args:
            path: Directory path for the project
            name: Project name

        Returns:
            Dictionary with project info
        """
        pass

    @abstractmethod
    def open_project(self, path: Path) -> Dict[str, Any]:
        """
        Open an existing KiCAD project

        Args:
            path: Path to .kicad_pro file

        Returns:
            Dictionary with project info
        """
        pass

    @abstractmethod
    def save_project(self, path: Optional[Path] = None) -> Dict[str, Any]:
        """
        Save the current project

        Args:
            path: Optional new path to save to

        Returns:
            Dictionary with save status
        """
        pass

    @abstractmethod
    def close_project(self) -> None:
        """Close the current project"""
        pass

    # Board Operations
    @abstractmethod
    def get_board(self) -> 'BoardAPI':
        """
        Get board API for current project

        Returns:
            BoardAPI instance
        """
        pass


class BoardAPI(ABC):
    """Abstract interface for board operations"""

    @abstractmethod
    def set_size(self, width: float, height: float, unit: str = "mm") -> bool:
        """
        Set board size

        Args:
            width: Board width
            height: Board height
            unit: Unit of measurement ("mm" or "in")

        Returns:
            True if successful
        """
        pass

    @abstractmethod
    def get_size(self) -> Dict[str, float]:
        """
        Get current board size

        Returns:
            Dictionary with width, height, unit
        """
        pass

    @abstractmethod
    def add_layer(self, layer_name: str, layer_type: str) -> bool:
        """
        Add a layer to the board

        Args:
            layer_name: Name of the layer
            layer_type: Type ("copper", "technical", "user")

        Returns:
            True if successful
        """
        pass

    @abstractmethod
    def list_components(self) -> List[Dict[str, Any]]:
        """
        List all components on the board

        Returns:
            List of component dictionaries
        """
        pass

    @abstractmethod
    def place_component(
        self,
        reference: str,
        footprint: str,
        x: float,
        y: float,
        rotation: float = 0,
        layer: str = "F.Cu"
    ) -> bool:
        """
        Place a component on the board

        Args:
            reference: Component reference (e.g., "R1")
            footprint: Footprint library path
            x: X position (mm)
            y: Y position (mm)
            rotation: Rotation angle (degrees)
            layer: Layer name

        Returns:
            True if successful
        """
        pass

    # Routing Operations
    def add_track(
        self,
        start_x: float,
        start_y: float,
        end_x: float,
        end_y: float,
        width: float = 0.25,
        layer: str = "F.Cu",
        net_name: Optional[str] = None
    ) -> bool:
        """
        Add a track (trace) to the board

        Args:
            start_x: Start X position (mm)
            start_y: Start Y position (mm)
            end_x: End X position (mm)
            end_y: End Y position (mm)
            width: Track width (mm)
            layer: Layer name
            net_name: Optional net name

        Returns:
            True if successful
        """
        raise NotImplementedError()

    def add_via(
        self,
        x: float,
        y: float,
        diameter: float = 0.8,
        drill: float = 0.4,
        net_name: Optional[str] = None,
        via_type: str = "through"
    ) -> bool:
        """
        Add a via to the board

        Args:
            x: X position (mm)
            y: Y position (mm)
            diameter: Via diameter (mm)
            drill: Drill diameter (mm)
            net_name: Optional net name
            via_type: Via type ("through", "blind", "micro")

        Returns:
            True if successful
        """
        raise NotImplementedError()

    # Transaction support for undo/redo
    def begin_transaction(self, description: str = "MCP Operation") -> None:
        """Begin a transaction for grouping operations."""
        pass  # Optional - not all backends support this

    def commit_transaction(self, description: str = "MCP Operation") -> None:
        """Commit the current transaction."""
        pass  # Optional

    def rollback_transaction(self) -> None:
        """Roll back the current transaction."""
        pass  # Optional

    def save(self) -> bool:
        """Save the board."""
        raise NotImplementedError()

    # Query operations
    def get_tracks(self) -> List[Dict[str, Any]]:
        """Get all tracks on the board."""
        raise NotImplementedError()

    def get_vias(self) -> List[Dict[str, Any]]:
        """Get all vias on the board."""
        raise NotImplementedError()

    def get_nets(self) -> List[Dict[str, Any]]:
        """Get all nets on the board."""
        raise NotImplementedError()

    def get_selection(self) -> List[Dict[str, Any]]:
        """Get currently selected items."""
        raise NotImplementedError()


class BackendError(Exception):
    """Base exception for backend errors"""
    pass


class ConnectionError(BackendError):
    """Raised when connection to KiCAD fails"""
    pass


class APINotAvailableError(BackendError):
    """Raised when required API is not available"""
    pass

```

--------------------------------------------------------------------------------
/docs/IPC_BACKEND_STATUS.md:
--------------------------------------------------------------------------------

```markdown
# KiCAD IPC Backend Implementation Status

**Status:** Under Active Development and Testing
**Date:** 2025-12-02
**KiCAD Version:** 9.0.6
**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:** 2025-12-02

```

--------------------------------------------------------------------------------
/python/commands/component_schematic.py:
--------------------------------------------------------------------------------

```python
from skip import Schematic
# Symbol class might not be directly importable in the current version
import os

class ComponentManager:
    """Manage components in a schematic"""

    @staticmethod
    def add_component(schematic: Schematic, component_def: dict):
        """Add a component to the schematic"""
        try:
            # Create a new symbol
            symbol = schematic.add_symbol(
                lib=component_def.get('library', 'Device'),
                name=component_def.get('type', 'R'), # Default to Resistor symbol 'R'
                reference=component_def.get('reference', 'R?'),
                at=[component_def.get('x', 0), component_def.get('y', 0)],
                unit=component_def.get('unit', 1),
                rotation=component_def.get('rotation', 0)
            )

            # Set properties
            if 'value' in component_def:
                symbol.property.Value.value = component_def['value']
            if 'footprint' in component_def:
                symbol.property.Footprint.value = component_def['footprint']
            if 'datasheet' in component_def:
                 symbol.property.Datasheet.value = component_def['datasheet']

            # Add additional properties
            for key, value in component_def.get('properties', {}).items():
                # Avoid overwriting standard properties unless explicitly intended
                if key not in ['Reference', 'Value', 'Footprint', 'Datasheet']:
                    symbol.property.append(key, value)

            print(f"Added component {symbol.reference} ({symbol.name}) to schematic.")
            return symbol
        except Exception as e:
            print(f"Error adding component: {e}")
            return None

    @staticmethod
    def remove_component(schematic: Schematic, component_ref: str):
        """Remove a component from the schematic by reference designator"""
        try:
            # kicad-skip doesn't have a direct remove_symbol method by reference.
            # We need to find the symbol and then remove it from the symbols list.
            symbol_to_remove = None
            for symbol in schematic.symbol:
                if symbol.reference == component_ref:
                    symbol_to_remove = symbol
                    break

            if symbol_to_remove:
                schematic.symbol.remove(symbol_to_remove)
                print(f"Removed component {component_ref} from schematic.")
                return True
            else:
                print(f"Component with reference {component_ref} not found.")
                return False
        except Exception as e:
            print(f"Error removing component {component_ref}: {e}")
            return False


    @staticmethod
    def update_component(schematic: Schematic, component_ref: str, new_properties: dict):
        """Update component properties by reference designator"""
        try:
            symbol_to_update = None
            for symbol in schematic.symbol:
                if symbol.reference == component_ref:
                    symbol_to_update = symbol
                    break

            if symbol_to_update:
                for key, value in new_properties.items():
                    if key in symbol_to_update.property:
                        symbol_to_update.property[key].value = value
                    else:
                         # Add as a new property if it doesn't exist
                         symbol_to_update.property.append(key, value)
                print(f"Updated properties for component {component_ref}.")
                return True
            else:
                print(f"Component with reference {component_ref} not found.")
                return False
        except Exception as e:
            print(f"Error updating component {component_ref}: {e}")
            return False

    @staticmethod
    def get_component(schematic: Schematic, component_ref: str):
        """Get a component by reference designator"""
        for symbol in schematic.symbol:
            if symbol.reference == component_ref:
                print(f"Found component with reference {component_ref}.")
                return symbol
        print(f"Component with reference {component_ref} not found.")
        return None

    @staticmethod
    def search_components(schematic: Schematic, query: str):
        """Search for components matching criteria (basic implementation)"""
        # This is a basic search, could be expanded to use regex or more complex logic
        matching_components = []
        query_lower = query.lower()
        for symbol in schematic.symbol:
            if query_lower in symbol.reference.lower() or \
               query_lower in symbol.name.lower() or \
               (hasattr(symbol.property, 'Value') and query_lower in symbol.property.Value.value.lower()):
                matching_components.append(symbol)
        print(f"Found {len(matching_components)} components matching query '{query}'.")
        return matching_components

    @staticmethod
    def get_all_components(schematic: Schematic):
        """Get all components in schematic"""
        print(f"Retrieving all {len(schematic.symbol)} components.")
        return list(schematic.symbol)

if __name__ == '__main__':
    # Example Usage (for testing)
    from schematic import SchematicManager # Assuming schematic.py is in the same directory

    # Create a new schematic
    test_sch = SchematicManager.create_schematic("ComponentTestSchematic")

    # Add components
    comp1_def = {"type": "R", "reference": "R1", "value": "10k", "x": 100, "y": 100}
    comp2_def = {"type": "C", "reference": "C1", "value": "0.1uF", "x": 200, "y": 100, "library": "Device"}
    comp3_def = {"type": "LED", "reference": "D1", "x": 300, "y": 100, "library": "Device", "properties": {"Color": "Red"}}

    comp1 = ComponentManager.add_component(test_sch, comp1_def)
    comp2 = ComponentManager.add_component(test_sch, comp2_def)
    comp3 = ComponentManager.add_component(test_sch, comp3_def)

    # Get a component
    retrieved_comp = ComponentManager.get_component(test_sch, "C1")
    if retrieved_comp:
        print(f"Retrieved component: {retrieved_comp.reference} ({retrieved_comp.value})")

    # Update a component
    ComponentManager.update_component(test_sch, "R1", {"value": "20k", "Tolerance": "5%"})

    # Search components
    matching_comps = ComponentManager.search_components(test_sch, "100") # Search by position
    print(f"Search results for '100': {[c.reference for c in matching_comps]}")

    # Get all components
    all_comps = ComponentManager.get_all_components(test_sch)
    print(f"All components: {[c.reference for c in all_comps]}")

    # Remove a component
    ComponentManager.remove_component(test_sch, "D1")
    all_comps_after_remove = ComponentManager.get_all_components(test_sch)
    print(f"Components after removing D1: {[c.reference for c in all_comps_after_remove]}")

    # Save the schematic (optional)
    # SchematicManager.save_schematic(test_sch, "component_test.kicad_sch")

    # Clean up (if saved)
    # if os.path.exists("component_test.kicad_sch"):
    #     os.remove("component_test.kicad_sch")
    #     print("Cleaned up component_test.kicad_sch")

```

--------------------------------------------------------------------------------
/python/commands/project.py:
--------------------------------------------------------------------------------

```python
"""
Project-related command implementations for KiCAD interface
"""

import os
import pcbnew  # type: ignore
import logging
from typing import Dict, Any, Optional

logger = logging.getLogger('kicad_interface')

class ProjectCommands:
    """Handles project-related KiCAD operations"""

    def __init__(self, board: Optional[pcbnew.BOARD] = None):
        """Initialize with optional board instance"""
        self.board = board

    def create_project(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Create a new KiCAD project"""
        try:
            # Accept both 'name' (from MCP tool) and 'projectName' (legacy)
            project_name = params.get("name") or params.get("projectName", "New_Project")
            path = params.get("path", os.getcwd())
            template = params.get("template")

            # Generate the full project path
            project_path = os.path.join(path, project_name)
            if not project_path.endswith(".kicad_pro"):
                project_path += ".kicad_pro"

            # Create project directory if it doesn't exist
            os.makedirs(os.path.dirname(project_path), exist_ok=True)

            # Create a new board
            board = pcbnew.BOARD()
            
            # Set project properties
            board.GetTitleBlock().SetTitle(project_name)
            
            # Set current date with proper parameter
            from datetime import datetime
            current_date = datetime.now().strftime("%Y-%m-%d")
            board.GetTitleBlock().SetDate(current_date)

            # If template is specified, try to load it
            if template:
                template_path = os.path.expanduser(template)
                if os.path.exists(template_path):
                    template_board = pcbnew.LoadBoard(template_path)
                    # Copy settings from template
                    board.SetDesignSettings(template_board.GetDesignSettings())
                    board.SetLayerStack(template_board.GetLayerStack())

            # Save the board
            board_path = project_path.replace(".kicad_pro", ".kicad_pcb")
            board.SetFileName(board_path)
            pcbnew.SaveBoard(board_path, board)

            # Create project file
            with open(project_path, 'w') as f:
                f.write('{\n')
                f.write('  "board": {\n')
                f.write(f'    "filename": "{os.path.basename(board_path)}"\n')
                f.write('  }\n')
                f.write('}\n')

            self.board = board

            return {
                "success": True,
                "message": f"Created project: {project_name}",
                "project": {
                    "name": project_name,
                    "path": project_path,
                    "boardPath": board_path
                }
            }

        except Exception as e:
            logger.error(f"Error creating project: {str(e)}")
            return {
                "success": False,
                "message": "Failed to create project",
                "errorDetails": str(e)
            }

    def open_project(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Open an existing KiCAD project"""
        try:
            filename = params.get("filename")
            if not filename:
                return {
                    "success": False,
                    "message": "No filename provided",
                    "errorDetails": "The filename parameter is required"
                }

            # Expand user path and make absolute
            filename = os.path.abspath(os.path.expanduser(filename))

            # If it's a project file, get the board file
            if filename.endswith(".kicad_pro"):
                board_path = filename.replace(".kicad_pro", ".kicad_pcb")
            else:
                board_path = filename

            # Load the board
            board = pcbnew.LoadBoard(board_path)
            self.board = board

            return {
                "success": True,
                "message": f"Opened project: {os.path.basename(board_path)}",
                "project": {
                    "name": os.path.splitext(os.path.basename(board_path))[0],
                    "path": filename,
                    "boardPath": board_path
                }
            }

        except Exception as e:
            logger.error(f"Error opening project: {str(e)}")
            return {
                "success": False,
                "message": "Failed to open project",
                "errorDetails": str(e)
            }

    def save_project(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Save the current KiCAD project"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            filename = params.get("filename")
            if filename:
                # Save to new location
                filename = os.path.abspath(os.path.expanduser(filename))
                self.board.SetFileName(filename)

            # Save the board
            pcbnew.SaveBoard(self.board.GetFileName(), self.board)

            return {
                "success": True,
                "message": f"Saved project to: {self.board.GetFileName()}",
                "project": {
                    "name": os.path.splitext(os.path.basename(self.board.GetFileName()))[0],
                    "path": self.board.GetFileName()
                }
            }

        except Exception as e:
            logger.error(f"Error saving project: {str(e)}")
            return {
                "success": False,
                "message": "Failed to save project",
                "errorDetails": str(e)
            }

    def get_project_info(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get information about the current project"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            title_block = self.board.GetTitleBlock()
            filename = self.board.GetFileName()
            
            return {
                "success": True,
                "project": {
                    "name": os.path.splitext(os.path.basename(filename))[0],
                    "path": filename,
                    "title": title_block.GetTitle(),
                    "date": title_block.GetDate(),
                    "revision": title_block.GetRevision(),
                    "company": title_block.GetCompany(),
                    "comment1": title_block.GetComment(0),
                    "comment2": title_block.GetComment(1),
                    "comment3": title_block.GetComment(2),
                    "comment4": title_block.GetComment(3)
                }
            }

        except Exception as e:
            logger.error(f"Error getting project info: {str(e)}")
            return {
                "success": False,
                "message": "Failed to get project information",
                "errorDetails": str(e)
            }

```

--------------------------------------------------------------------------------
/src/tools/schematic.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Schematic tools for KiCAD MCP server
 */

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

export function registerSchematicTools(server: McpServer, callKicadScript: Function) {
  // Create schematic tool
  server.tool(
    "create_schematic",
    "Create a new schematic",
    {
      name: z.string().describe("Schematic name"),
      path: z.string().optional().describe("Optional path"),
    },
    async (args: { name: string; path?: string }) => {
      const result = await callKicadScript("create_schematic", args);
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result, null, 2)
        }]
      };
    }
  );

  // Add component to schematic
  server.tool(
    "add_schematic_component",
    "Add a component to the schematic",
    {
      symbol: z.string().describe("Symbol library reference"),
      reference: z.string().describe("Component reference (e.g., R1, U1)"),
      value: z.string().optional().describe("Component value"),
      position: z.object({
        x: z.number(),
        y: z.number()
      }).optional().describe("Position on schematic"),
    },
    async (args: any) => {
      const result = await callKicadScript("add_schematic_component", args);
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result, null, 2)
        }]
      };
    }
  );

  // Connect components with wire
  server.tool(
    "add_wire",
    "Add a wire connection in the schematic",
    {
      start: z.object({
        x: z.number(),
        y: z.number()
      }).describe("Start position"),
      end: z.object({
        x: z.number(),
        y: z.number()
      }).describe("End position"),
    },
    async (args: any) => {
      const result = await callKicadScript("add_wire", args);
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result, null, 2)
        }]
      };
    }
  );

  // Add pin-to-pin connection
  server.tool(
    "add_schematic_connection",
    "Connect two component pins with a wire",
    {
      schematicPath: z.string().describe("Path to the schematic file"),
      sourceRef: z.string().describe("Source component reference (e.g., R1)"),
      sourcePin: z.string().describe("Source pin name/number (e.g., 1, 2, GND)"),
      targetRef: z.string().describe("Target component reference (e.g., C1)"),
      targetPin: z.string().describe("Target pin name/number (e.g., 1, 2, VCC)")
    },
    async (args: { schematicPath: string; sourceRef: string; sourcePin: string; targetRef: string; targetPin: string }) => {
      const result = await callKicadScript("add_schematic_connection", args);
      if (result.success) {
        return {
          content: [{
            type: "text",
            text: `Successfully connected ${args.sourceRef}/${args.sourcePin} to ${args.targetRef}/${args.targetPin}`
          }]
        };
      } else {
        return {
          content: [{
            type: "text",
            text: `Failed to add connection: ${result.message || 'Unknown error'}`
          }]
        };
      }
    }
  );

  // Add net label
  server.tool(
    "add_schematic_net_label",
    "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")
    },
    async (args: { schematicPath: string; netName: string; position: number[] }) => {
      const result = await callKicadScript("add_schematic_net_label", args);
      if (result.success) {
        return {
          content: [{
            type: "text",
            text: `Successfully added net label '${args.netName}' at position [${args.position}]`
          }]
        };
      } else {
        return {
          content: [{
            type: "text",
            text: `Failed to add net label: ${result.message || 'Unknown error'}`
          }]
        };
      }
    }
  );

  // Connect pin to net
  server.tool(
    "connect_to_net",
    "Connect a component pin to a named net",
    {
      schematicPath: z.string().describe("Path to the schematic file"),
      componentRef: z.string().describe("Component reference (e.g., U1, R1)"),
      pinName: z.string().describe("Pin name/number to connect"),
      netName: z.string().describe("Name of the net to connect to")
    },
    async (args: { schematicPath: string; componentRef: string; pinName: string; netName: string }) => {
      const result = await callKicadScript("connect_to_net", args);
      if (result.success) {
        return {
          content: [{
            type: "text",
            text: `Successfully connected ${args.componentRef}/${args.pinName} to net '${args.netName}'`
          }]
        };
      } else {
        return {
          content: [{
            type: "text",
            text: `Failed to connect to net: ${result.message || 'Unknown error'}`
          }]
        };
      }
    }
  );

  // Get net connections
  server.tool(
    "get_net_connections",
    "Get all connections for a named net",
    {
      schematicPath: z.string().describe("Path to the schematic file"),
      netName: z.string().describe("Name of the net to query")
    },
    async (args: { schematicPath: string; netName: string }) => {
      const result = await callKicadScript("get_net_connections", args);
      if (result.success && result.connections) {
        const connectionList = result.connections.map((conn: any) =>
          `  - ${conn.component}/${conn.pin}`
        ).join('\n');
        return {
          content: [{
            type: "text",
            text: `Net '${args.netName}' connections:\n${connectionList}`
          }]
        };
      } else {
        return {
          content: [{
            type: "text",
            text: `Failed to get net connections: ${result.message || 'Unknown error'}`
          }]
        };
      }
    }
  );

  // Generate netlist
  server.tool(
    "generate_netlist",
    "Generate a netlist from the schematic",
    {
      schematicPath: z.string().describe("Path to the schematic file")
    },
    async (args: { schematicPath: string }) => {
      const result = await callKicadScript("generate_netlist", args);
      if (result.success && result.netlist) {
        const netlist = result.netlist;
        const output = [
          `=== Netlist for ${args.schematicPath} ===`,
          `\nComponents (${netlist.components.length}):`,
          ...netlist.components.map((comp: any) =>
            `  ${comp.reference}: ${comp.value} (${comp.footprint || 'No footprint'})`
          ),
          `\nNets (${netlist.nets.length}):`,
          ...netlist.nets.map((net: any) => {
            const connections = net.connections.map((conn: any) =>
              `${conn.component}/${conn.pin}`
            ).join(', ');
            return `  ${net.name}: ${connections}`;
          })
        ].join('\n');

        return {
          content: [{
            type: "text",
            text: output
          }]
        };
      } else {
        return {
          content: [{
            type: "text",
            text: `Failed to generate netlist: ${result.message || 'Unknown error'}`
          }]
        };
      }
    }
  );
}

```

--------------------------------------------------------------------------------
/src/prompts/component.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * 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');
}

```

--------------------------------------------------------------------------------
/src/resources/component.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Component resources for KiCAD MCP server
 * 
 * These resources provide information about components on the PCB
 * to the LLM, enabling better context-aware assistance.
 */

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<string, unknown>) => Promise<any>;

/**
 * Register component resources with the MCP server
 * 
 * @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');

  // ------------------------------------------------------
  // Component List Resource
  // ------------------------------------------------------
  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: [{
            uri: uri.href,
            text: JSON.stringify({
              error: "Failed to retrieve component list",
              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"
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Component Details Resource
  // ------------------------------------------------------
  server.resource(
    "component_details",
    new ResourceTemplate("kicad://component/{reference}/details", {
      list: undefined
    }),
    async (uri, params) => {
      const { reference } = params;
      logger.debug(`Retrieving details for component: ${reference}`);
      const result = await callKicadScript("get_component_properties", {
        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"
          }]
        };
      }
      
      logger.debug(`Successfully retrieved details for component: ${reference}`);
      return {
        contents: [{
          uri: uri.href,
          text: JSON.stringify(result),
          mimeType: "application/json"
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Component Connections Resource
  // ------------------------------------------------------
  server.resource(
    "component_connections",
    new ResourceTemplate("kicad://component/{reference}/connections", {
      list: undefined
    }),
    async (uri, params) => {
      const { reference } = params;
      logger.debug(`Retrieving connections for component: ${reference}`);
      const result = await callKicadScript("get_component_connections", {
        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"
          }]
        };
      }
      
      logger.debug(`Successfully retrieved connections for component: ${reference}`);
      return {
        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", {});
      
      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
            }),
            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", {});
      
      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
            }),
            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
  // ------------------------------------------------------
  server.resource(
    "component_visualization",
    new ResourceTemplate("kicad://component/{reference}/visualization", {
      list: undefined
    }),
    async (uri, params) => {
      const { reference } = params;
      logger.debug(`Generating visualization for component: ${reference}`);
      const result = await callKicadScript("get_component_visualization", {
        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"
          }]
        };
      }
      
      logger.debug(`Successfully generated visualization for component: ${reference}`);
      return {
        contents: [{
          uri: uri.href,
          blob: result.imageData,  // Base64 encoded image data
          mimeType: "image/png"
        }]
      };
    }
  );

  logger.info('Component resources registered');
}

```

--------------------------------------------------------------------------------
/src/resources/project.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * 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<string, unknown>) => Promise<any>;

/**
 * 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<string, number> {
  const typeCounts: Record<string, number> = {};
  
  for (const component of components) {
    const type = component.value?.split(' ')[0] || 'Unknown';
    typeCounts[type] = (typeCounts[type] || 0) + 1;
  }
  
  return typeCounts;
}

```

--------------------------------------------------------------------------------
/docs/ROADMAP.md:
--------------------------------------------------------------------------------

```markdown
# KiCAD MCP Roadmap

**Vision:** Enable anyone to design professional PCBs through natural conversation with AI

**Current Version:** 2.1.0-alpha
**Target:** 2.0.0 stable by end of Week 12

---

## Week 2: Component Integration & Routing

**Goal:** Make the MCP server useful for real PCB design
**Status:** 80% Complete (2025-11-01)

### High Priority

**1. Component Library Integration** ✅ **COMPLETE**
- [x] Detect KiCAD footprint library paths
- [x] Add configuration for custom library paths
- [x] Create footprint search/autocomplete
- [x] Test component placement end-to-end
- [x] Document supported footprints

**Deliverable:** ✅ Place components with actual footprints from libraries (153 libraries discovered!)

**2. Routing Operations** ✅ **COMPLETE**
- [x] Test `route_trace` with KiCAD 9.0
- [x] Test `add_via` with KiCAD 9.0
- [x] Test `add_copper_pour` with KiCAD 9.0
- [x] Fix any API compatibility issues
- [x] Add routing examples to docs

**Deliverable:** ✅ Successfully route a simple board (tested with nets, traces, vias, copper pours)

**3. JLCPCB Parts Database** 📋 **PLANNED**
- [x] Research JLCPCB API and data format
- [x] Design integration architecture
- [ ] Download/parse JLCPCB parts database (~108k parts)
- [ ] Map parts to KiCAD footprints
- [ ] Create search by part number
- [ ] Add price/stock information
- [ ] Integrate with component placement

**Deliverable:** "Add a 10k resistor (JLCPCB basic part)" - Ready to implement

### Medium Priority

**4. Fix get_board_info** 🟡 **DEFERRED**
- [ ] Update layer constants for KiCAD 9.0
- [ ] Add backward compatibility
- [ ] Test with real boards

**Status:** Low priority, workarounds available

**5. Example Projects** 🟢
- [ ] LED blinker (555 timer)
- [ ] Arduino Uno shield template
- [ ] Raspberry Pi HAT template
- [ ] Video tutorial of complete workflow

### Bonus Achievements ✨

**Real-time Collaboration** ✅ **COMPLETE**
- [x] Test MCP→UI workflow (AI places, human sees)
- [x] Test UI→MCP workflow (human edits, AI reads)
- [x] Document best practices and limitations
- [x] Verify bidirectional sync works correctly

**Documentation** ✅ **COMPLETE**
- [x] LIBRARY_INTEGRATION.md (comprehensive library guide)
- [x] REALTIME_WORKFLOW.md (collaboration workflows)
- [x] JLCPCB_INTEGRATION_PLAN.md (implementation plan)

---

## Week 3: IPC Backend & Real-time Updates

**Goal:** Eliminate manual reload - see changes instantly
**Status:** 🟢 **IMPLEMENTED** (2025-11-30)

### High Priority

**1. IPC Connection** ✅ **COMPLETE**
- [x] Establish socket connection to KiCAD
- [x] Handle connection errors gracefully
- [x] Auto-reconnect if KiCAD restarts
- [x] Fall back to SWIG if IPC unavailable

**2. IPC Operations** ✅ **COMPLETE**
- [x] Port project operations to IPC
- [x] Port board operations to IPC
- [x] Port component operations to IPC
- [x] Port routing operations to IPC

**3. Real-time UI Updates** ✅ **COMPLETE**
- [x] Changes appear instantly in UI
- [x] No reload prompt
- [x] Visual feedback within 100ms
- [ ] Demo video showing real-time design

**Deliverable:** ✅ Design a board with live updates as Claude works

### Medium Priority

**4. Dual Backend Support** ✅ **COMPLETE**
- [x] Auto-detect if IPC is available
- [x] Switch between SWIG/IPC seamlessly
- [x] Document when to use each
- [ ] Performance comparison

---

## Week 4-5: Smart BOM & Supplier Integration

**Goal:** Optimize component selection for cost and availability

**1. Digikey Integration**
- [ ] API authentication
- [ ] Part search by specs
- [ ] Price/stock checking
- [ ] Parametric search (e.g., "10k resistor, 0603, 1%")

**2. Smart BOM Management**
- [ ] Auto-suggest component substitutions
- [ ] Calculate total board cost
- [ ] Check component availability
- [ ] Generate purchase links

**3. Cost Optimization**
- [ ] Suggest JLCPCB basic parts (free assembly)
- [ ] Warn about expensive/obsolete parts
- [ ] Batch component suggestions

**Deliverable:** "Design a low-cost LED driver under $5 BOM"

---

## Week 6-7: Design Patterns & Templates

**Goal:** Accelerate common design tasks

**1. Circuit Patterns Library**
- [ ] Voltage regulators (LDO, switching)
- [ ] USB interfaces (USB-C, micro-USB)
- [ ] Microcontroller circuits (ESP32, STM32, RP2040)
- [ ] Power protection (reverse polarity, ESD)
- [ ] Common interfaces (I2C, SPI, UART)

**2. Board Templates**
- [ ] Arduino form factors (Uno, Nano, Mega)
- [ ] Raspberry Pi HATs
- [ ] Feather wings
- [ ] Custom PCB shapes (badges, wearables)

**3. Auto-routing Helpers**
- [ ] Suggest trace widths by current
- [ ] Auto-create ground pours
- [ ] Match differential pair lengths
- [ ] Check impedance requirements

**Deliverable:** "Create an ESP32 dev board with USB-C"

---

## Week 8-9: Guided Workflows & Education

**Goal:** Make PCB design accessible to beginners

**1. Interactive Tutorials**
- [ ] First PCB (LED blinker)
- [ ] Understanding layers and vias
- [ ] Routing best practices
- [ ] Design rule checking

**2. Design Validation**
- [ ] Check for common mistakes
- [ ] Suggest improvements
- [ ] Explain DRC violations
- [ ] Manufacturing feasibility check

**3. Documentation Generation**
- [ ] Auto-generate assembly drawings
- [ ] Create BOM spreadsheets
- [ ] Export fabrication files
- [ ] Generate user manual

**Deliverable:** Complete beginner-to-fabrication tutorial

---

## Week 10-11: Advanced Features

**Goal:** Support complex professional designs

**1. Multi-board Projects**
- [ ] Panel designs for manufacturing
- [ ] Shared schematics across boards
- [ ] Version management

**2. High-speed Design**
- [ ] Impedance-controlled traces
- [ ] Length matching for DDR/PCIe
- [ ] Signal integrity analysis
- [ ] Via stitching for EMI

**3. Advanced Components**
- [ ] BGAs and fine-pitch packages
- [ ] Flex PCB support
- [ ] Rigid-flex designs

---

## Week 12: Polish & Release

**Goal:** Production-ready v2.0 release

**1. Performance**
- [ ] Optimize large board operations
- [ ] Cache library searches
- [ ] Parallel operations where possible

**2. Testing**
- [ ] Unit tests for all commands
- [ ] Integration tests for workflows
- [ ] Test on Windows/macOS/Linux
- [ ] Load testing with complex boards

**3. Documentation**
- [ ] Complete API reference
- [ ] Video tutorial series
- [ ] Blog post/announcement
- [ ] Example project gallery

**4. Community**
- [ ] Contribution guidelines
- [ ] Plugin system for custom tools
- [ ] Discord/forum for support

**Deliverable:** KiCAD MCP v2.0 stable release

---

## Future (Post-v2.0)

**Big Ideas for v3.0+**

**1. AI-Powered Design**
- Generate circuits from specifications
- Optimize layouts for size/cost/performance
- Suggest alternative designs
- Learn from user preferences

**2. Collaboration**
- Multi-user design sessions
- Design reviews and comments
- Version control integration (Git)
- Share design patterns

**3. Manufacturing Integration**
- Direct order to PCB fabs
- Assembly service integration
- Track order status
- Automated quoting

**4. Simulation**
- SPICE integration for circuit sim
- Thermal simulation
- Signal integrity
- Power integrity

**5. Extended Platform Support**
- Altium import/export
- Eagle compatibility
- EasyEDA integration
- Web-based viewer

---

## Success Metrics

**v2.0 Release Criteria:**

- [ ] 95%+ of commands working reliably
- [ ] Component placement with 10,000+ footprints
- [ ] IPC backend working on all platforms
- [ ] 10+ example projects
- [ ] 5+ video tutorials
- [ ] 100+ GitHub stars
- [ ] 10+ community contributors

**User Success Stories:**
- "Designed my first PCB with Claude Code in 30 minutes"
- "Cut PCB design time by 80% using MCP"
- "Got my board manufactured - it works!"

---

## How to Contribute

See the roadmap and want to help?

**High-value contributions:**
1. Component library mappings (JLCPCB → KiCAD)
2. Design pattern library (circuits you use often)
3. Testing on Windows/macOS
4. Documentation and tutorials
5. Bug reports with reproductions

Check [CONTRIBUTING.md](../CONTRIBUTING.md) for details.

---

**Last Updated:** 2025-11-30
**Maintained by:** KiCAD MCP Team

```

--------------------------------------------------------------------------------
/docs/LINUX_COMPATIBILITY_AUDIT.md:
--------------------------------------------------------------------------------

```markdown
# 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

```

--------------------------------------------------------------------------------
/python/commands/board/view.py:
--------------------------------------------------------------------------------

```python
"""
Board view command implementations for KiCAD interface
"""

import os
import pcbnew
import logging
from typing import Dict, Any, Optional, List, Tuple
from PIL import Image
import io
import base64

logger = logging.getLogger('kicad_interface')

class BoardViewCommands:
    """Handles board viewing operations"""

    def __init__(self, board: Optional[pcbnew.BOARD] = None):
        """Initialize with optional board instance"""
        self.board = board

    def get_board_info(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get information about the current board"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            # Get board dimensions
            board_box = self.board.GetBoardEdgesBoundingBox()
            width_nm = board_box.GetWidth()
            height_nm = board_box.GetHeight()

            # Convert to mm
            width_mm = width_nm / 1000000
            height_mm = height_nm / 1000000

            # Get layer information
            layers = []
            for layer_id in range(pcbnew.PCB_LAYER_ID_COUNT):
                if self.board.IsLayerEnabled(layer_id):
                    layers.append({
                        "name": self.board.GetLayerName(layer_id),
                        "type": self._get_layer_type_name(self.board.GetLayerType(layer_id)),
                        "id": layer_id
                    })

            return {
                "success": True,
                "board": {
                    "filename": self.board.GetFileName(),
                    "size": {
                        "width": width_mm,
                        "height": height_mm,
                        "unit": "mm"
                    },
                    "layers": layers,
                    "title": self.board.GetTitleBlock().GetTitle()
                    # Note: activeLayer removed - GetActiveLayer() doesn't exist in KiCAD 9.0
                    # Active layer is a UI concept not applicable to headless scripting
                }
            }

        except Exception as e:
            logger.error(f"Error getting board info: {str(e)}")
            return {
                "success": False,
                "message": "Failed to get board information",
                "errorDetails": str(e)
            }

    def get_board_2d_view(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get a 2D image of the PCB"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            # Get parameters
            width = params.get("width", 800)
            height = params.get("height", 600)
            format = params.get("format", "png")
            layers = params.get("layers", [])

            # Create plot controller
            plotter = pcbnew.PLOT_CONTROLLER(self.board)
            
            # Set up plot options
            plot_opts = plotter.GetPlotOptions()
            plot_opts.SetOutputDirectory(os.path.dirname(self.board.GetFileName()))
            plot_opts.SetScale(1)
            plot_opts.SetMirror(False)
            # Note: SetExcludeEdgeLayer() removed in KiCAD 9.0 - default behavior includes all layers
            plot_opts.SetPlotFrameRef(False)
            plot_opts.SetPlotValue(True)
            plot_opts.SetPlotReference(True)
            
            # Plot to SVG first (for vector output)
            # Note: KiCAD 9.0 prepends the project name to the filename, so we use GetPlotFileName() to get the actual path
            plotter.OpenPlotfile("temp_view", pcbnew.PLOT_FORMAT_SVG, "Temporary View")

            # Plot specified layers or all enabled layers
            # Note: In KiCAD 9.0, SetLayer() must be called before PlotLayer()
            if layers:
                for layer_name in layers:
                    layer_id = self.board.GetLayerID(layer_name)
                    if layer_id >= 0 and self.board.IsLayerEnabled(layer_id):
                        plotter.SetLayer(layer_id)
                        plotter.PlotLayer()
            else:
                for layer_id in range(pcbnew.PCB_LAYER_ID_COUNT):
                    if self.board.IsLayerEnabled(layer_id):
                        plotter.SetLayer(layer_id)
                        plotter.PlotLayer()

            # Get the actual filename that was created (includes project name prefix)
            temp_svg = plotter.GetPlotFileName()

            plotter.ClosePlot()

            # Convert SVG to requested format
            if format == "svg":
                with open(temp_svg, 'r') as f:
                    svg_data = f.read()
                os.remove(temp_svg)
                return {
                    "success": True,
                    "imageData": svg_data,
                    "format": "svg"
                }
            else:
                # Use PIL to convert SVG to PNG/JPG
                from cairosvg import svg2png
                png_data = svg2png(url=temp_svg, output_width=width, output_height=height)
                os.remove(temp_svg)
                
                if format == "jpg":
                    # Convert PNG to JPG
                    img = Image.open(io.BytesIO(png_data))
                    jpg_buffer = io.BytesIO()
                    img.convert('RGB').save(jpg_buffer, format='JPEG')
                    jpg_data = jpg_buffer.getvalue()
                    return {
                        "success": True,
                        "imageData": base64.b64encode(jpg_data).decode('utf-8'),
                        "format": "jpg"
                    }
                else:
                    return {
                        "success": True,
                        "imageData": base64.b64encode(png_data).decode('utf-8'),
                        "format": "png"
                    }

        except Exception as e:
            logger.error(f"Error getting board 2D view: {str(e)}")
            return {
                "success": False,
                "message": "Failed to get board 2D view",
                "errorDetails": str(e)
            }
    
    def _get_layer_type_name(self, type_id: int) -> str:
        """Convert KiCAD layer type constant to name"""
        type_map = {
            pcbnew.LT_SIGNAL: "signal",
            pcbnew.LT_POWER: "power",
            pcbnew.LT_MIXED: "mixed",
            pcbnew.LT_JUMPER: "jumper"
        }
        # Note: LT_USER was removed in KiCAD 9.0
        return type_map.get(type_id, "unknown")

    def get_board_extents(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """Get the bounding box extents of the board"""
        try:
            if not self.board:
                return {
                    "success": False,
                    "message": "No board is loaded",
                    "errorDetails": "Load or create a board first"
                }

            # Get unit preference (default to mm)
            unit = params.get("unit", "mm")
            scale = 1000000 if unit == "mm" else 25400000  # nm to mm or inch

            # Get board bounding box
            board_box = self.board.GetBoardEdgesBoundingBox()

            # Extract bounds in nanometers, then convert
            left = board_box.GetLeft() / scale
            top = board_box.GetTop() / scale
            right = board_box.GetRight() / scale
            bottom = board_box.GetBottom() / scale
            width = board_box.GetWidth() / scale
            height = board_box.GetHeight() / scale

            # Get center point
            center_x = board_box.GetCenter().x / scale
            center_y = board_box.GetCenter().y / scale

            return {
                "success": True,
                "extents": {
                    "left": left,
                    "top": top,
                    "right": right,
                    "bottom": bottom,
                    "width": width,
                    "height": height,
                    "center": {
                        "x": center_x,
                        "y": center_y
                    },
                    "unit": unit
                }
            }

        except Exception as e:
            logger.error(f"Error getting board extents: {str(e)}")
            return {
                "success": False,
                "message": "Failed to get board extents",
                "errorDetails": str(e)
            }

```
Page 1/4FirstPrevNextLast