MCP Server Usage Examples

This guide provides examples of using the kicad-sch-api MCP server for programmatic circuit generation.

Table of Contents

Setup

Prerequisites

# Install kicad-sch-api
cd /path/to/kicad-sch-api
uv pip install -e .

# Verify MCP server works
uv run kicad-sch-mcp
# Press Ctrl+C to stop

Claude Code Integration

The .mcp.json file in the project root automatically loads the MCP server:

{
  "mcpServers": {
    "kicad-sch-api": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "kicad-sch-mcp"]
    }
  }
}

Start Claude Code normally (NOT with --dangerously-skip-permissions):

cd /path/to/kicad-sch-api
claude

Approve the MCP server when prompted, then verify:

"What MCP tools do you have available?"

You should see 15 tools across 4 categories.

Basic Component Operations

Example 1: Create Schematic and Add Component

Request:

Create a new schematic called "BasicTest" and add a 10k resistor at position (100, 100)

MCP Tools Called:

  1. create_schematic(name="BasicTest")

  2. add_component(lib_id="Device:R", value="10k", reference="R1", position=(100.0, 100.0))

Result:

  • New schematic created

  • Resistor R1 added at specified position

  • Component has auto-generated UUID

  • Ready to add more components or save

Example 2: List and Filter Components

Request:

Show me all components in the schematic, then find all resistors

MCP Tools Called:

  1. list_components() - Returns all components with metadata

  2. filter_components(lib_id="Device:R") - Returns only resistors

Output includes:

  • Reference (R1, R2, etc.)

  • Value (10k, 100k, etc.)

  • Position (x, y coordinates)

  • Rotation (0, 90, 180, 270)

  • Library ID (Device:R)

  • Footprint (if specified)

Example 3: Update Component Properties

Request:

Change R1's value to 20k, rotate it 90 degrees, and set footprint to R_0603_1608Metric

MCP Tools Called:

update_component(
    reference="R1",
    value="20k",
    rotation=90.0,
    footprint="Resistor_SMD:R_0603_1608Metric"
)

Result:

  • R1 value updated: 10k β†’ 20k

  • R1 rotation updated: 0Β° β†’ 90Β°

  • R1 footprint assigned

  • Component ready for PCB layout

Example 4: Remove Component

Request:

Remove resistor R1 from the schematic

MCP Tools Called:

remove_component(reference="R1")

Result:

  • R1 removed from schematic

  • UUID freed for reuse

  • Schematic modified flag set

Building Complete Circuits

Example 5: Voltage Divider (Verified βœ…)

Request:

Create a voltage divider with R1=10k and R2=20k, fully connected with VCC and GND labels

Complete MCP Tool Sequence:

# 1. Create schematic
create_schematic(name="Voltage Divider")

# 2. Add components
add_component(
    lib_id="Device:R",
    reference="R1",
    value="10k",
    position=(127.0, 76.2),
    rotation=0
)

add_component(
    lib_id="Device:R",
    reference="R2",
    value="20k",
    position=(127.0, 95.25),
    rotation=0
)

# 3. Get pin positions
get_component_pins("R1")
# Returns:
# {
#   "pin_count": 2,
#   "pins": [
#     {"number": "1", "position": {"x": 127.0, "y": 72.39}, "type": "passive"},
#     {"number": "2", "position": {"x": 127.0, "y": 80.01}, "type": "passive"}
#   ]
# }

get_component_pins("R2")
# Returns:
# {
#   "pin_count": 2,
#   "pins": [
#     {"number": "1", "position": {"x": 127.0, "y": 91.44}, "type": "passive"},
#     {"number": "2", "position": {"x": 127.0, "y": 99.06}, "type": "passive"}
#   ]
# }

# 4. Add wires
add_wire(start=(127.0, 72.39), end=(127.0, 66.04))   # VCC to R1 pin 1
add_wire(start=(127.0, 80.01), end=(127.0, 91.44))   # R1 pin 2 to R2 pin 1
add_wire(start=(127.0, 99.06), end=(127.0, 105.41))  # R2 pin 2 to GND

# 5. Add labels (offset from wire for visibility)
add_label(text="VCC", position=(129.54, 66.04), rotation=0.0)
add_label(text="VOUT", position=(129.54, 85.725), rotation=0.0)
add_label(text="GND", position=(129.54, 105.41), rotation=0.0)

# 6. Add junction at voltage divider tap point
add_junction(position=(127.0, 85.725), diameter=0.0)

# 7. Save schematic
save_schematic(file_path="voltage_divider.kicad_sch")

Circuit Details:

  • Input: VCC at top

  • Output: VOUT = VCC Γ— (R2 / (R1 + R2)) = VCC Γ— (20k / 30k) = 0.667 Γ— VCC

  • Ground: GND at bottom

  • Junction: At R1-R2 connection point (VOUT tap)

Result: βœ… VERIFIED WORKING - Opens perfectly in KiCAD with proper connectivity!

Example 6: LED Circuit with Current Limiting Resistor

Request:

Create an LED circuit with a 220Ξ© current limiting resistor, wired to VCC and GND

Complete MCP Tool Sequence:

# 1. Create schematic
create_schematic(name="LED Circuit")

# 2. Add LED
add_component(
    lib_id="Device:LED",
    reference="D1",
    value="LED",
    position=(127.0, 88.9),
    rotation=0
)

# 3. Add current limiting resistor
add_component(
    lib_id="Device:R",
    reference="R1",
    value="220",
    position=(127.0, 69.85),
    rotation=0
)

# 4. Get pin positions
r1_pins = get_component_pins("R1")
# Pin 1 at (127.0, 66.04), Pin 2 at (127.0, 73.66)

d1_pins = get_component_pins("D1")
# Anode (pin 1) at (127.0, 85.09), Cathode (pin 2) at (127.0, 92.71)

# 5. Wire VCC β†’ R1 β†’ LED β†’ GND
add_wire(start=(127.0, 66.04), end=(127.0, 59.69))   # VCC to R1
add_wire(start=(127.0, 73.66), end=(127.0, 85.09))   # R1 to LED anode
add_wire(start=(127.0, 92.71), end=(127.0, 99.06))   # LED cathode to GND

# 6. Add labels
add_label(text="VCC", position=(129.54, 59.69), rotation=0.0)
add_label(text="GND", position=(129.54, 99.06), rotation=0.0)

# 7. Save
save_schematic(file_path="led_circuit.kicad_sch")

Circuit Details:

  • Current Limiting: I = (VCC - V_LED) / R1 = (5V - 2V) / 220Ξ© β‰ˆ 13.6mA (safe for standard LED)

  • Polarity: Anode to VCC (through resistor), cathode to GND

  • Components: Standard red/green LED, 1/4W resistor

Result: Complete LED driver circuit ready for use!

Example 7: RC Low-Pass Filter

Request:

Create an RC low-pass filter with R=10k, C=100nF for audio applications

Complete MCP Tool Sequence:

# 1. Create schematic
create_schematic(name="RC Low-Pass Filter")

# 2. Add resistor
add_component(
    lib_id="Device:R",
    reference="R1",
    value="10k",
    position=(101.6, 88.9),
    rotation=90  # Horizontal orientation
)

# 3. Add capacitor
add_component(
    lib_id="Device:C",
    reference="C1",
    value="100nF",
    position=(127.0, 95.25),
    rotation=0  # Vertical orientation
)

# 4. Get pin positions
r1_pins = get_component_pins("R1")
# Pin 1 (left) at (97.79, 88.9), Pin 2 (right) at (105.41, 88.9)

c1_pins = get_component_pins("C1")
# Pin 1 (top) at (127.0, 91.44), Pin 2 (bottom) at (127.0, 99.06)

# 5. Wire input β†’ R1 β†’ C1 β†’ output
add_wire(start=(97.79, 88.9), end=(88.9, 88.9))      # Input to R1
add_wire(start=(105.41, 88.9), end=(127.0, 88.9))    # R1 to horizontal bus
add_wire(start=(127.0, 88.9), end=(127.0, 91.44))    # Bus to C1 top
add_wire(start=(127.0, 88.9), end=(135.89, 88.9))    # Bus to output
add_wire(start=(127.0, 99.06), end=(127.0, 105.41))  # C1 bottom to GND

# 6. Add labels
add_label(text="INPUT", position=(86.36, 88.9), rotation=0.0)
add_label(text="OUTPUT", position=(138.43, 88.9), rotation=0.0)
add_label(text="GND", position=(129.54, 105.41), rotation=0.0)

# 7. Add junction at output tap (where R1, C1, and output meet)
add_junction(position=(127.0, 88.9), diameter=0.0)

# 8. Save
save_schematic(file_path="rc_filter.kicad_sch")

Circuit Details:

  • Cutoff Frequency: f_c = 1 / (2Ο€ Γ— R Γ— C) = 1 / (2Ο€ Γ— 10kΞ© Γ— 100nF) β‰ˆ 159 Hz

  • Application: Audio low-pass filter, removes high-frequency noise

  • Attenuation: -20dB/decade above cutoff

  • Input Impedance: 10kΞ©

  • Output Impedance: ~10kΞ© at DC, decreases with frequency

Result: Professional audio filter circuit with proper grounding!

Advanced Examples

Example 8: Multi-Component Circuit Analysis

Request:

Load my schematic and analyze it:
1. List all components
2. Find all resistors
3. Find all capacitors with value 100nF
4. Show pin details for U1

MCP Tool Sequence:

# 1. Load existing schematic
load_schematic(file_path="/path/to/my_circuit.kicad_sch")

# 2. List all components
all_components = list_components()
# Returns: {"success": true, "count": 15, "components": [...]}

# 3. Find all resistors
resistors = filter_components(lib_id="Device:R")
# Returns: {"success": true, "count": 5, "components": [R1, R2, R3, R4, R5]}

# 4. Find specific capacitors
caps_100nf = filter_components(lib_id="Device:C", value="100nF")
# Returns: {"success": true, "count": 2, "components": [C2, C7]}

# 5. Get detailed pin information for IC
u1_pins = get_component_pins("U1")
# Returns all 64 pins with positions, names, and types

Use Cases:

  • BOM generation

  • Design review

  • Component inventory

  • Circuit analysis

Example 9: Pin Discovery for Complex ICs

Request:

For component U1 (STM32 microcontroller):
1. Show all pins
2. Find all clock pins
3. Find all power input pins
4. Find UART TX pin

MCP Tool Sequence:

# 1. Get all pins (comprehensive view)
all_pins = get_component_pins("U1")
# Returns: 144 pins with complete metadata

# 2. Find clock pins by name pattern
clk_pins = find_pins_by_name("U1", "CLK*", case_sensitive=False)
# Returns: ["PA8", "PB0", "PC9"] - all pins with "CLK" in name

# 3. Find power pins by electrical type
power_pins = find_pins_by_type("U1", "power_in")
# Returns: ["VDD", "VDDA", "VREF+", ...] - all power input pins

# 4. Find specific UART pin
uart_tx = find_pins_by_name("U1", "*TX*", case_sensitive=False)
# Returns: ["PA9", "PB6", "PC10"] - UART TX pins

Use Cases:

  • Complex IC routing

  • Power distribution design

  • Signal integrity analysis

  • Automatic wire routing

Example 10: Batch Component Updates

Request:

Update all resistors to 1% tolerance footprint and rotate them 90 degrees

MCP Tool Sequence:

# 1. Find all resistors
resistors = filter_components(lib_id="Device:R")

# 2. Update each resistor
for resistor in resistors["components"]:
    ref = resistor["reference"]

    update_component(
        reference=ref,
        rotation=90.0,
        footprint="Resistor_SMD:R_0603_1608Metric"
    )

# Result: All resistors now have:
# - 90Β° rotation (horizontal orientation)
# - 0603 footprint for tight PCB layout

Use Cases:

  • Design standardization

  • Footprint assignment

  • Layout optimization

  • Design rules compliance

Common Patterns

Pattern 1: Component Placement with Grid Alignment

Always use grid-aligned coordinates (1.27mm increments):

# Good - on grid
add_component("Device:R", "R1", "10k", position=(127.0, 76.2))
add_component("Device:C", "C1", "100nF", position=(101.6, 88.9))

# Bad - off grid (causes connectivity issues!)
add_component("Device:R", "R2", "10k", position=(125.5, 75.3))

Grid calculation helper:

# Convert mm to grid units (1.27mm grid)
def to_grid(mm):
    return round(mm / 1.27) * 1.27

# Examples
to_grid(100.0) β†’ 101.6   # (80 Γ— 1.27)
to_grid(125.0) β†’ 124.46  # (98 Γ— 1.27)

Pattern 2: Vertical Component Stacking

Stack components vertically with consistent spacing:

SPACING = 19.05  # 15 Γ— 1.27mm grid units

base_x = 127.0
base_y = 76.2

# Add components with vertical stacking
add_component("Device:R", "R1", "10k", position=(base_x, base_y))
add_component("Device:R", "R2", "20k", position=(base_x, base_y + SPACING))
add_component("Device:R", "R3", "30k", position=(base_x, base_y + 2*SPACING))

# Result: Three resistors perfectly aligned vertically

Pattern 3: Pin-to-Pin Wiring

Connect components using pin positions:

# 1. Get pin positions
r1_pins = get_component_pins("R1")
r2_pins = get_component_pins("R2")

# Extract specific pins
r1_pin2 = next(p for p in r1_pins["pins"] if p["number"] == "2")
r2_pin1 = next(p for p in r2_pins["pins"] if p["number"] == "1")

# 2. Create wire
add_wire(
    start=(r1_pin2["position"]["x"], r1_pin2["position"]["y"]),
    end=(r2_pin1["position"]["x"], r2_pin1["position"]["y"])
)

# Result: Direct connection between R1 pin 2 and R2 pin 1

Pattern 4: Label Placement Near Wires

Place labels offset from wires for visibility:

# Wire coordinates
wire_x = 127.0
wire_y = 66.04

# Add wire
add_wire(start=(wire_x, wire_y), end=(wire_x, wire_y - 10.0))

# Add label offset to the right (+2.54mm)
add_label(
    text="VCC",
    position=(wire_x + 2.54, wire_y),
    rotation=0.0
)

# Result: Label appears to the right of the wire, clearly visible

Note: See issue #104 for planned improvements to automatic label placement on wires.

Pattern 5: Junction Placement

Add junctions where 3+ wires meet:

# Connection point coordinates
tap_x = 127.0
tap_y = 85.725

# Add three wires meeting at this point
add_wire(start=(tap_x, 80.01), end=(tap_x, tap_y))    # From above
add_wire(start=(tap_x, tap_y), end=(tap_x, 91.44))    # To below
add_wire(start=(tap_x, tap_y), end=(tap_x + 10, tap_y))  # To right

# Add junction to indicate proper connection
add_junction(position=(tap_x, tap_y), diameter=0.0)

# Result: Clear T-connection with visual junction indicator

Troubleshooting

Issue 1: Components Not Connecting

Problem: Wires don’t connect to component pins.

Solution: Verify pin positions and grid alignment:

# Check pin positions
pins = get_component_pins("R1")
print(pins)  # Verify exact coordinates

# Ensure wire endpoints match pin positions exactly
add_wire(
    start=(127.0, 72.39),  # Must match pin position EXACTLY
    end=(127.0, 66.04)
)

Issue 2: Labels Not On Wires

Problem: Labels appear disconnected from wires.

Current Workaround: Manually calculate label offset:

# Wire position
wire_pos = (127.0, 66.04)

# Place label offset to the right
label_pos = (wire_pos[0] + 2.54, wire_pos[1])

add_label(text="VCC", position=label_pos)

Future: See issue #104 for planned add_label_on_wire() helper method.

Issue 3: Component Rotation

Problem: Component oriented incorrectly after placement.

Solution: Use correct rotation values:

# Resistor/Capacitor orientations
rotation=0    # Vertical (default) - pins at top and bottom
rotation=90   # Horizontal - pins on left and right
rotation=180  # Vertical inverted
rotation=270  # Horizontal inverted

# Update rotation if needed
update_component(reference="R1", rotation=90.0)

Issue 4: Schematic Not Saving

Problem: save_schematic() fails or produces empty file.

Solution: Check schematic state and file path:

# Verify schematic info
info = get_schematic_info()
print(info)  # Should show component count, project name

# Save with absolute path
save_schematic(file_path="/Users/me/Desktop/my_circuit.kicad_sch")

Issue 5: Component Not Found

Problem: get_component_pins("R1") returns error β€œComponent not found”.

Solution: Verify component exists and use correct reference:

# List all components
components = list_components()
print([c["reference"] for c in components["components"]])

# Use exact reference
pins = get_component_pins("R1")  # Case-sensitive!

Best Practices

  1. Always use grid-aligned coordinates (1.27mm increments)

  2. Get pin positions before wiring - don’t guess coordinates

  3. Add junctions at T-connections - ensures proper connectivity

  4. Place labels offset from wires - improves readability

  5. Use consistent spacing - improves readability and maintainability

  6. Verify component references - use exact case-sensitive names

  7. Save frequently - preserve work incrementally

  8. Test in KiCAD - verify generated schematics open correctly

Additional Resources


Questions or Issues?

Report problems at: https://github.com/circuit-synth/kicad-sch-api/issues