kicad-mcp/CLAUDE.md
Ryan Malloy 4ae38fed59 Rebuild on FastMCP 3 with src-layout and kicad-sch-api integration
Migrate from FastMCP 2.14.5 to 3.1.0 with complete architectural
overhaul. Adopt src-layout packaging, lazy config functions to
eliminate .env race condition, and decorator-based tool registration.

Consolidate 14 tool modules into 8 focused modules (33 tools total).
Add 9 new schematic tools via kicad-sch-api for creating and
manipulating .kicad_sch files. Drop pandas dependency (BOM uses
stdlib csv). Remove ~17k lines of stubs, over-engineering, and
dead code.

All checks pass: ruff clean, mypy 0 errors, 17/17 tests green.
2026-03-03 18:26:54 -07:00

136 lines
5.4 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code when working with the mckicad codebase.
## Development Commands
- `make install` - Install dependencies with uv (creates .venv)
- `make run` - Start the MCP server (`uv run python main.py`)
- `make test` - Run all tests (`uv run pytest tests/ -v`)
- `make test <file>` - Run a specific test file
- `make lint` - Lint with ruff + mypy (`src/mckicad/` and `tests/`)
- `make format` - Auto-format with ruff
- `make build` - Build package
- `make clean` - Remove build artifacts and caches
Python 3.10+ required. Uses `uv` for everything. Configure via `.env` (copy `.env.example`).
## Architecture
mckicad is a FastMCP 3 server for KiCad electronic design automation. It uses src-layout packaging with `hatchling` as the build backend.
### Project Structure
```
src/mckicad/
__init__.py # __version__ only
server.py # FastMCP 3 server + lifespan + module imports
config.py # Lazy config functions (no module-level env reads)
tools/
schematic.py # kicad-sch-api: create/edit schematics (9 tools)
project.py # Project discovery and structure (3 tools)
drc.py # DRC checking + manufacturing constraints (4 tools)
bom.py # BOM generation and export (2 tools)
export.py # Gerber, drill, PDF, SVG via kicad-cli (4 tools)
routing.py # FreeRouting autorouter integration (3 tools)
analysis.py # Board validation + real-time analysis (3 tools)
pcb.py # IPC-based PCB manipulation via kipy (5 tools)
resources/
projects.py # kicad://projects resource
files.py # kicad://project/{path} resource
prompts/
templates.py # debug_pcb, analyze_bom, design_circuit, debug_schematic
utils/
kicad_cli.py # KiCad CLI detection and execution
path_validator.py # Path security / directory traversal prevention
secure_subprocess.py # Safe subprocess execution with timeouts
ipc_client.py # kipy IPC wrapper for live KiCad connection
freerouting.py # FreeRouting JAR engine
file_utils.py # Project file discovery
kicad_utils.py # KiCad path detection, project search
tests/
conftest.py # Shared fixtures (tmp dirs, project paths)
test_*.py # Per-module test files
main.py # Entry point: .env loader + server start
```
### Key Design Decisions
**Lazy config** (`config.py`): All environment-dependent values are accessed via functions (`get_search_paths()`, `get_kicad_user_dir()`) called at runtime, not at import time. Static constants (`KICAD_EXTENSIONS`, `TIMEOUT_CONSTANTS`, `COMMON_LIBRARIES`) remain as module-level dicts since they don't read env vars. This eliminates the .env load-order race condition.
**Decorator-based tool registration**: Each tool module imports `mcp` from `server.py` and decorates functions with `@mcp.tool()` at module level. `server.py` imports the modules to trigger registration. No `register_*_tools()` boilerplate.
**Schematic abstraction point**: `tools/schematic.py` uses `kicad-sch-api` for file-level schematic manipulation. The `_get_schematic_engine()` helper exists as a swap point for when kipy adds schematic IPC support.
**Dual-mode operation**: PCB tools work via IPC (kipy, requires running KiCad) or CLI (kicad-cli, batch mode). Tools degrade gracefully when KiCad isn't running.
### Tool Registration Pattern
```python
# tools/example.py
from mckicad.server import mcp
@mcp.tool()
def my_tool(param: str) -> dict:
"""Tool description for the calling LLM."""
return {"success": True, "data": "..."}
```
### Tool Return Convention
All tools return dicts with at least `success: bool`. On failure, include `error: str`. On success, include relevant data fields.
## Adding New Features
1. Choose the right module (or create one in `tools/`)
2. Import `mcp` from `mckicad.server`
3. Decorate with `@mcp.tool()` and add a clear docstring
4. If new module: add import in `server.py`
5. Write tests in `tests/test_<module>.py`
## Security
- All file paths validated via `utils/path_validator.py` before access
- External commands run through `utils/secure_subprocess.py` with timeouts
- KiCad CLI commands sanitized — no shell injection
- `main.py` inline .env loader runs before any mckicad imports
## Environment Variables
- `KICAD_USER_DIR` - KiCad user config directory
- `KICAD_SEARCH_PATHS` - Comma-separated project search paths
- `KICAD_CLI_PATH` - Explicit kicad-cli path
- `FREEROUTING_JAR_PATH` - Path to FreeRouting JAR
- `LOG_LEVEL` - Logging level (default: INFO)
## Testing
Markers: `unit`, `integration`, `requires_kicad`, `slow`, `performance`
```bash
make test # all tests
make test tests/test_schematic.py # one file
uv run pytest -m "unit" # by marker
```
## Entry Point
```toml
[project.scripts]
mckicad = "mckicad.server:main"
```
Run via `uvx mckicad`, `uv run mckicad`, or `uv run python main.py`.
## FreeRouting Setup
1. Download JAR from https://freerouting.app/
2. Place at `~/freerouting.jar`, `/usr/local/bin/freerouting.jar`, or `/opt/freerouting/freerouting.jar`
3. Install Java runtime
4. Verify with `check_routing_capability()` tool
5. Or set `FREEROUTING_JAR_PATH` in `.env`
## Logging
Logs go to `mckicad.log` in project root, overwritten each start. Never use `print()` — MCP uses stdin/stdout for JSON-RPC transport.