MCP API and tool reference

KiPilot is a stdio Model Context Protocol server for a live KiCad PCB session. This page documents the transport model, runtime configuration, safety controls, operational expectations, and the full tool surface exposed to MCP-aware hosts.

Overview

KiPilot exposes KiCad PCB actions as JSON-serializable MCP tools over stdio.

KiPilot is designed for MCP hosts such as GitHub Copilot in VS Code, Claude, or any other client that can launch a stdio MCP server and exchange tool calls. It does not expose an HTTP API, it does not launch KiCad for you, and it assumes that the PCB you want to inspect or edit is already open inside a user-controlled KiCad GUI session.

What KiPilot provides

  • Stdio MCP transport with a stable, agent-friendly tool surface.
  • Read-only board inspection for documents, footprints, pads, nets, net classes, connectivity, graphics, tracks, vias, zones, standalone board text, origins, and title blocks.
  • Controlled PCB mutations with dry-run previews, mutation gating, and explicit force guards for destructive actions.
  • Operational logging to stderr and optionally to a file.

What KiPilot does not provide

  • No headless KiCad management or GUI automation.
  • No committed schematic automation baseline in the current KiCad 10 target.
  • No generic unrestricted arbitrary-item updater.
  • No stdout logging, because stdout is reserved for MCP protocol traffic.
  1. Launch KiCad yourself Open the target project and the PCB Editor before running board-aware MCP tools.
  2. Start KiPilot through an MCP host Point the host at the KiPilot Python environment and run the stdio server module.
  3. Verify reachability first Use ping_kicad or get_kicad_version before any geometry or mutation request.
  4. Query, preview, then apply Round-trip item IDs from read tools, prefer dry_run=true first, then apply and save deliberately.
Compatibility

The current baseline targets KiCad 10 PCB workflows with a running GUI instance.

KiPilot is built around the official kicad-python binding and the KiCad GUI IPC endpoint. The implementation is intentionally scoped to the capabilities validated against the current repository baseline.

Validated baseline

  • Python 3.11+ supported. Use a stable CPython 3.11, 3.12, or 3.13 release.
  • KiCad 10.x is the documented target for the current tool surface.
  • One running KiCad instance at a time is strongly recommended during setup and debugging.
  • Board-context tools assume the PCB Editor endpoint is available, not only the Project Manager.

Scope boundaries

  • GUI IPC only. No committed headless or daemonized KiCad operation.
  • PCB Editor first. Schematic tooling remains future or version-gated work.
  • Export and plotting are not part of the current KiCad 10 baseline.
  • Some queries depend on KiCad 10.0.1+ level APIs inside the running application.

Avoid preview or alpha Python interpreters because the native dependency chain may not publish compatible wheels for them yet.

Architecture

The server is a FastMCP stdio process that creates a fresh KiCad IPC client per tool call.

This design keeps tool execution isolated, aligns well with MCP host process models, and keeps error boundaries simple. Blocking KiCad calls are wrapped behind an async-friendly interface so MCP hosts still see normal asynchronous tool execution.

MCP host
  -> stdio transport
  -> KiPilot FastMCP server
  -> per-tool KiCadIpcClient
  -> official kicad-python binding
  -> running KiCad GUI IPC endpoint
  -> active project / active PCB board objects

Transport model

  • The public integration surface is MCP over stdio only.
  • MCP hosts discover tools automatically; users normally do not handcraft raw protocol frames.
  • Stdout must remain protocol-clean, which is why logs go to stderr or to a file.

Connection model

  • Every tool call builds a fresh runtime config and client instance.
  • The server uses the official KiCad socket and token when provided.
  • If those variables are absent, the binding falls back to platform defaults.

Why this matters for agents

  • Failures stay local to a single tool call.
  • Dry-run previews can be executed without unlocking write access.
  • Mutation operations can include narrow commit messages and deterministic guardrails.

Logging model

  • Server startup is logged once per process.
  • Each tool call records start, finish, duration, and warning/error outcomes.
  • Long argument payloads are summarized to keep logs useful without becoming unreadable.
Installation

Install KiPilot from the cloned repository and verify that KiCad is already running.

Use an isolated Python environment when possible. A virtual environment is recommended because it keeps KiPilot's runtime dependencies separate from system Python, but it is not a product requirement if your team already manages Python environments another way.

Windows helper

.\start-kipilot-mcp.ps1 -SkipRun

The helper creates or reuses .venv, installs the KiPilot runtime package, applies conservative default environment variables, and exits before starting the server. Run the same script without -SkipRun for a manual terminal launch.

Manual install

python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install .

On macOS or Linux, activate the environment with source .venv/bin/activate. For development, install the editable package with test and lint dependencies:

python -m pip install -e ".[dev]"

You can run the server directly for manual checks, although most users will launch it through their MCP host:

kipilot-mcp

# or
python -m kipilot_mcp.server

Before first use

  • Start KiCad and open the target project yourself.
  • Open the PCB Editor, not only the project window.
  • If needed in your KiCad build, enable the API under Preferences -> Plugins -> Enable KiCad API.
  • Keep the setup simple by using one KiCad instance at a time.

Endpoint resolution

  • When KiCad launches an API plugin, it can provide KICAD_API_SOCKET and KICAD_API_TOKEN.
  • When launching from VS Code or another host, you may need to pass those values yourself.
  • If ping_kicad works but board tools do not, you are likely connected to the wrong endpoint and need the PCB Editor endpoint.
Configuration

Runtime behavior is controlled entirely by environment variables.

KiPilot reads configuration at startup and again for each tool call. That makes MCP host configuration the source of truth for endpoint selection, timeouts, mutation permissions, commit prefixes, and logging.

# Official KiCad IPC values when available
KICAD_API_SOCKET=...
KICAD_API_TOKEN=...

# KiPilot runtime values
KIPILOT_KICAD_CLIENT_NAME=kipilot-mcp
KIPILOT_KICAD_TIMEOUT_MS=60000
KIPILOT_ENABLE_MUTATIONS=0
KIPILOT_COMMIT_MESSAGE_PREFIX=KiPilot MCP
KIPILOT_LOG_LEVEL=INFO
KIPILOT_LOG_FILE=.logs/kipilot-mcp.log

Endpoint and identity settings

  • KICAD_API_SOCKET: explicit socket or named-pipe endpoint when the default is not correct.
  • KICAD_API_TOKEN: token for KiCad API authentication when provided by KiCad.
  • KIPILOT_KICAD_CLIENT_NAME: the logical client name sent to KiCad. Defaults to kipilot-mcp.

Performance and timeout settings

  • KIPILOT_KICAD_TIMEOUT_MS: IPC timeout in milliseconds. Default is 60000.
  • The default is intentionally high because zone refills and some board operations can take tens of seconds on large designs.
  • Increase the timeout further on slower machines or unusually large boards.

Mutation controls

  • KIPILOT_ENABLE_MUTATIONS: when false, write tools only work in dry-run mode.
  • KIPILOT_COMMIT_MESSAGE_PREFIX: prefix for grouped write commits such as KiPilot MCP: move_footprint.
  • Destructive tools and high-risk board-state changes still require force=true even when mutations are enabled.

Logging controls

  • KIPILOT_LOG_LEVEL: one of DEBUG, INFO, WARNING, ERROR, or CRITICAL.
  • KIPILOT_LOG_FILE: optional path for persistent structured logs in addition to stderr.
  • Never redirect logs to stdout, because stdout is the MCP wire.
MCP hosts

Any stdio-capable MCP client can launch KiPilot with the same command model.

The exact configuration file format depends on the host, but the core command shape is identical: run the Python interpreter inside the KiPilot environment and execute -m kipilot_mcp.server.

GitHub Copilot in VS Code

{
  "servers": {
    "kipilot-mcp": {
      "type": "stdio",
      "command": "${workspaceFolder}\\.venv\\Scripts\\python.exe",
      "args": ["-m", "kipilot_mcp.server"],
      "env": {
        "KIPILOT_KICAD_CLIENT_NAME": "kipilot-mcp",
        "KIPILOT_KICAD_TIMEOUT_MS": "60000",
        "KIPILOT_LOG_LEVEL": "INFO",
        "KIPILOT_LOG_FILE": ".logs/kipilot-mcp.log"
      }
    }
  }
}

Generic stdio MCP host

{
  "mcpServers": {
    "kipilot-mcp": {
      "command": "C:\\absolute\\path\\to\\.venv\\Scripts\\python.exe",
      "args": ["-m", "kipilot_mcp.server"],
      "env": {
        "KIPILOT_KICAD_CLIENT_NAME": "kipilot-mcp",
        "KIPILOT_KICAD_TIMEOUT_MS": "60000",
        "KIPILOT_LOG_LEVEL": "INFO",
        "KIPILOT_LOG_FILE": ".logs/kipilot-mcp.log"
      }
    }
  }
}
  • Restart the host after changing server configuration.
  • Add KICAD_API_SOCKET and KICAD_API_TOKEN only when the default endpoint is not correct.
  • Use a workspace-relative log file only when the host launches the server from a predictable working directory.
API conventions

All tools return JSON objects with predictable success, error, identity, and unit conventions.

The server is optimized for MCP hosts and agent workflows, so responses deliberately echo target identifiers, requested changes, and normalized geometry. That makes it easier for an agent to preview, explain, and then safely apply the same change.

Success and failure shape

# Success
{
  "ok": true,
  "...": "tool-specific fields"
}

# Failure
{
  "ok": false,
  "message": "Human-readable explanation",
  "error": "Underlying error when available"
}

Common serialization patterns

# Position or point
{
  "x_nm": 1500000,
  "y_nm": 2500000,
  "x_mm": 1.5,
  "y_mm": 2.5
}

# Layer
{
  "id": 0,
  "name": "F.Cu"
}

# Net
{
  "name": "+3V3",
  "code": 7
}

Units and coordinates

  • Tool inputs use millimeters for geometry fields such as x_mm, y_mm, width_mm, and diameter_mm.
  • Most outputs provide both millimeters and nanometers for deterministic round-tripping.
  • Outline and polyline inputs are lists of point objects with x_mm and y_mm.

Identity and lookup rules

  • Use the returned item IDs from read tools for later mutation calls whenever possible.
  • Footprint operations typically allow either reference or footprint_id.
  • Track, zone, via, and generic item operations are ID-driven.

Dry runs and commit groups

  • Most write tools accept dry_run and return a preview of the post-change state without persisting it.
  • When mutations are enabled, many write tools wrap operations in a KiCad commit group.
  • save_board persists the current board file and does not create a separate commit group.

Dangerous operations

  • kicad_revert_board, kicad_delete_items, and live kicad_set_enabled_layers calls require force=true.
  • These tools also report dangerous: true in their response payloads.
  • Enabling mutations does not bypass the force guard.
Tool reference

The current MCP surface contains 41 tools across discovery, inspection, controlled mutation, editing, and persistence.

Every tool listed below is directly exposed through the MCP server. Grouping here is for documentation only; the host sees each item as a flat callable tool.

Connection and discovery

3 tools for endpoint health, version reporting, and document visibility.

Inspection and lookup

21 tools for board metadata, geometry, connectivity, search, board text lookup, and project metadata expansion.

Controlled mutation

9 tools for visibility and layer state, origins, title block data, board text edits, footprints, and safe revert flows.

Advanced editing and persistence

8 tools for tracks, vias, zones, whitelisted batch updates, deletion, refill, and save.

Current release emphasis

The latest documentation pass adds full coverage for pads, generic graphics, project net classes, board netclass lookups, connectivity tracing, active-layer control, and guarded enabled-layer updates.

Connection and document discovery

ping_kicad() is the primary health probe. It takes no arguments and verifies that the KiCad IPC endpoint is reachable.

  • Returns socket_path, client_name, kicad_version, api_version, and api_version_matches_binding.
  • Typical success message: KiCad IPC endpoint is reachable.
  • Typical failure explains that KiCad is not reachable and includes the underlying error when available.

get_kicad_version() uses the same underlying reachability and version probe, but is named for hosts and prompts that specifically ask for version data.

  • No arguments.
  • Useful as the second validation check after ping_kicad.

kicad_list_open_documents(document_types=None) returns the active board and project documents or filters by explicit KiCad document type IDs.

  • document_types is optional and accepts a list of integer type IDs.
  • Returns documents, count, and a source indicator describing how the active document set was resolved.

Board context, stackup, and project metadata

kicad_get_board_summary() is the high-level board inventory tool.

  • No arguments.
  • Returns serialized board metadata plus counts for footprints, nets, tracks, vias, zones, graphics, and text items.
  • Also returns copper_layer_count and the active layer ID.

kicad_get_board_outline() extracts Edge.Cuts-derived geometry for the current PCB.

  • No arguments.
  • Use this to understand overall board extents and shape before placement or routing changes.

kicad_get_stackup() returns stackup layers together with visible and enabled layer sets.

  • No arguments.
  • Returns physical or logical stackup entries, including dielectric information when exposed by the binding.
  • Also returns visible_layers and enabled_layers as serialized layer objects.

kicad_get_project_text_variables() returns project-scoped text variables for the active board project.

  • No arguments.
  • Returns a project descriptor plus both a map and an array representation of available text variables.

kicad_expand_project_text_variables(text) expands project variables inside one text fragment.

  • text is required and is returned back as input_text beside the expanded result.
  • Use this when an agent needs to preview the concrete value of title-block or project-driven strings before writing them elsewhere.

kicad_get_project_net_classes() returns project net classes with serialized rule values.

  • No arguments.
  • Returns the project descriptor, a count, and per-netclass rule fields such as clearance, track width, via diameter, and via drill in both nanometers and millimeters.

Search, inspection, and object lookup

kicad_get_footprints(limit=200) returns placed footprints with IDs, references, values, positions, orientations, layers, and lock state.

  • limit defaults to 200.
  • Use returned footprint IDs in later mutation tools for exact targeting.

kicad_find_footprints(reference=None, footprint_id=None, text_query=None, layer=None, area=None, limit=200) performs focused footprint lookup.

  • reference and footprint_id narrow by identity.
  • text_query searches text-bearing footprint fields exposed by the binding.
  • layer accepts a numeric ID or canonical name such as F.Cu.
  • area expects x_min_mm, y_min_mm, x_max_mm, and y_max_mm.
  • Returns the normalized query block so clients can see how the request was resolved.

kicad_get_nets(limit=200) returns serialized net names and codes.

  • Use net names from this tool as safe inputs for routing or track-editing tools.

kicad_get_items_by_net(net_name, item_types=None, layer=None, area=None, limit=200) returns heterogeneous board items attached to a named net.

  • net_name is required.
  • item_types can narrow the KiCad item classes to include.
  • layer and area work as additional geometry filters.
  • This is useful when an agent must find all board objects associated with a signal before editing.

kicad_get_items_by_netclass(netclass_name, item_types=None, layer=None, area=None, limit=200) returns heterogeneous board items associated with a named net class.

  • netclass_name is required and is resolved against the active project.
  • Use this when inspection should follow design-rule intent rather than a single explicit net.
  • layer, area, and optional KiCad item_types behave like the net-based lookup tool.

kicad_get_netclass_for_nets(net_names) returns the effective net class for one or more named nets.

  • net_names is a required non-empty string array.
  • Useful for validating whether a proposed routing change belongs to the expected design-rule bucket before editing geometry.

kicad_get_connected_items(item_id, item_types=None, layer=None, area=None, limit=200) traces copper-connected items from a source item.

  • item_id is required and should come from an earlier read tool.
  • The response includes the serialized source_item plus the connected item set, making it suitable for explainable agent workflows.

kicad_get_tracks(limit=200), kicad_get_vias(limit=200), and kicad_get_zones(limit=200) return serialized geometry collections.

  • Tracks include start and end points, layer, net, lock state, width, length, and bounding box.
  • Vias include position, net, diameter, drill diameter, lock state, and via type.
  • Zones include net, layers, fill status, priority, type, bounding box, and outline geometry.

kicad_get_pads(net_name=None, layer=None, area=None, limit=200) returns serialized pads with optional net, layer, and area filters.

  • Results include pad ID, number, position, pad type, net, and padstack-derived layer presence.
  • This is the right starting point for pad-aware review flows before any future pad-geometry helpers are introduced.

kicad_get_graphics(layer=None, area=None, limit=200) returns generic board graphics beyond the derived board outline.

  • Use it to inspect silkscreen, fabrication, or other board-shape graphics directly instead of only the Edge.Cuts outline.
  • Each result includes its item ID, kind, layer, lock state, bounding box, and shape points exposed by the binding.

kicad_get_board_text(text_id=None, text_query=None, layer=None, exact=False, limit=200) returns standalone board text and board text box items.

  • Use text_query for substring search or set exact=true for an exact text match.
  • layer accepts a numeric ID or canonical name such as F.SilkS.
  • Results return the text item ID, current text content, layer, lock state, and position or text box corners.

kicad_get_board_origins() and kicad_get_title_block() expose board metadata often needed in automation workflows.

  • The origin tool returns both grid and drill origins.
  • The title block tool returns title, revision, date, company, and comment slots.

Visibility and board-state mutation

kicad_set_visible_layers(layers, dry_run=False, commit_message=None) updates the visible layer set.

  • layers is required and accepts layer names or numeric IDs.
  • Returns previous visible layers, resolved target layers, and the resulting visible layer set.
  • When mutations are enabled, the operation is committed under the configured commit prefix unless an explicit commit_message is provided.

kicad_set_active_layer(layer, dry_run=False, commit_message=None) updates the current active layer in the board editor.

  • layer is required and accepts a numeric layer ID or canonical name such as F.SilkS.
  • Returns both the previous and resulting active layer as serialized layer objects.

kicad_set_enabled_layers(non_copper_layers, dry_run=False, commit_message=None, force=False) updates enabled non-copper layers while preserving the current copper layer count.

  • The tool intentionally does not expose arbitrary copper-layer-count edits.
  • Dry-run mode previews the resulting enabled layer set without requiring live write access.
  • Live mode requires force=true because disabling layers can delete content already placed on those layers.

kicad_revert_board(dry_run=False, force=False) reverts unsaved board changes back to the last saved state.

  • This tool is destructive and requires force=true.
  • It supports dry-run preview and marks the response with dangerous: true.
  • Unlike grouped commit mutations, the live operation calls the board revert directly.
  • The implementation includes targeted retry behavior for transient timeout or busy conditions.

Footprint placement and board metadata mutation

kicad_move_footprint(x_mm, y_mm, reference=None, footprint_id=None, dry_run=False, commit_message=None) moves a footprint to an absolute board coordinate.

  • Requires either reference or footprint_id.
  • Returns the previous serialized footprint, the updated footprint preview or result, and the requested position.

kicad_rotate_footprint(orientation_degrees, reference=None, footprint_id=None, dry_run=False, commit_message=None) sets footprint orientation in degrees.

  • Supports dry runs and the same targeting rules as kicad_move_footprint.
  • Returns both previous and resulting footprint state.

kicad_set_board_origin(origin_type, x_mm, y_mm, dry_run=False, commit_message=None) updates the grid or drill/place origin.

  • origin_type accepts grid, drill, 1, or 2.
  • Returns previous and requested origin coordinates with a normalized origin type object.

kicad_set_title_block(title=None, revision=None, date=None, company=None, comments=None, dry_run=False, commit_message=None) merges partial title block updates.

  • At least one field or comment change must be provided.
  • comments is a mapping keyed by title block comment slot numbers.
  • Dry-run responses include both the previous title block and the merged post-change title block.

kicad_update_board_text(text_id, new_text, expected_current_text=None, dry_run=False, commit_message=None) updates one standalone board text or board text box by item ID.

  • text_id and new_text are required.
  • Use expected_current_text as a stale-data guard when the text must still match an exact known value before the write is applied.
  • Dry-run responses include both the previous text item and the post-change preview so an agent can verify the exact silkscreen label before writing.

Creation and targeted geometry editing

kicad_create_track_segments(points, layer, width_mm, net_name=None, locked=False, dry_run=False, commit_message=None) creates straight track segments from a polyline.

  • points is an ordered list of board-space points in millimeters.
  • The tool creates one segment between each consecutive point pair.
  • Returns the resulting track list, layer, net, and count.

kicad_create_via(x_mm, y_mm, diameter_mm, drill_diameter_mm, net_name=None, via_type=1, locked=False, dry_run=False, commit_message=None) creates a via at an absolute position.

  • The default via_type is 1, which maps to through.
  • Returns position, diameter, drill diameter, via type, net, and the serialized via result.

kicad_update_track_geometry(track_id, start_x_mm=None, start_y_mm=None, end_x_mm=None, end_y_mm=None, width_mm=None, layer=None, net_name=None, locked=None, dry_run=False, commit_message=None) updates one straight track.

  • track_id is required.
  • At least one geometry or metadata field must change.
  • Supports endpoint edits, width changes, layer reassignment, net reassignment, and lock-state updates.

kicad_update_zone_outline(zone_id, outline_points, dry_run=False, commit_message=None) replaces the outer polygon of a zone.

  • zone_id and outline_points are required.
  • The outline must contain at least three points.
  • The tool focuses on the primary zone outline rather than exposing a generic full-zone editor.

Whitelisted batch updates, deletion, refill, and save

kicad_update_items(updates, dry_run=False, commit_message=None) is the controlled batch updater.

  • updates must be a non-empty array of objects.
  • Each target item may only appear once per request.
  • Only footprint, track, and zone kinds are allowed.
  • Unsupported fields are rejected explicitly instead of being ignored silently.
# Whitelisted update shapes
{
  "kind": "footprint",
  "reference": "R1",
  "footprint_id": "optional-id",
  "x_mm": 10.0,
  "y_mm": 12.0,
  "orientation_degrees": 90.0
}

{
  "kind": "track",
  "track_id": "track-id",
  "start_x_mm": 1.0,
  "start_y_mm": 2.0,
  "end_x_mm": 6.0,
  "end_y_mm": 2.0,
  "width_mm": 0.25,
  "layer": "F.Cu",
  "net_name": "+3V3",
  "locked": false
}

{
  "kind": "zone",
  "zone_id": "zone-id",
  "outline_points": [
    {"x_mm": 0.0, "y_mm": 0.0},
    {"x_mm": 10.0, "y_mm": 0.0},
    {"x_mm": 10.0, "y_mm": 8.0},
    {"x_mm": 0.0, "y_mm": 8.0}
  ]
}

kicad_delete_items(item_ids, dry_run=False, commit_message=None, force=False) removes board items by KiCad item ID.

  • Requires a non-empty list of item IDs.
  • Requires force=true because it is destructive.
  • Dry-run responses include the fully serialized target items.

kicad_refill_zones(zone_ids=None, dry_run=False, commit_message=None) refills all zones or a selected subset.

  • When zone_ids is omitted, the server can refill all zones on the board.
  • On large boards this can be slow, so the server includes targeted retry behavior for transient busy states.

kicad_save_board(dry_run=False) persists the currently open board file.

  • Dry-run mode reports the target filename without writing.
  • Live mode calls the board save operation directly.
Example workflows

Use a read, preview, apply, then save flow for the safest agent-driven work.

KiPilot works best when an agent first discovers the exact target objects, previews the intended change, and only then applies the mutation. The examples below show the expected rhythm.

Recommended first prompts

  • Run ping_kicad and tell me if KiCad is reachable.
  • Run get_kicad_version and show the KiCad and IPC API version.
  • Summarize the current board, then list the first ten footprints and nets.

Safe edit pattern

  • Resolve the target with kicad_find_footprints, kicad_get_board_text, kicad_get_pads, kicad_get_tracks, or kicad_get_zones.
  • Preview the change with the matching write tool and dry_run=true.
  • Apply the same change with mutations enabled.
  • Use kicad_save_board when you want the board file written to disk.

Example: move a footprint safely

1. kicad_find_footprints(reference="R1")
2. kicad_move_footprint(reference="R1", x_mm=42.0, y_mm=18.5, dry_run=true)
3. kicad_move_footprint(reference="R1", x_mm=42.0, y_mm=18.5, dry_run=false)
4. kicad_save_board(dry_run=false)

Example: update a silkscreen board label safely

1. kicad_get_board_text(text_query="Mainboard v1.1", layer="F.SilkS", exact=true)
2. kicad_update_board_text(
     text_id="board-text-id",
     new_text="Mainboard v1.2",
     expected_current_text="Mainboard v1.1",
     dry_run=true
   )
3. kicad_update_board_text(
     text_id="board-text-id",
     new_text="Mainboard v1.2",
     expected_current_text="Mainboard v1.1",
     dry_run=false
   )
4. kicad_save_board(dry_run=false)

Example: batch update with a whitelist

kicad_update_items(
  updates=[
    {
      "kind": "footprint",
      "footprint_id": "footprint-id",
      "orientation_degrees": 45.0
    },
    {
      "kind": "track",
      "track_id": "track-id",
      "width_mm": 0.3,
      "locked": true
    },
    {
      "kind": "zone",
      "zone_id": "zone-id",
      "outline_points": [
        {"x_mm": 0.0, "y_mm": 0.0},
        {"x_mm": 12.0, "y_mm": 0.0},
        {"x_mm": 12.0, "y_mm": 6.0},
        {"x_mm": 0.0, "y_mm": 6.0}
      ]
    }
  ],
  dry_run=true
)

Example: trace a power network by design-rule class

1. kicad_get_project_net_classes()
2. kicad_get_items_by_netclass("Power", layer="F.Cu")
3. kicad_get_connected_items(item_id="track-id")
4. kicad_get_netclass_for_nets(net_names=["+3V3", "GND"])

Example: preview a board-state change before a live layer update

1. kicad_get_stackup()
2. kicad_set_active_layer(layer="F.SilkS", dry_run=true)
3. kicad_set_enabled_layers(non_copper_layers=["F.SilkS", "Edge.Cuts"], dry_run=true)
4. kicad_set_enabled_layers(non_copper_layers=["F.SilkS", "Edge.Cuts"], dry_run=false, force=true)
Operations

Logging, retries, timeout sizing, and mutation guardrails are part of the runtime contract.

KiPilot is meant for real board sessions, so operational behavior matters as much as the raw tool catalog. The current implementation includes deliberate choices around logs, retries, and write safety.

Logging

  • Logs go to stderr by default.
  • Set KIPILOT_LOG_FILE to persist the same records to disk.
  • Server startup, tool start, tool finish, duration, warnings, and exceptions are logged.

Timeouts

  • The default IPC timeout is 60000 ms.
  • Large zone refills may still require more time on heavier boards.
  • If you observe timeouts in practice, increase the timeout in the MCP host environment instead of repeatedly retrying manually.

Targeted retries

  • kicad_revert_board retries transient timeout-like failures.
  • kicad_refill_zones retries selected busy or timeout conditions.
  • The retry policy is intentionally narrow and not applied to arbitrary geometry creation or mutation calls.

Write safety

  • Mutations are disabled unless KIPILOT_ENABLE_MUTATIONS=1.
  • Dry-run previews remain available when writes are disabled.
  • Destructive and high-risk board-state tools still require force=true even after enabling mutations.
Troubleshooting

Most failures come from endpoint selection, host config drift, or deliberate safety gates.

The fastest way to debug a problem is to verify the basic connection path first, then inspect the server log output, then confirm that the board and tool inputs actually match the current KiCad session.

ping_kicad fails

  • Make sure KiCad is already running.
  • Verify that the API is enabled in KiCad when your installation requires it.
  • If the host is not using the correct endpoint, pass KICAD_API_SOCKET and KICAD_API_TOKEN explicitly.

Health checks pass but board tools fail

  • Open the PCB Editor, not only the project window.
  • Reconnect to the PCB Editor endpoint if the current endpoint only exposes project-level APIs.
  • Use one KiCad instance while stabilizing the setup.

Mutation tools refuse to run

  • Set KIPILOT_ENABLE_MUTATIONS=1 for live writes.
  • Use dry_run=true if you only want a preview.
  • For kicad_revert_board, kicad_delete_items, and live kicad_set_enabled_layers calls, also pass force=true.

Zone refill or revert times out

  • Increase KIPILOT_KICAD_TIMEOUT_MS.
  • Check the log for tool duration and failure messages.
  • Expect long refill operations on large copper pours.

kicad_update_items rejects a payload

  • Confirm that the kind is one of footprint, track, or zone.
  • Remove unsupported keys instead of assuming they will be ignored.
  • Do not target the same item more than once in a single request.

No useful logs available

  • Set KIPILOT_LOG_LEVEL=INFO or DEBUG.
  • Set KIPILOT_LOG_FILE to a writable path.
  • Remember that the server intentionally does not log to stdout.

Python or install problems on Windows

  • Use a stable Python release such as 3.13, 3.12, or 3.11.
  • Avoid preview or alpha interpreters for this dependency stack.
  • Recreate the virtual environment if the interpreter path changed underneath it.