#
tokens: 48440/50000 58/72 files (page 1/2)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 2. 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
├── config
│   ├── claude-desktop-config.json
│   ├── default-config.json
│   ├── linux-config.example.json
│   ├── macos-config.example.json
│   └── windows-config.example.json
├── CONTRIBUTING.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
│   │   ├── 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
│   └── utils
│       ├── __init__.py
│       ├── kicad_process.py
│       └── platform_helper.py
├── README.md
├── requirements-dev.txt
├── requirements.txt
├── scripts
│   ├── auto_refresh_kicad.sh
│   └── install-linux.sh
├── 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
│   │   ├── project.ts
│   │   ├── routing.ts
│   │   ├── schematic.ts
│   │   └── ui.ts
│   └── utils
│       └── resource-helpers.ts
├── tests
│   ├── __init__.py
│   └── test_platform_helper.py
├── tsconfig-json.json
└── 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

# 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
# Note: this is basically a BETA Build 
# I built this in Linux / Ubuntu using Claude Code.  I have ONLY tested in Ubuntu.
I am working on this again after dealing with some family issues.
I apologize for this looking abandoned, it is not.




# KiCAD MCP: AI-Assisted PCB Design

KiCAD MCP is a Model Context Protocol (MCP) implementation that enables Large Language Models (LLMs) like Claude to directly interact with KiCAD for printed circuit board design. It creates a standardized communication bridge between AI assistants and the KiCAD PCB design software, allowing for natural language control of advanced PCB design operations.

## What is MCP?

The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard from Anthropic that allows AI assistants like Claude to securely connect to external tools and data sources. Think of it as a universal adapter that lets Claude interact with your local software - in this case, KiCAD.

**With this MCP server, you can:**
- Design PCBs by talking to Claude in natural language
- Automate complex KiCAD operations through AI assistance
- Get real-time feedback as Claude creates and modifies your boards
- Leverage AI to handle tedious PCB design tasks

## NEW FEATURES

### Schematic Generation
Now, in addition to PCB design, KiCAD MCP enables AI assistants to:

- Create and manage KiCAD schematics through natural language
- Add components like resistors, capacitors, and ICs to schematics
- Connect components with wires to create complete circuits
- Save and load schematic files in KiCAD format
- Export schematics to PDF

### UI Auto-Launch
Seamless visual feedback for PCB design. The MCP server can now:

- Auto-detect if KiCAD UI is running
- Auto-launch KiCAD when needed
- Open projects directly in the UI
- Cross-platform support (Linux, macOS, Windows)

Just say "Create a board" and watch it appear in KiCAD. See [UI_AUTO_LAUNCH.md](docs/UI_AUTO_LAUNCH.md) for details.

## Project Status

**This project is currently undergoing a major v2.0 rebuild**

**Current Status ():**
- Cross-platform support (Linux, Windows, macOS)
- CI/CD pipeline with automated testing
- Platform-agnostic path handling
- Migrating to KiCAD IPC API (from deprecated SWIG)
- Adding JLCPCB parts integration
- Adding Digikey parts integration
- Smart BOM management system

**What Works Now (Tested & Verified):**
- Project management (create, open, save)
- Board outline creation (rectangle, circle, polygon)
- Board size setting (KiCAD 9.0 compatible)
- Mounting holes with configurable diameters
- Board text annotations (KiCAD 9.0 compatible)
- Layer management (add, set active, list)
- UI auto-launch and detection
- Visual feedback workflow (manual reload)
- Cross-platform Python venv support
- Design rule checking
- Export (Gerber, PDF, SVG, 3D models)
- Schematic generation

**Known Issues:**
- Component placement needs library path integration
- Routing operations not yet tested with KiCAD 9.0
- `get_board_info` has KiCAD 9.0 API compatibility issue
- UI auto-reload requires manual confirmation (IPC will fix this)

**Next Priorities ():**
1. Component Library Integration - Map JLCPCB/Digikey parts to KiCAD footprints
2. Routing Operations - Test and fix trace routing, vias, copper pours
3. IPC Backend - Enable real-time UI updates (no manual reload)
4. Documentation - Add video tutorials and example projects

**Future (v2.0):**
- AI-assisted component selection with cost optimization
- Smart BOM management and supplier integration
- Design pattern library (Arduino shields, Raspberry Pi HATs, etc.)
- Guided workflows for beginners
- Auto-documentation generation

**Documentation:**
- [Status Summary](docs/STATUS_SUMMARY.md) - Current state at a glance
- [Roadmap](docs/ROADMAP.md) - Where we're going (12-week plan)
- [Known Issues](docs/KNOWN_ISSUES.md) - Problems and workarounds
- [Changelog](CHANGELOG_2025-10-26.md) - Recent updates and fixes

## What It Does

KiCAD MCP transforms how engineers and designers work with KiCAD by enabling AI assistants to:

- Create and manage KiCAD PCB projects through natural language requests
- **Create schematics** with components and connections
- Manipulate board geometry, outlines, layers, and properties
- Place and organize components in various patterns (grid, circular, aligned)
- Route traces, differential pairs, and create copper pours
- Implement design rules and perform design rule checks
- Generate exports in various formats (Gerber, PDF, SVG, 3D models)
- Provide comprehensive context about the circuit board to the AI assistant

This enables a natural language-driven PCB design workflow where complex operations can be requested in plain English, while still maintaining full engineer oversight and control.

## Core Architecture

- **TypeScript MCP Server**: Implements the Anthropic Model Context Protocol specification to communicate with Claude and other compatible AI assistants
- **Python KiCAD Interface**: Handles actual KiCAD operations via pcbnew Python API and kicad-skip library with comprehensive error handling
- **Modular Design**: Organizes functionality by domains (project, schematic, board, component, routing) for maintainability and extensibility

## Prerequisites - READ THIS FIRST!

Before installing this MCP server, you **MUST** have:

### 1. KiCAD 9.0 or Higher (REQUIRED!)

**This is the most critical requirement.** Without KiCAD properly installed with its Python module, this MCP server will not work.

- **Download:** [kicad.org/download](https://www.kicad.org/download/)
- **Verify Python module:** After installing, run:
  ```bash
  python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"
  ```
  If this fails, your KiCAD installation is incomplete.

### 2. Python 3.10 or Higher

**Required Python packages:**
```
kicad-skip>=0.1.0        # Schematic manipulation
Pillow>=9.0.0            # Image processing for board rendering
cairosvg>=2.7.0          # SVG rendering
colorlog>=6.7.0          # Colored logging
pydantic>=2.5.0          # Data validation
requests>=2.31.0         # HTTP requests (for future API features)
python-dotenv>=1.0.0     # Environment management
```

These will be installed automatically via `pip install -r requirements.txt`

### 3. Node.js v18 or Higher

- **Download:** [nodejs.org](https://nodejs.org/)
- **Verify:** Run `node --version` and `npm --version`

### 4. An MCP-Compatible Client

Choose one:
- **[Claude Desktop](https://claude.ai/download)** - Official Anthropic desktop app
- **[Claude Code](https://docs.claude.com/claude-code)** - Official Anthropic CLI tool
- **[Cline](https://github.com/cline/cline)** - Popular VSCode extension

### 5. Operating System

- **Linux** (Ubuntu 22.04+, Fedora, Arch) - Primary platform, fully tested
- **Windows 10/11** - Fully supported
- **macOS** - Experimental (untested, please report issues!)

## Installation

Choose your platform below for detailed installation instructions:

<details>
<summary><b>Linux (Ubuntu/Debian)</b> - Click to expand</summary>

### Step 1: Install KiCAD 9.0

```bash
# Add KiCAD 9.0 PPA (Ubuntu/Debian)
sudo add-apt-repository --yes ppa:kicad/kicad-9.0-releases
sudo apt-get update

# Install KiCAD and libraries
sudo apt-get install -y kicad kicad-libraries
```

### Step 2: Install Node.js

```bash
# Install Node.js 20.x (recommended)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs

# Verify installation
node --version  # Should be v20.x or higher
npm --version
```

### Step 3: Clone and Build

```bash
# Clone repository
git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git
cd KiCAD-MCP-Server

# Install Node.js dependencies
npm install

# Install Python dependencies
pip3 install -r requirements.txt

# Build TypeScript
npm run build
```

### Step 4: Configure Cline

1. Install VSCode and the Cline extension
2. Edit Cline MCP settings:
   ```bash
   code ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
   ```

3. Add this configuration (adjust paths for your system):
   ```json
   {
     "mcpServers": {
       "kicad": {
         "command": "node",
         "args": ["/home/YOUR_USERNAME/KiCAD-MCP-Server/dist/index.js"],
         "env": {
           "NODE_ENV": "production",
           "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages",
           "LOG_LEVEL": "info"
         },
         "description": "KiCAD PCB Design Assistant"
       }
     }
   }
   ```

4. Restart VSCode

### Step 5: Verify Installation

```bash
# Test platform detection
python3 python/utils/platform_helper.py

# Run tests (optional)
pytest tests/
```

**Troubleshooting:**
- If KiCAD Python module not found, check: `python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"`
- For PYTHONPATH issues, see: [docs/LINUX_COMPATIBILITY_AUDIT.md](docs/LINUX_COMPATIBILITY_AUDIT.md)

</details>

<details>
<summary><b>Windows 10/11</b> - Click to expand</summary>

### Step 1: Install KiCAD 9.0

1. Download KiCAD 9.0 from [kicad.org/download/windows](https://www.kicad.org/download/windows/)
2. Run the installer with default options
3. Verify Python module is installed (included by default)

### Step 2: Install Node.js

1. Download Node.js 20.x from [nodejs.org](https://nodejs.org/)
2. Run installer with default options
3. Verify in PowerShell:
   ```powershell
   node --version
   npm --version
   ```

### Step 3: Clone and Build

```powershell
# Clone repository
git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git
cd KiCAD-MCP-Server

# Install dependencies
npm install
pip install -r requirements.txt

# Build
npm run build
```

### Step 4: Configure Cline

1. Install VSCode and Cline extension
2. Edit Cline MCP settings at:
   ```
   %USERPROFILE%\AppData\Roaming\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json
   ```

3. Add configuration:
   ```json
   {
     "mcpServers": {
       "kicad": {
         "command": "C:\\Program Files\\nodejs\\node.exe",
         "args": ["C:\\Users\\YOUR_USERNAME\\KiCAD-MCP-Server\\dist\\index.js"],
         "env": {
           "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages"
         }
       }
     }
   }
   ```

4. Restart VSCode

</details>

<details>
<summary><b>macOS</b> - Click to expand (Experimental)</summary>

### Step 1: Install KiCAD 9.0

1. Download KiCAD 9.0 from [kicad.org/download/macos](https://www.kicad.org/download/macos/)
2. Drag KiCAD.app to Applications folder

### Step 2: Install Node.js

```bash
# Using Homebrew (install from brew.sh if needed)
brew install node@20

# Verify
node --version
npm --version
```

### Step 3: Clone and Build

```bash
git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git
cd KiCAD-MCP-Server
npm install
pip3 install -r requirements.txt
npm run build
```

### Step 4: Configure Cline

Edit `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`:

```json
{
  "mcpServers": {
    "kicad": {
      "command": "node",
      "args": ["/Users/YOUR_USERNAME/KiCAD-MCP-Server/dist/index.js"],
      "env": {
        "PYTHONPATH": "/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages"
      }
    }
  }
}
```

**Note:** macOS support is experimental. Please report issues on GitHub.

</details>

## Quick Start

After installation, test with Cline:

1. Open VSCode with Cline extension
2. Start a conversation with Claude
3. Try these commands:

```
Create a new KiCAD project named 'TestProject' in my home directory.
```

```
Set the board size to 100mm x 80mm and add a rectangular outline.
```

```
Show me the current board properties.
```

If Claude successfully executes these commands, your installation is working!

### Configuration for Other Clients

The examples above show configuration for Cline (VSCode), but KiCAD MCP works with any MCP-compatible client:

- **Claude Desktop** - Desktop app from Anthropic
- **Claude Code** - CLI tool from Anthropic
- **Cline** - VSCode extension
- **Any MCP client** - Using STDIO transport

For detailed configuration instructions for all clients, see:
**[Client Configuration Guide](docs/CLIENT_CONFIGURATION.md)**

The guide includes:
- Platform-specific configurations (Linux, macOS, Windows)
- Client-specific setup (Claude Desktop, Cline, Claude Code)
- Troubleshooting steps
- How to find KiCAD Python paths
- Advanced configuration options

## Usage Examples

Here are some examples of what you can ask Claude to do with KiCAD MCP:

### Project Management

```
Create a new KiCAD project named 'WiFiModule' in my Documents folder.
```

```
Open the existing KiCAD project at C:/Projects/Amplifier/Amplifier.kicad_pro
```

### UI Management (NEW!)

```
Is KiCAD running?
```

```
Launch KiCAD with my project at /tmp/demo/project.kicad_pcb
```

```
Open KiCAD so I can see the board as we design it
```

### Schematic Design

```
Create a new schematic named 'PowerSupply'.
```

```
Add a 10kΩ resistor and 0.1µF capacitor to the schematic.
```

```
Connect the resistor's pin 1 to the capacitor's pin 1.
```

### Board Design

```
Set the board size to 100mm x 80mm.
```

```
Add a rounded rectangle board outline with 3mm corner radius.
```

```
Add mounting holes at each corner of the board, 5mm from the edges.
```

### Component Placement

```
Place a 10uF capacitor at position x=50mm, y=30mm.
```

```
Create a grid of 8 LEDs, 4x2, starting at position x=20mm, y=10mm with 10mm spacing.
```

```
Align all resistors horizontally and distribute them evenly.
```

### Routing

```
Create a new net named 'VCC' and assign it to the power net class.
```

```
Route a trace from component U1 pin 1 to component C3 pin 2 on layer F.Cu.
```

```
Add a copper pour for GND on the bottom layer.
```

### Design Rules and Export

```
Set design rules with 0.2mm clearance and 0.25mm minimum track width.
```

```
Export Gerber files to the 'fabrication' directory.
```

## Features by Category

### Project Management
- Create new KiCAD projects with customizable settings
- Open existing KiCAD projects from file paths
- Save projects with optional new locations
- Retrieve project metadata and properties

### Schematic Design
- Create new schematics with customizable settings
- Add components from symbol libraries (resistors, capacitors, ICs, etc.)
- Connect components with wires to create circuits
- Add labels, annotations, and documentation to schematics
- Save and load schematics in KiCAD format
- Export schematics to PDF for documentation

### Board Design
- Set precise board dimensions with support for metric and imperial units
- Add custom board outlines (rectangle, rounded rectangle, circle, polygon)
- Create and manage board layers with various configurations
- Add mounting holes, text annotations, and other board features
- Visualize the current board state

### Components
- Place components with specified footprints at precise locations
- Create component arrays in grid or circular patterns
- Move, rotate, and modify existing components
- Align and distribute components evenly
- Duplicate components with customizable properties
- Get detailed component properties and listings

### Routing
- Create and manage nets with specific properties
- Route traces between component pads or arbitrary points
- Add vias, including blind and buried vias
- Create differential pair routes for high-speed signals
- Generate copper pours (ground planes, power planes)
- Define net classes with specific design rules

### Design Rules
- Set global design rules for clearance, track width, etc.
- Define specific rules for different net classes
- Run Design Rule Check (DRC) to validate the design
- View and manage DRC violations

### Export
- Generate industry-standard Gerber files for fabrication
- Export PDF documentation of the PCB
- Create SVG vector graphics of the board
- Generate 3D models in STEP or VRML format
- Produce bill of materials (BOM) in various formats

## Implementation Details

The KiCAD MCP implementation uses a modular, maintainable architecture:

### TypeScript MCP Server (Node.js)
- **kicad-server.ts**: The main server that implements the MCP protocol
- Uses STDIO transport for reliable communication with Cline
- Manages the Python process for KiCAD operations
- Handles command queuing, error recovery, and response formatting

### Python Interface
- **kicad_interface.py**: The main Python interface that:
  - Parses commands received as JSON via stdin
  - Routes commands to the appropriate specialized handlers
  - Returns results as JSON via stdout
  - Handles errors gracefully with detailed information

- **Modular Command Structure**:
  - `commands/project.py`: Project creation, opening, saving
  - `commands/schematic.py`: Schematic creation and management
  - `commands/component_schematic.py`: Schematic component operations
  - `commands/connection_schematic.py`: Wire and connection management
  - `commands/library_schematic.py`: Symbol library integration
  - `commands/board/`: Modular board manipulation functions
    - `size.py`: Board size operations
    - `layers.py`: Layer management
    - `outline.py`: Board outline creation
    - `view.py`: Visualization functions
  - `commands/component.py`: PCB component placement and manipulation
  - `commands/routing.py`: Trace routing and net management
  - `commands/design_rules.py`: DRC and rule configuration
  - `commands/export.py`: Output generation in various formats

This architecture ensures that each aspect of PCB design is handled by specialized modules while maintaining a clean, consistent interface layer.

## Troubleshooting

### Common Issues and Solutions

**Problem: KiCAD MCP isn't showing up in Claude's tools**
- Make sure VSCode is completely restarted after updating the Cline MCP settings
- Verify the paths in the config are correct for your system
- Check that the `npm run build` completed successfully

**Problem: Node.js errors when launching the server**
- Ensure you're using Node.js v18 or higher
- Try running `npm install` again to ensure all dependencies are properly installed
- Check the console output for specific error messages

**Problem: Python errors or KiCAD commands failing**
- Verify that KiCAD 9.0 is properly installed
- Check that the PYTHONPATH in the configuration points to the correct location
- Try running a simple KiCAD Python script directly to ensure the pcbnew module is accessible

**Problem: Claude can't find or load your KiCAD project**
- Use absolute paths when referring to project locations
- Ensure the user running VSCode has access permissions to the directories

### Getting Help

If you encounter issues not covered in this troubleshooting section:
1. Check the console output for error messages
2. Look for similar issues in the GitHub repository's Issues section
3. Open a new issue with detailed information about the problem

## Contributing

Contributions to this project are welcome! Here's how you can help:

1. **Report Bugs**: Open an issue describing what went wrong and how to reproduce it
2. **Suggest Features**: Have an idea? Share it via an issue
3. **Submit Pull Requests**: Fixed a bug or added a feature? Submit a PR!
4. **Improve Documentation**: Help clarify or expand the documentation

Please follow the existing code style and include tests for new features.

## License

This project is licensed under the MIT License - see the LICENSE file for details.



```

--------------------------------------------------------------------------------
/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/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": ""
}

```

--------------------------------------------------------------------------------
/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:
--------------------------------------------------------------------------------

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

```

--------------------------------------------------------------------------------
/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"
    }
  }
}

```

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

```

--------------------------------------------------------------------------------
/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.31.0

# Environment variable management
python-dotenv>=1.0.0

```

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

```

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

```json
{
  "name": "kicad-mcp",
  "version": "2.0.0-alpha.1",
  "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.10.0",
    "dotenv": "^16.0.3",
    "express": "^5.1.0",
    "zod": "^3.22.2"
  },
  "devDependencies": {
    "@types/express": "^5.0.1",
    "@types/node": "^20.5.6",
    "nodemon": "^3.0.1",
    "typescript": "^5.2.2"
  }
}

```

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

```

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

```

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

```

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

```

--------------------------------------------------------------------------------
/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"""
        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"
                }

            # Convert to internal units (nanometers)
            scale = 1000000 if unit == "mm" else 25400000  # mm or inch to nm
            width_nm = int(width * scale)
            height_nm = int(height * scale)

            # Set board size using KiCAD 9.0 API
            # Note: In KiCAD 9.0, SetSize takes two separate parameters instead of VECTOR2I
            board_box = self.board.GetBoardEdgesBoundingBox()
            try:
                # Try KiCAD 9.0+ API (two parameters)
                board_box.SetSize(width_nm, height_nm)
            except TypeError:
                # Fall back to older API (VECTOR2I)
                board_box.SetSize(pcbnew.VECTOR2I(width_nm, height_nm))

            # Note: SetBoardEdgesBoundingBox might not exist in all versions
            # The board bounding box is typically derived from actual edge cuts
            # For now, we'll just note the size was calculated
            logger.info(f"Board size set to {width}x{height} {unit}")

            return {
                "success": True,
                "message": f"Set board size to {width}x{height} {unit}",
                "size": {
                    "width": width,
                    "height": height,
                    "unit": unit
                }
            }

        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
    switch (level) {
      case 'error':
        console.error(formattedMessage);
        break;
      case 'warn':
        console.warn(formattedMessage);
        break;
      case 'info':
      case 'debug':
      default:
        console.log(formattedMessage);
        break;
    }
    
    // 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/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 if this file is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
  main().catch((error) => {
    logger.error(`Unhandled error in main: ${error}`);
    process.exit(1);
  });
}

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

```

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

```

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

```python
from skip import Schematic
import os

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

        print(f"Created new schematic: {name}")
        return sch

    @staticmethod
    def load_schematic(file_path):
        """Load an existing schematic"""
        if not os.path.exists(file_path):
            print(f"Error: Schematic file not found at {file_path}")
            return None
        try:
            sch = Schematic(file_path)
            print(f"Loaded schematic from: {file_path}")
            return sch
        except Exception as e:
            print(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)
            print(f"Saved schematic to: {file_path}")
            return True
        except Exception as e:
            print(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
        }
        print("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}")

```

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

    # Add more abstract methods for routing, DRC, export, etc.
    # These will be filled in during migration


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

```

--------------------------------------------------------------------------------
/python/commands/connection_schematic.py:
--------------------------------------------------------------------------------

```python
from skip import Schematic
# Wire and Net classes might not be directly importable in the current version
import os

class ConnectionManager:
    """Manage connections between components"""

    @staticmethod
    def add_wire(schematic: Schematic, start_point: list, end_point: list, properties: dict = None):
        """Add a wire between two points"""
        try:
            wire = schematic.add_wire(start=start_point, end=end_point)
            # kicad-skip wire properties are limited, but we can potentially
            # add graphical properties if needed in the future.
            print(f"Added wire from {start_point} to {end_point}.")
            return wire
        except Exception as e:
            print(f"Error adding wire: {e}")
            return None

    @staticmethod
    def add_connection(schematic: Schematic, source_ref: str, source_pin: str, target_ref: str, target_pin: str):
        """Add a connection between component pins"""
        # kicad-skip handles connections implicitly through wires and labels.
        # This method would typically involve adding wires and potentially net labels
        # to connect the specified pins.
        # A direct 'add_connection' between pins isn't a standard kicad-skip operation
        # in the way it is in some other schematic tools.
        # We will need to implement this logic by finding the component pins
        # and adding wires/labels between their locations. This is more complex
        # and might require pin location information which isn't directly
        # exposed in a simple way by default in kicad-skip Symbol objects.

        # For now, this method will be a placeholder or require a more advanced
        # implementation based on how kicad-skip handles net connections.
        # A common approach is to add wires between graphical points and then
        # add net labels to define the net name.

        print(f"Attempted to add connection between {source_ref}/{source_pin} and {target_ref}/{target_pin}. This requires advanced implementation.")
        return False # Indicate not fully implemented yet

    @staticmethod
    def remove_connection(schematic: Schematic, connection_id: str):
        """Remove a connection"""
        # Removing connections in kicad-skip typically means removing the wires
        # or net labels that form the connection.
        # This method would need to identify the relevant graphical elements
        # based on a connection identifier (which we would need to define).
        # This is also an advanced implementation task.
        print(f"Attempted to remove connection with ID {connection_id}. This requires advanced implementation.")
        return False # Indicate not fully implemented yet

    @staticmethod
    def get_net_connections(schematic: Schematic, net_name: str):
        """Get all connections in a named net"""
        # kicad-skip represents nets implicitly through connected wires and net labels.
        # To get connections for a net, we would need to iterate through wires
        # and net labels to build a list of connected pins/points.
        # This requires traversing the schematic's graphical elements and understanding
        # how they form nets. This is an advanced implementation task.
        print(f"Attempted to get connections for net '{net_name}'. This requires advanced implementation.")
        return [] # Return empty list for now

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("ConnectionTestSchematic")

    # Add some wires
    wire1 = ConnectionManager.add_wire(test_sch, [100, 100], [200, 100])
    wire2 = ConnectionManager.add_wire(test_sch, [200, 100], [200, 200])

    # Note: add_connection, remove_connection, get_net_connections are placeholders
    # and require more complex implementation based on kicad-skip's structure.

    # Example of how you might add a net label (requires finding a point on a wire)
    # from skip import Label
    # if wire1:
    #     net_label_pos = wire1.start # Or calculate a point on the wire
    #     net_label = test_sch.add_label(text="Net_01", at=net_label_pos)
    #     print(f"Added net label 'Net_01' at {net_label_pos}")

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

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

```

--------------------------------------------------------------------------------
/.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 "✗ {}"'

```

--------------------------------------------------------------------------------
/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
    try:
        import kicad
        results['ipc'] = {
            'available': True,
            'version': getattr(kicad, '__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}")

```

--------------------------------------------------------------------------------
/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(),
                    "activeLayer": self.board.GetActiveLayer()
                }
            }

        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)
            plot_opts.SetExcludeEdgeLayer(False)
            plot_opts.SetPlotFrameRef(False)
            plot_opts.SetPlotValue(True)
            plot_opts.SetPlotReference(True)
            
            # Plot to SVG first (for vector output)
            temp_svg = os.path.join(os.path.dirname(self.board.GetFileName()), "temp_view.svg")
            plotter.OpenPlotfile("temp_view", pcbnew.PLOT_FORMAT_SVG, "Temporary View")
            
            # Plot specified layers or all enabled layers
            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.PlotLayer(layer_id)
            else:
                for layer_id in range(pcbnew.PCB_LAYER_ID_COUNT):
                    if self.board.IsLayerEnabled(layer_id):
                        plotter.PlotLayer(layer_id)
            
            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",
            pcbnew.LT_USER: "user"
        }
        return type_map.get(type_id, "unknown")

```

--------------------------------------------------------------------------------
/python/kicad_api/ipc_backend.py:
--------------------------------------------------------------------------------

```python
"""
IPC API Backend (KiCAD 9.0+)

Uses the official kicad-python library for inter-process communication
with a running KiCAD instance.

Note: Requires KiCAD to be running with IPC server enabled:
    Preferences > Plugins > Enable IPC API Server
"""
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 IPCBackend(KiCADBackend):
    """
    KiCAD IPC API backend

    Communicates with KiCAD via Protocol Buffers over UNIX sockets.
    Requires KiCAD 9.0+ to be running with IPC enabled.
    """

    def __init__(self):
        self.kicad = None
        self._connected = False

    def connect(self) -> bool:
        """
        Connect to running KiCAD instance via IPC

        Returns:
            True if connection successful

        Raises:
            ConnectionError: If connection fails
        """
        try:
            # Import here to allow module to load even without kicad-python
            from kicad import KiCad

            logger.info("Connecting to KiCAD via IPC...")
            self.kicad = KiCad()

            # Verify connection with version check
            version = self.get_version()
            logger.info(f"✓ Connected to KiCAD {version} via IPC")
            self._connected = True
            return True

        except ImportError as e:
            logger.error("kicad-python library not found")
            raise APINotAvailableError(
                "IPC backend requires kicad-python. "
                "Install with: pip install kicad-python"
            ) from e
        except Exception as e:
            logger.error(f"Failed to connect via IPC: {e}")
            logger.info(
                "Ensure KiCAD is running with IPC enabled: "
                "Preferences > Plugins > Enable IPC API Server"
            )
            raise ConnectionError(f"IPC connection failed: {e}") from e

    def disconnect(self) -> None:
        """Disconnect from KiCAD"""
        if self.kicad:
            # kicad-python handles cleanup automatically
            self.kicad = None
            self._connected = False
            logger.info("Disconnected from KiCAD IPC")

    def is_connected(self) -> bool:
        """Check if connected"""
        return self._connected and self.kicad is not None

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

        try:
            # Use kicad-python's version checking
            version_info = self.kicad.check_version()
            return str(version_info)
        except Exception as e:
            logger.warning(f"Could not get version: {e}")
            return "unknown"

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

        TODO: Implement with IPC API
        """
        if not self.is_connected():
            raise ConnectionError("Not connected to KiCAD")

        logger.warning("create_project not yet implemented for IPC backend")
        raise NotImplementedError(
            "Project creation via IPC API is not yet implemented. "
            "This will be added in Week 2-3 migration."
        )

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

        logger.warning("open_project not yet implemented for IPC backend")
        raise NotImplementedError("Coming in Week 2-3 migration")

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

        logger.warning("save_project not yet implemented for IPC backend")
        raise NotImplementedError("Coming in Week 2-3 migration")

    def close_project(self) -> None:
        """Close current project"""
        if not self.is_connected():
            raise ConnectionError("Not connected to KiCAD")

        logger.warning("close_project not yet implemented for IPC backend")
        raise NotImplementedError("Coming in Week 2-3 migration")

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

        return IPCBoardAPI(self.kicad)


class IPCBoardAPI(BoardAPI):
    """Board API implementation for IPC backend"""

    def __init__(self, kicad_instance):
        self.kicad = kicad_instance
        self._board = None

    def _get_board(self):
        """Lazy-load board instance"""
        if self._board is None:
            self._board = self.kicad.get_board()
        return self._board

    def set_size(self, width: float, height: float, unit: str = "mm") -> bool:
        """Set board size"""
        logger.warning("set_size not yet implemented for IPC backend")
        raise NotImplementedError("Coming in Week 2-3 migration")

    def get_size(self) -> Dict[str, float]:
        """Get board size"""
        logger.warning("get_size not yet implemented for IPC backend")
        raise NotImplementedError("Coming in Week 2-3 migration")

    def add_layer(self, layer_name: str, layer_type: str) -> bool:
        """Add layer"""
        logger.warning("add_layer not yet implemented for IPC backend")
        raise NotImplementedError("Coming in Week 2-3 migration")

    def list_components(self) -> List[Dict[str, Any]]:
        """List components"""
        logger.warning("list_components not yet implemented for IPC backend")
        raise NotImplementedError("Coming in Week 2-3 migration")

    def place_component(
        self,
        reference: str,
        footprint: str,
        x: float,
        y: float,
        rotation: float = 0,
        layer: str = "F.Cu"
    ) -> bool:
        """Place component"""
        logger.warning("place_component not yet implemented for IPC backend")
        raise NotImplementedError("Coming in Week 2-3 migration")


# Note: Full implementation will be completed during Week 2-3 migration
# This is a skeleton to establish the pattern

```

--------------------------------------------------------------------------------
/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/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,
                        "isActive": layer_id == self.board.GetActiveLayer()
                    })

            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_USER,
            "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",
            pcbnew.LT_USER: "user"
        }
        return type_map.get(type_id, "unknown")

```

--------------------------------------------------------------------------------
/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/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/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:
            project_name = 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)
            }

```

--------------------------------------------------------------------------------
/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")

```

--------------------------------------------------------------------------------
/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;
}

```

--------------------------------------------------------------------------------
/src/tools/export.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Export tools for KiCAD MCP server
 * 
 * These tools handle exporting PCB data to various formats
 */

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

// Command function type for KiCAD script calls
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;

/**
 * Register export tools with the MCP server
 * 
 * @param server MCP server instance
 * @param callKicadScript Function to call KiCAD script commands
 */
export function registerExportTools(server: McpServer, callKicadScript: CommandFunction): void {
  logger.info('Registering export tools');
  
  // ------------------------------------------------------
  // Export Gerber Tool
  // ------------------------------------------------------
  server.tool(
    "export_gerber",
    {
      outputDir: z.string().describe("Directory to save Gerber files"),
      layers: z.array(z.string()).optional().describe("Optional array of layer names to export (default: all)"),
      useProtelExtensions: z.boolean().optional().describe("Whether to use Protel filename extensions"),
      generateDrillFiles: z.boolean().optional().describe("Whether to generate drill files"),
      generateMapFile: z.boolean().optional().describe("Whether to generate a map file"),
      useAuxOrigin: z.boolean().optional().describe("Whether to use auxiliary axis as origin")
    },
    async ({ outputDir, layers, useProtelExtensions, generateDrillFiles, generateMapFile, useAuxOrigin }) => {
      logger.debug(`Exporting Gerber files to: ${outputDir}`);
      const result = await callKicadScript("export_gerber", {
        outputDir,
        layers,
        useProtelExtensions,
        generateDrillFiles,
        generateMapFile,
        useAuxOrigin
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Export PDF Tool
  // ------------------------------------------------------
  server.tool(
    "export_pdf",
    {
      outputPath: z.string().describe("Path to save the PDF file"),
      layers: z.array(z.string()).optional().describe("Optional array of layer names to include (default: all)"),
      blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"),
      frameReference: z.boolean().optional().describe("Whether to include frame reference"),
      pageSize: z.enum(["A4", "A3", "A2", "A1", "A0", "Letter", "Legal", "Tabloid"]).optional().describe("Page size")
    },
    async ({ outputPath, layers, blackAndWhite, frameReference, pageSize }) => {
      logger.debug(`Exporting PDF to: ${outputPath}`);
      const result = await callKicadScript("export_pdf", {
        outputPath,
        layers,
        blackAndWhite,
        frameReference,
        pageSize
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Export SVG Tool
  // ------------------------------------------------------
  server.tool(
    "export_svg",
    {
      outputPath: z.string().describe("Path to save the SVG file"),
      layers: z.array(z.string()).optional().describe("Optional array of layer names to include (default: all)"),
      blackAndWhite: z.boolean().optional().describe("Whether to export in black and white"),
      includeComponents: z.boolean().optional().describe("Whether to include component outlines")
    },
    async ({ outputPath, layers, blackAndWhite, includeComponents }) => {
      logger.debug(`Exporting SVG to: ${outputPath}`);
      const result = await callKicadScript("export_svg", {
        outputPath,
        layers,
        blackAndWhite,
        includeComponents
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Export 3D Model Tool
  // ------------------------------------------------------
  server.tool(
    "export_3d",
    {
      outputPath: z.string().describe("Path to save the 3D model file"),
      format: z.enum(["STEP", "STL", "VRML", "OBJ"]).describe("3D model format"),
      includeComponents: z.boolean().optional().describe("Whether to include 3D component models"),
      includeCopper: z.boolean().optional().describe("Whether to include copper layers"),
      includeSolderMask: z.boolean().optional().describe("Whether to include solder mask"),
      includeSilkscreen: z.boolean().optional().describe("Whether to include silkscreen")
    },
    async ({ outputPath, format, includeComponents, includeCopper, includeSolderMask, includeSilkscreen }) => {
      logger.debug(`Exporting 3D model to: ${outputPath}`);
      const result = await callKicadScript("export_3d", {
        outputPath,
        format,
        includeComponents,
        includeCopper,
        includeSolderMask,
        includeSilkscreen
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Export BOM Tool
  // ------------------------------------------------------
  server.tool(
    "export_bom",
    {
      outputPath: z.string().describe("Path to save the BOM file"),
      format: z.enum(["CSV", "XML", "HTML", "JSON"]).describe("BOM file format"),
      groupByValue: z.boolean().optional().describe("Whether to group components by value"),
      includeAttributes: z.array(z.string()).optional().describe("Optional array of additional attributes to include")
    },
    async ({ outputPath, format, groupByValue, includeAttributes }) => {
      logger.debug(`Exporting BOM to: ${outputPath}`);
      const result = await callKicadScript("export_bom", {
        outputPath,
        format,
        groupByValue,
        includeAttributes
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Export Netlist Tool
  // ------------------------------------------------------
  server.tool(
    "export_netlist",
    {
      outputPath: z.string().describe("Path to save the netlist file"),
      format: z.enum(["KiCad", "Spice", "Cadstar", "OrcadPCB2"]).optional().describe("Netlist format (default: KiCad)")
    },
    async ({ outputPath, format }) => {
      logger.debug(`Exporting netlist to: ${outputPath}`);
      const result = await callKicadScript("export_netlist", {
        outputPath,
        format
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Export Position File Tool
  // ------------------------------------------------------
  server.tool(
    "export_position_file",
    {
      outputPath: z.string().describe("Path to save the position file"),
      format: z.enum(["CSV", "ASCII"]).optional().describe("File format (default: CSV)"),
      units: z.enum(["mm", "inch"]).optional().describe("Units to use (default: mm)"),
      side: z.enum(["top", "bottom", "both"]).optional().describe("Which board side to include (default: both)")
    },
    async ({ outputPath, format, units, side }) => {
      logger.debug(`Exporting position file to: ${outputPath}`);
      const result = await callKicadScript("export_position_file", {
        outputPath,
        format,
        units,
        side
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Export VRML Tool
  // ------------------------------------------------------
  server.tool(
    "export_vrml",
    {
      outputPath: z.string().describe("Path to save the VRML file"),
      includeComponents: z.boolean().optional().describe("Whether to include 3D component models"),
      useRelativePaths: z.boolean().optional().describe("Whether to use relative paths for 3D models")
    },
    async ({ outputPath, includeComponents, useRelativePaths }) => {
      logger.debug(`Exporting VRML to: ${outputPath}`);
      const result = await callKicadScript("export_vrml", {
        outputPath,
        includeComponents,
        useRelativePaths
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  logger.info('Export tools registered');
}

```

--------------------------------------------------------------------------------
/src/resources/library.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Library resources for KiCAD MCP server
 * 
 * These resources provide information about KiCAD component libraries
 * to the LLM, enabling better context-aware assistance.
 */

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

// Command function type for KiCAD script calls
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;

/**
 * Register library resources with the MCP server
 * 
 * @param server MCP server instance
 * @param callKicadScript Function to call KiCAD script commands
 */
export function registerLibraryResources(server: McpServer, callKicadScript: CommandFunction): void {
  logger.info('Registering library resources');

  // ------------------------------------------------------
  // Component Library Resource
  // ------------------------------------------------------
  server.resource(
    "component_library",
    new ResourceTemplate("kicad://components/{filter?}/{library?}", {
      list: async () => ({
        resources: [
          { uri: "kicad://components", name: "All Components" }
        ]
      })
    }),
    async (uri, params) => {
      const filter = params.filter || '';
      const library = params.library || '';
      const limit = Number(params.limit) || undefined;

      logger.debug(`Retrieving component library${filter ? ` with filter: ${filter}` : ''}${library ? ` from library: ${library}` : ''}`);
      
      const result = await callKicadScript("get_component_library", {
        filter,
        library,
        limit
      });

      if (!result.success) {
        logger.error(`Failed to retrieve component library: ${result.errorDetails}`);
        return {
          contents: [{
            uri: uri.href,
            text: JSON.stringify({
              error: "Failed to retrieve component library",
              details: result.errorDetails
            }),
            mimeType: "application/json"
          }]
        };
      }

      logger.debug(`Successfully retrieved ${result.components?.length || 0} components from library`);
      return {
        contents: [{
          uri: uri.href,
          text: JSON.stringify(result),
          mimeType: "application/json"
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Library List Resource
  // ------------------------------------------------------
  server.resource(
    "library_list",
    "kicad://libraries",
    async (uri) => {
      logger.debug('Retrieving library list');
      const result = await callKicadScript("get_library_list", {});

      if (!result.success) {
        logger.error(`Failed to retrieve library list: ${result.errorDetails}`);
        return {
          contents: [{
            uri: uri.href,
            text: JSON.stringify({
              error: "Failed to retrieve library list",
              details: result.errorDetails
            }),
            mimeType: "application/json"
          }]
        };
      }

      logger.debug(`Successfully retrieved ${result.libraries?.length || 0} libraries`);
      return {
        contents: [{
          uri: uri.href,
          text: JSON.stringify(result),
          mimeType: "application/json"
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Library Component Details Resource
  // ------------------------------------------------------
  server.resource(
    "library_component_details",
    new ResourceTemplate("kicad://library/component/{componentId}/{library?}", {
      list: undefined
    }),
    async (uri, params) => {
      const { componentId, library } = params;
      logger.debug(`Retrieving details for component: ${componentId}${library ? ` from library: ${library}` : ''}`);
      
      const result = await callKicadScript("get_component_details", {
        componentId,
        library
      });

      if (!result.success) {
        logger.error(`Failed to retrieve component details: ${result.errorDetails}`);
        return {
          contents: [{
            uri: uri.href,
            text: JSON.stringify({
              error: `Failed to retrieve details for component ${componentId}`,
              details: result.errorDetails
            }),
            mimeType: "application/json"
          }]
        };
      }

      logger.debug(`Successfully retrieved details for component: ${componentId}`);
      return {
        contents: [{
          uri: uri.href,
          text: JSON.stringify(result),
          mimeType: "application/json"
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Component Footprint Resource
  // ------------------------------------------------------
  server.resource(
    "component_footprint",
    new ResourceTemplate("kicad://footprint/{componentId}/{footprint?}", {
      list: undefined
    }),
    async (uri, params) => {
      const { componentId, footprint } = params;
      logger.debug(`Retrieving footprint for component: ${componentId}${footprint ? ` (${footprint})` : ''}`);
      
      const result = await callKicadScript("get_component_footprint", {
        componentId,
        footprint
      });

      if (!result.success) {
        logger.error(`Failed to retrieve component footprint: ${result.errorDetails}`);
        return {
          contents: [{
            uri: uri.href,
            text: JSON.stringify({
              error: `Failed to retrieve footprint for component ${componentId}`,
              details: result.errorDetails
            }),
            mimeType: "application/json"
          }]
        };
      }

      logger.debug(`Successfully retrieved footprint for component: ${componentId}`);
      return {
        contents: [{
          uri: uri.href,
          text: JSON.stringify(result),
          mimeType: "application/json"
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Component Symbol Resource
  // ------------------------------------------------------
  server.resource(
    "component_symbol",
    new ResourceTemplate("kicad://symbol/{componentId}", {
      list: undefined
    }),
    async (uri, params) => {
      const { componentId } = params;
      logger.debug(`Retrieving symbol for component: ${componentId}`);
      
      const result = await callKicadScript("get_component_symbol", {
        componentId
      });

      if (!result.success) {
        logger.error(`Failed to retrieve component symbol: ${result.errorDetails}`);
        return {
          contents: [{
            uri: uri.href,
            text: JSON.stringify({
              error: `Failed to retrieve symbol for component ${componentId}`,
              details: result.errorDetails
            }),
            mimeType: "application/json"
          }]
        };
      }

      logger.debug(`Successfully retrieved symbol for component: ${componentId}`);

      // If the result includes SVG data, return it as SVG
      if (result.svgData) {
        return {
          contents: [{
            uri: uri.href,
            text: result.svgData,
            mimeType: "image/svg+xml"
          }]
        };
      }

      // Otherwise return the JSON result
      return {
        contents: [{
          uri: uri.href,
          text: JSON.stringify(result),
          mimeType: "application/json"
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Component 3D Model Resource
  // ------------------------------------------------------
  server.resource(
    "component_3d_model",
    new ResourceTemplate("kicad://3d-model/{componentId}/{footprint?}", {
      list: undefined
    }),
    async (uri, params) => {
      const { componentId, footprint } = params;
      logger.debug(`Retrieving 3D model for component: ${componentId}${footprint ? ` (${footprint})` : ''}`);
      
      const result = await callKicadScript("get_component_3d_model", {
        componentId,
        footprint
      });

      if (!result.success) {
        logger.error(`Failed to retrieve component 3D model: ${result.errorDetails}`);
        return {
          contents: [{
            uri: uri.href,
            text: JSON.stringify({
              error: `Failed to retrieve 3D model for component ${componentId}`,
              details: result.errorDetails
            }),
            mimeType: "application/json"
          }]
        };
      }

      logger.debug(`Successfully retrieved 3D model for component: ${componentId}`);
      return {
        contents: [{
          uri: uri.href,
          text: JSON.stringify(result),
          mimeType: "application/json"
        }]
      };
    }
  );

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

```

--------------------------------------------------------------------------------
/src/tools/design-rules.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Design rules tools for KiCAD MCP server
 * 
 * These tools handle design rule checking and configuration
 */

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

// Command function type for KiCAD script calls
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;

/**
 * Register design rule tools with the MCP server
 * 
 * @param server MCP server instance
 * @param callKicadScript Function to call KiCAD script commands
 */
export function registerDesignRuleTools(server: McpServer, callKicadScript: CommandFunction): void {
  logger.info('Registering design rule tools');
  
  // ------------------------------------------------------
  // Set Design Rules Tool
  // ------------------------------------------------------
  server.tool(
    "set_design_rules",
    {
      clearance: z.number().optional().describe("Minimum clearance between copper items (mm)"),
      trackWidth: z.number().optional().describe("Default track width (mm)"),
      viaDiameter: z.number().optional().describe("Default via diameter (mm)"),
      viaDrill: z.number().optional().describe("Default via drill size (mm)"),
      microViaDiameter: z.number().optional().describe("Default micro via diameter (mm)"),
      microViaDrill: z.number().optional().describe("Default micro via drill size (mm)"),
      minTrackWidth: z.number().optional().describe("Minimum track width (mm)"),
      minViaDiameter: z.number().optional().describe("Minimum via diameter (mm)"),
      minViaDrill: z.number().optional().describe("Minimum via drill size (mm)"),
      minMicroViaDiameter: z.number().optional().describe("Minimum micro via diameter (mm)"),
      minMicroViaDrill: z.number().optional().describe("Minimum micro via drill size (mm)"),
      minHoleDiameter: z.number().optional().describe("Minimum hole diameter (mm)"),
      requireCourtyard: z.boolean().optional().describe("Whether to require courtyards for all footprints"),
      courtyardClearance: z.number().optional().describe("Minimum clearance between courtyards (mm)")
    },
    async (params) => {
      logger.debug('Setting design rules');
      const result = await callKicadScript("set_design_rules", params);
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Get Design Rules Tool
  // ------------------------------------------------------
  server.tool(
    "get_design_rules",
    {},
    async () => {
      logger.debug('Getting design rules');
      const result = await callKicadScript("get_design_rules", {});
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Run DRC Tool
  // ------------------------------------------------------
  server.tool(
    "run_drc",
    {
      reportPath: z.string().optional().describe("Optional path to save the DRC report")
    },
    async ({ reportPath }) => {
      logger.debug('Running DRC check');
      const result = await callKicadScript("run_drc", { reportPath });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Add Net Class Tool
  // ------------------------------------------------------
  server.tool(
    "add_net_class",
    {
      name: z.string().describe("Name of the net class"),
      description: z.string().optional().describe("Optional description of the net class"),
      clearance: z.number().describe("Clearance for this net class (mm)"),
      trackWidth: z.number().describe("Track width for this net class (mm)"),
      viaDiameter: z.number().describe("Via diameter for this net class (mm)"),
      viaDrill: z.number().describe("Via drill size for this net class (mm)"),
      uvia_diameter: z.number().optional().describe("Micro via diameter for this net class (mm)"),
      uvia_drill: z.number().optional().describe("Micro via drill size for this net class (mm)"),
      diff_pair_width: z.number().optional().describe("Differential pair width for this net class (mm)"),
      diff_pair_gap: z.number().optional().describe("Differential pair gap for this net class (mm)"),
      nets: z.array(z.string()).optional().describe("Array of net names to assign to this class")
    },
    async ({ name, description, clearance, trackWidth, viaDiameter, viaDrill, uvia_diameter, uvia_drill, diff_pair_width, diff_pair_gap, nets }) => {
      logger.debug(`Adding net class: ${name}`);
      const result = await callKicadScript("add_net_class", {
        name,
        description,
        clearance,
        trackWidth,
        viaDiameter,
        viaDrill,
        uvia_diameter,
        uvia_drill,
        diff_pair_width,
        diff_pair_gap,
        nets
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Assign Net to Class Tool
  // ------------------------------------------------------
  server.tool(
    "assign_net_to_class",
    {
      net: z.string().describe("Name of the net"),
      netClass: z.string().describe("Name of the net class")
    },
    async ({ net, netClass }) => {
      logger.debug(`Assigning net ${net} to class ${netClass}`);
      const result = await callKicadScript("assign_net_to_class", {
        net,
        netClass
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Set Layer Constraints Tool
  // ------------------------------------------------------
  server.tool(
    "set_layer_constraints",
    {
      layer: z.string().describe("Layer name (e.g., 'F.Cu')"),
      minTrackWidth: z.number().optional().describe("Minimum track width for this layer (mm)"),
      minClearance: z.number().optional().describe("Minimum clearance for this layer (mm)"),
      minViaDiameter: z.number().optional().describe("Minimum via diameter for this layer (mm)"),
      minViaDrill: z.number().optional().describe("Minimum via drill size for this layer (mm)")
    },
    async ({ layer, minTrackWidth, minClearance, minViaDiameter, minViaDrill }) => {
      logger.debug(`Setting constraints for layer: ${layer}`);
      const result = await callKicadScript("set_layer_constraints", {
        layer,
        minTrackWidth,
        minClearance,
        minViaDiameter,
        minViaDrill
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Check Clearance Tool
  // ------------------------------------------------------
  server.tool(
    "check_clearance",
    {
      item1: z.object({
        type: z.enum(["track", "via", "pad", "zone", "component"]).describe("Type of the first item"),
        id: z.string().optional().describe("ID of the first item (if applicable)"),
        reference: z.string().optional().describe("Reference designator (for component)"),
        position: z.object({
          x: z.number().optional(),
          y: z.number().optional(),
          unit: z.enum(["mm", "inch"]).optional()
        }).optional().describe("Position to check (if ID not provided)")
      }).describe("First item to check"),
      item2: z.object({
        type: z.enum(["track", "via", "pad", "zone", "component"]).describe("Type of the second item"),
        id: z.string().optional().describe("ID of the second item (if applicable)"),
        reference: z.string().optional().describe("Reference designator (for component)"),
        position: z.object({
          x: z.number().optional(),
          y: z.number().optional(),
          unit: z.enum(["mm", "inch"]).optional()
        }).optional().describe("Position to check (if ID not provided)")
      }).describe("Second item to check")
    },
    async ({ item1, item2 }) => {
      logger.debug(`Checking clearance between ${item1.type} and ${item2.type}`);
      const result = await callKicadScript("check_clearance", {
        item1,
        item2
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Get DRC Violations Tool
  // ------------------------------------------------------
  server.tool(
    "get_drc_violations",
    {
      severity: z.enum(["error", "warning", "all"]).optional().describe("Filter violations by severity")
    },
    async ({ severity }) => {
      logger.debug('Getting DRC violations');
      const result = await callKicadScript("get_drc_violations", { severity });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  logger.info('Design rule tools registered');
}

```

--------------------------------------------------------------------------------
/src/tools/component.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * 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: Record<string, unknown>) => 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.tool(
    "place_component",
    {
      componentId: z.string().describe("Identifier for the component to place (e.g., 'R_0603_10k')"),
      position: z.object({
        x: z.number().describe("X coordinate"),
        y: z.number().describe("Y coordinate"),
        unit: z.enum(["mm", "inch"]).describe("Unit of measurement")
      }).describe("Position coordinates and unit"),
      reference: z.string().optional().describe("Optional desired reference (e.g., 'R5')"),
      value: z.string().optional().describe("Optional component value (e.g., '10k')"),
      footprint: z.string().optional().describe("Optional specific footprint name"),
      rotation: z.number().optional().describe("Optional rotation in degrees"),
      layer: z.string().optional().describe("Optional layer (e.g., 'F.Cu', 'B.SilkS')")
    },
    async ({ componentId, position, reference, value, footprint, rotation, layer }) => {
      logger.debug(`Placing component: ${componentId} at ${position.x},${position.y} ${position.unit}`);
      const result = await callKicadScript("place_component", {
        componentId,
        position,
        reference,
        value,
        footprint,
        rotation,
        layer
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Move Component Tool
  // ------------------------------------------------------
  server.tool(
    "move_component",
    {
      reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
      position: z.object({
        x: z.number().describe("X coordinate"),
        y: z.number().describe("Y coordinate"),
        unit: z.enum(["mm", "inch"]).describe("Unit of measurement")
      }).describe("New position coordinates and unit"),
      rotation: z.number().optional().describe("Optional new rotation in degrees")
    },
    async ({ reference, position, rotation }) => {
      logger.debug(`Moving component: ${reference} to ${position.x},${position.y} ${position.unit}`);
      const result = await callKicadScript("move_component", {
        reference,
        position,
        rotation
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Rotate Component Tool
  // ------------------------------------------------------
  server.tool(
    "rotate_component",
    {
      reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
      angle: z.number().describe("Rotation angle in degrees (absolute, not relative)")
    },
    async ({ reference, angle }) => {
      logger.debug(`Rotating component: ${reference} to ${angle} degrees`);
      const result = await callKicadScript("rotate_component", {
        reference,
        angle
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Delete Component Tool
  // ------------------------------------------------------
  server.tool(
    "delete_component",
    {
      reference: z.string().describe("Reference designator of the component to delete (e.g., 'R5')")
    },
    async ({ reference }) => {
      logger.debug(`Deleting component: ${reference}`);
      const result = await callKicadScript("delete_component", { reference });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Edit Component Properties Tool
  // ------------------------------------------------------
  server.tool(
    "edit_component",
    {
      reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
      newReference: z.string().optional().describe("Optional new reference designator"),
      value: z.string().optional().describe("Optional new component value"),
      footprint: z.string().optional().describe("Optional new footprint")
    },
    async ({ reference, newReference, value, footprint }) => {
      logger.debug(`Editing component: ${reference}`);
      const result = await callKicadScript("edit_component", {
        reference,
        newReference,
        value,
        footprint
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Find Component Tool
  // ------------------------------------------------------
  server.tool(
    "find_component",
    {
      reference: z.string().optional().describe("Reference designator to search for"),
      value: z.string().optional().describe("Component value to search for")
    },
    async ({ reference, value }) => {
      logger.debug(`Finding component with ${reference ? `reference: ${reference}` : `value: ${value}`}`);
      const result = await callKicadScript("find_component", { reference, value });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Get Component Properties Tool
  // ------------------------------------------------------
  server.tool(
    "get_component_properties",
    {
      reference: z.string().describe("Reference designator of the component (e.g., 'R5')")
    },
    async ({ reference }) => {
      logger.debug(`Getting properties for component: ${reference}`);
      const result = await callKicadScript("get_component_properties", { reference });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Add Component Annotation Tool
  // ------------------------------------------------------
  server.tool(
    "add_component_annotation",
    {
      reference: z.string().describe("Reference designator of the component (e.g., 'R5')"),
      annotation: z.string().describe("Annotation or comment text to add"),
      visible: z.boolean().optional().describe("Whether the annotation should be visible on the PCB")
    },
    async ({ reference, annotation, visible }) => {
      logger.debug(`Adding annotation to component: ${reference}`);
      const result = await callKicadScript("add_component_annotation", {
        reference,
        annotation,
        visible
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Group Components Tool
  // ------------------------------------------------------
  server.tool(
    "group_components",
    {
      references: z.array(z.string()).describe("Reference designators of components to group"),
      groupName: z.string().describe("Name for the component group")
    },
    async ({ references, groupName }) => {
      logger.debug(`Grouping components: ${references.join(', ')} as ${groupName}`);
      const result = await callKicadScript("group_components", {
        references,
        groupName
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  // ------------------------------------------------------
  // Replace Component Tool
  // ------------------------------------------------------
  server.tool(
    "replace_component",
    {
      reference: z.string().describe("Reference designator of the component to replace"),
      newComponentId: z.string().describe("ID of the new component to use"),
      newFootprint: z.string().optional().describe("Optional new footprint"),
      newValue: z.string().optional().describe("Optional new component value")
    },
    async ({ reference, newComponentId, newFootprint, newValue }) => {
      logger.debug(`Replacing component: ${reference} with ${newComponentId}`);
      const result = await callKicadScript("replace_component", {
        reference,
        newComponentId,
        newFootprint,
        newValue
      });
      
      return {
        content: [{
          type: "text",
          text: JSON.stringify(result)
        }]
      };
    }
  );

  logger.info('Component management tools registered');
}

```

--------------------------------------------------------------------------------
/python/utils/platform_helper.py:
--------------------------------------------------------------------------------

```python
"""
Platform detection and path utilities for cross-platform compatibility

This module provides helpers for detecting the current platform and
getting appropriate paths for KiCAD, configuration, logs, etc.
"""
import os
import platform
import sys
from pathlib import Path
from typing import List, Optional
import logging

logger = logging.getLogger(__name__)


class PlatformHelper:
    """Platform detection and path resolution utilities"""

    @staticmethod
    def is_windows() -> bool:
        """Check if running on Windows"""
        return platform.system() == "Windows"

    @staticmethod
    def is_linux() -> bool:
        """Check if running on Linux"""
        return platform.system() == "Linux"

    @staticmethod
    def is_macos() -> bool:
        """Check if running on macOS"""
        return platform.system() == "Darwin"

    @staticmethod
    def get_platform_name() -> str:
        """Get human-readable platform name"""
        system = platform.system()
        if system == "Darwin":
            return "macOS"
        return system

    @staticmethod
    def get_kicad_python_paths() -> List[Path]:
        """
        Get potential KiCAD Python dist-packages paths for current platform

        Returns:
            List of potential paths to check (in priority order)
        """
        paths = []

        if PlatformHelper.is_windows():
            # Windows: Check Program Files
            program_files = [
                Path("C:/Program Files/KiCad"),
                Path("C:/Program Files (x86)/KiCad"),
            ]
            for pf in program_files:
                # Check multiple KiCAD versions
                for version in ["9.0", "9.1", "10.0", "8.0"]:
                    path = pf / version / "lib" / "python3" / "dist-packages"
                    if path.exists():
                        paths.append(path)

        elif PlatformHelper.is_linux():
            # Linux: Check common installation paths
            candidates = [
                Path("/usr/lib/kicad/lib/python3/dist-packages"),
                Path("/usr/share/kicad/scripting/plugins"),
                Path("/usr/local/lib/kicad/lib/python3/dist-packages"),
                Path.home() / ".local/lib/kicad/lib/python3/dist-packages",
            ]

            # Also check based on Python version
            py_version = f"{sys.version_info.major}.{sys.version_info.minor}"
            candidates.extend([
                Path(f"/usr/lib/python{py_version}/dist-packages/kicad"),
                Path(f"/usr/local/lib/python{py_version}/dist-packages/kicad"),
            ])

            # Check system Python dist-packages (modern KiCAD 9+ on Ubuntu/Debian)
            # This is where pcbnew.py typically lives on modern systems
            candidates.extend([
                Path(f"/usr/lib/python3/dist-packages"),
                Path(f"/usr/lib/python{py_version}/dist-packages"),
                Path(f"/usr/local/lib/python3/dist-packages"),
                Path(f"/usr/local/lib/python{py_version}/dist-packages"),
            ])

            paths = [p for p in candidates if p.exists()]

        elif PlatformHelper.is_macos():
            # macOS: Check application bundle
            kicad_app = Path("/Applications/KiCad/KiCad.app")
            if kicad_app.exists():
                # Check Python framework path
                for version in ["3.9", "3.10", "3.11", "3.12"]:
                    path = kicad_app / "Contents" / "Frameworks" / "Python.framework" / "Versions" / version / "lib" / f"python{version}" / "site-packages"
                    if path.exists():
                        paths.append(path)

        if not paths:
            logger.warning(f"No KiCAD Python paths found for {PlatformHelper.get_platform_name()}")
        else:
            logger.info(f"Found {len(paths)} potential KiCAD Python paths")

        return paths

    @staticmethod
    def get_kicad_python_path() -> Optional[Path]:
        """
        Get the first valid KiCAD Python path

        Returns:
            Path to KiCAD Python dist-packages, or None if not found
        """
        paths = PlatformHelper.get_kicad_python_paths()
        return paths[0] if paths else None

    @staticmethod
    def get_kicad_library_search_paths() -> List[str]:
        """
        Get platform-appropriate KiCAD symbol library search paths

        Returns:
            List of glob patterns for finding .kicad_sym files
        """
        patterns = []

        if PlatformHelper.is_windows():
            patterns = [
                "C:/Program Files/KiCad/*/share/kicad/symbols/*.kicad_sym",
                "C:/Program Files (x86)/KiCad/*/share/kicad/symbols/*.kicad_sym",
            ]
        elif PlatformHelper.is_linux():
            patterns = [
                "/usr/share/kicad/symbols/*.kicad_sym",
                "/usr/local/share/kicad/symbols/*.kicad_sym",
                str(Path.home() / ".local/share/kicad/symbols/*.kicad_sym"),
            ]
        elif PlatformHelper.is_macos():
            patterns = [
                "/Applications/KiCad/KiCad.app/Contents/SharedSupport/symbols/*.kicad_sym",
            ]

        # Add user library paths for all platforms
        patterns.append(str(Path.home() / "Documents" / "KiCad" / "*" / "symbols" / "*.kicad_sym"))

        return patterns

    @staticmethod
    def get_config_dir() -> Path:
        r"""
        Get appropriate configuration directory for current platform

        Follows platform conventions:
        - Windows: %USERPROFILE%\.kicad-mcp
        - Linux: $XDG_CONFIG_HOME/kicad-mcp or ~/.config/kicad-mcp
        - macOS: ~/Library/Application Support/kicad-mcp

        Returns:
            Path to configuration 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"
        else:
            # Fallback for unknown platforms
            return Path.home() / ".kicad-mcp"

    @staticmethod
    def get_log_dir() -> Path:
        """
        Get appropriate log directory for current platform

        Returns:
            Path to log directory
        """
        config_dir = PlatformHelper.get_config_dir()
        return config_dir / "logs"

    @staticmethod
    def get_cache_dir() -> Path:
        r"""
        Get appropriate cache directory for current platform

        Follows platform conventions:
        - Windows: %USERPROFILE%\.kicad-mcp\cache
        - Linux: $XDG_CACHE_HOME/kicad-mcp or ~/.cache/kicad-mcp
        - macOS: ~/Library/Caches/kicad-mcp

        Returns:
            Path to cache directory
        """
        if PlatformHelper.is_windows():
            return PlatformHelper.get_config_dir() / "cache"
        elif PlatformHelper.is_linux():
            xdg_cache = os.environ.get("XDG_CACHE_HOME")
            if xdg_cache:
                return Path(xdg_cache) / "kicad-mcp"
            return Path.home() / ".cache" / "kicad-mcp"
        elif PlatformHelper.is_macos():
            return Path.home() / "Library" / "Caches" / "kicad-mcp"
        else:
            return PlatformHelper.get_config_dir() / "cache"

    @staticmethod
    def ensure_directories() -> None:
        """Create all necessary directories if they don't exist"""
        dirs_to_create = [
            PlatformHelper.get_config_dir(),
            PlatformHelper.get_log_dir(),
            PlatformHelper.get_cache_dir(),
        ]

        for directory in dirs_to_create:
            directory.mkdir(parents=True, exist_ok=True)
            logger.debug(f"Ensured directory exists: {directory}")

    @staticmethod
    def get_python_executable() -> Path:
        """Get path to current Python executable"""
        return Path(sys.executable)

    @staticmethod
    def add_kicad_to_python_path() -> bool:
        """
        Add KiCAD Python paths to sys.path

        Returns:
            True if at least one path was added, False otherwise
        """
        paths_added = False

        for path in PlatformHelper.get_kicad_python_paths():
            if str(path) not in sys.path:
                sys.path.insert(0, str(path))
                logger.info(f"Added to Python path: {path}")
                paths_added = True

        return paths_added


# Convenience function for quick platform detection
def detect_platform() -> dict:
    """
    Detect platform and return useful information

    Returns:
        Dictionary with platform information
    """
    return {
        "system": platform.system(),
        "platform": PlatformHelper.get_platform_name(),
        "is_windows": PlatformHelper.is_windows(),
        "is_linux": PlatformHelper.is_linux(),
        "is_macos": PlatformHelper.is_macos(),
        "python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
        "python_executable": str(PlatformHelper.get_python_executable()),
        "config_dir": str(PlatformHelper.get_config_dir()),
        "log_dir": str(PlatformHelper.get_log_dir()),
        "cache_dir": str(PlatformHelper.get_cache_dir()),
        "kicad_python_paths": [str(p) for p in PlatformHelper.get_kicad_python_paths()],
    }


if __name__ == "__main__":
    # Quick test/diagnostic
    import json
    info = detect_platform()
    print("Platform Information:")
    print(json.dumps(info, indent=2))

```
Page 1/2FirstPrevNextLast