Date: 2026-01-10 Status: Planning Phase Priority: HIGH (User-requested feature for Issue #26)
This plan outlines the implementation of complete schematic wiring functionality for the KiCAD MCP Server. Currently, component placement works perfectly with dynamic symbol loading, but wire/connection tools are incomplete or non-functional.
Goal: Enable users to create complete, functional schematics with wired connections between components through the MCP interface.
Files:
python/commands/connection_schematic.py- ConnectionManager class with wire/label methods- MCP handlers in
kicad_interface.pyfor 6 connection-related tools
MCP Tools (Registered):
add_schematic_wire- Add wire between two pointsadd_schematic_connection- Connect two component pinsadd_schematic_net_label- Add net labelconnect_to_net- Connect pin to named netget_net_connections- Query net connectionsgenerate_netlist- Generate netlist from schematic
ConnectionManager Methods:
add_wire(schematic, start_point, end_point)- Add wire between coordinatesadd_connection(schematic, source_ref, source_pin, target_ref, target_pin)- Connect pinsadd_net_label(schematic, net_name, position)- Add labelconnect_to_net(schematic, component_ref, pin_name, net_name)- Pin to netget_pin_location(symbol, pin_name)- Get pin coordinatesget_net_connections(schematic, net_name)- Query connectionsgenerate_netlist(schematic)- Generate netlist
Problem 1: kicad-skip API Uncertainty
- Code assumes
schematic.wire.append()exists - Code assumes
schematic.label.append()exists - Code assumes pins have
.nameand.locationattributes - Need to verify what kicad-skip actually supports
Problem 2: Pin Location Calculation
- Current implementation tries to calculate absolute pin positions
- May not account for symbol rotation
- May not work with multi-unit symbols
- Pin numbering vs pin naming confusion
Problem 3: No Visual Feedback
- No way to verify wires were created correctly
- No validation of wire endpoints
- No checks for overlapping wires or junctions
Problem 4: Limited Testing
- No integration tests for wiring functionality
- No validation with real KiCad schematics
- User reported
add_schematic_wirefails
Problem 5: Missing Features
- No junction (wire intersection) support
- No bus support (multi-bit signals)
- No no-connect flags
- No power symbols (VCC, GND graphical symbols)
- No hierarchical labels
Issue: The kicad-skip library documentation is sparse. We need to determine:
- Does
schematic.wireexist? - What's the correct API to add wires?
- How are wires stored in .kicad_sch files?
S-Expression Format (KiCad 8/9):
(wire (pts (xy 100 100) (xy 200 100))
(stroke (width 0) (type default))
(uuid "12345678-1234-1234-1234-123456789012")
)Approach:
- Examine kicad-skip source code
- Test wire creation manually with kicad-skip
- Fall back to S-expression manipulation if necessary (similar to dynamic symbol loading)
Issue: Need to find exact pin coordinates for automatic wiring.
Pin Data in Symbols: Pins are defined within symbol definitions in lib_symbols, with coordinates relative to symbol origin. When symbol is placed, pins move with it.
Required Information:
- Symbol position (x, y)
- Symbol rotation angle
- Pin offset from symbol origin
- Pin number/name mapping
Solution:
- Parse symbol definition to find pin definitions
- Apply transformation matrix (position + rotation) to pin coordinates
- Return absolute pin position in schematic space
Issue: Users don't want to manually specify every wire segment.
Desired Behavior:
User: "Connect R1 pin 1 to C1 pin 1"
System:
- Calculate R1 pin 1 location: (100, 100)
- Calculate C1 pin 1 location: (150, 120)
- Create wire path (orthogonal routing preferred):
- (100, 100) → (100, 120) → (150, 120)
- Or simple direct: (100, 100) → (150, 120)
Auto-Routing Options:
- Direct - Single wire segment (diagonal if needed)
- Orthogonal - Only horizontal/vertical segments (2 segments)
- Manhattan - Complex path avoiding components (3+ segments)
Phase 1 Approach: Start with direct wiring, add orthogonal later.
Issue: Labels need to attach to wires, not float in space.
KiCad Behavior:
- Labels must touch a wire or pin
- Labels create electrical connections at their attachment point
- Multiple labels with same name = connected net
Implementation:
- When adding label, find nearest wire endpoint
- Attach label to that coordinate
- Or create short wire stub for label attachment
Goal: Get basic wiring working with kicad-skip API
Tasks:
-
Research kicad-skip Wire API (4 hours)
- Read kicad-skip source code
- Test wire creation with Python REPL
- Document actual API methods
- Create test schematic with manual wires
-
Fix Wire Creation (6 hours)
- Update ConnectionManager.add_wire() with correct API
- Handle S-expression manipulation if needed
- Add UUID generation for wires
- Test with simple wire (100,100) → (200,100)
-
Implement Pin Discovery (8 hours)
- Parse symbol definitions to extract pin data
- Handle pin coordinates relative to symbol
- Apply rotation transformation
- Test with R, C, LED from dynamic symbols
-
Fix add_schematic_connection (4 hours)
- Use correct pin discovery
- Create direct wire between pins
- Handle error cases (pin not found, etc.)
- Test with R1 pin 2 → C1 pin 1
-
Integration Testing (4 hours)
- Create test schematic with R, C, LED
- Wire R to C
- Wire C to LED
- Verify schematic opens in KiCad
- Verify electrical connectivity
Deliverables:
- Working
add_schematic_wiretool - Working
add_schematic_connectiontool - Pin location discovery working
- Integration test passing
- Documentation updated
Success Criteria:
- User can connect two resistor pins with MCP command
- Wire appears in KiCad schematic viewer
- Netlist shows electrical connection
Goal: Enable named net connections (VCC, GND, etc.)
Tasks:
-
Fix Net Label Creation (4 hours)
- Update ConnectionManager.add_net_label()
- Use correct kicad-skip API or S-expression
- Position labels correctly
- Test label creation
-
Implement connect_to_net (6 hours)
- Create wire stub from pin
- Attach label to wire endpoint
- Support common nets (VCC, GND, 3V3, etc.)
- Test with multiple components on same net
-
Net Connection Discovery (6 hours)
- Parse wires and labels in schematic
- Build connectivity graph
- Implement get_net_connections()
- Return all pins on a net
-
Power Symbol Support (8 hours)
- Add power symbols to templates (VCC, GND, 3V3, 5V)
- Or dynamically load from power library
- Connect power pins to power nets
- Test complete circuit with power
-
Testing (4 hours)
- Create circuit with VCC, GND nets
- Connect multiple components to each net
- Verify net connectivity
- Generate and validate netlist
Deliverables:
- Working
add_schematic_net_labeltool - Working
connect_to_nettool - Working
get_net_connectionstool - Power symbol support
- Netlist generation working
Success Criteria:
- User can label nets VCC, GND
- Multiple components connect to same net
- Netlist correctly shows net membership
Goal: Professional schematic features
Tasks:
-
Junction Support (4 hours)
- Detect wire intersections
- Add junction dots at T-junctions
- S-expression:
(junction (at x y) (diameter 0) (uuid ...))
-
No-Connect Flags (2 hours)
- Add "X" marks on unused pins
- S-expression:
(no_connect (at x y) (uuid ...))
-
Orthogonal Routing (6 hours)
- Implement 2-segment wire routing
- Horizontal-then-vertical or vertical-then-horizontal
- Choose best path based on pin positions
-
Bus Support (8 hours)
- Multi-bit signal buses
- Bus labels (e.g., "D[0..7]")
- Bus entries for individual signals
-
Hierarchical Labels (8 hours)
- Labels for hierarchical sheets
- Input/Output/Bidirectional types
- Sheet connections
Deliverables:
- Junction creation
- No-connect support
- Smart orthogonal routing
- Bus and hierarchical label support
Success Criteria:
- Wires route cleanly around components
- Junctions appear at wire intersections
- Unused pins marked with no-connect
Goal: Production-ready reliability
Tasks:
-
ERC Integration (6 hours)
- Electrical Rule Check
- Detect floating nets
- Detect unconnected pins
- Detect short circuits
-
Visual Validation (4 hours)
- Export schematic to PDF after wiring
- Verify wire appearance
- Check net label placement
-
Comprehensive Testing (8 hours)
- Test with Device library components
- Test with IC components (multi-pin)
- Test with connectors
- Test complex circuits (10+ components)
-
Error Handling (4 hours)
- Graceful failures
- Clear error messages
- Validation of coordinates
- Duplicate net label detection
-
Documentation (6 hours)
- Update MCP tool descriptions
- Add usage examples to README
- Create wiring tutorial
- Add to CHANGELOG
Deliverables:
- ERC validation
- Comprehensive test suite
- Error handling
- Complete documentation
Success Criteria:
- 95%+ test pass rate
- Users can create functional circuits
- Clear error messages on failures
If kicad-skip supports wires natively:
# Add wire using native API
wire = schematic.wire.new(
start=[100, 100],
end=[200, 100]
)
# Add label
label = schematic.label.new(
text="VCC",
at=[150, 100]
)Pros:
- Clean, maintainable code
- Follows library patterns
- Less likely to break
Cons:
- Depends on kicad-skip having these features
- May be limited in functionality
If kicad-skip doesn't support wires:
Use the same approach as dynamic symbol loading:
import sexpdata
from sexpdata import Symbol
# Read schematic
with open(schematic_path, 'r') as f:
sch_data = sexpdata.loads(f.read())
# Create wire S-expression
wire_sexp = [
Symbol('wire'),
[Symbol('pts'),
[Symbol('xy'), 100, 100],
[Symbol('xy'), 200, 100]
],
[Symbol('stroke'), [Symbol('width'), 0], [Symbol('type'), Symbol('default')]],
[Symbol('uuid'), str(uuid.uuid4())]
]
# Insert into schematic
sch_data.append(wire_sexp)
# Write back
with open(schematic_path, 'w') as f:
f.write(sexpdata.dumps(sch_data))Pros:
- Complete control
- Can implement any feature
- Works around library limitations
Cons:
- More complex
- Requires deep KiCad format knowledge
- More maintenance
- Try kicad-skip native API first
- Fall back to S-expression if needed
- Use S-expression for advanced features (junctions, buses)
Symbols are stored in lib_symbols section:
(lib_symbols
(symbol "Device:R"
(symbol "R_0_1"
(rectangle (start -1 -2.54) (end 1 2.54) ...))
(symbol "R_1_1"
(pin passive line (at 0 3.81 270) (length 1.27)
(name "~" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27)))))
(pin passive line (at 0 -3.81 90) (length 1.27)
(name "~" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27)))))))For each pin:
- Number (e.g., "1", "2")
- Name (e.g., "GND", "VCC", "~" for unnamed)
- Position relative to symbol origin:
(at x y angle) - Length (distance from symbol body to connection point)
From symbol instance in schematic:
(symbol (lib_id "Device:R") (at 100 100 0) (unit 1)
(property "Reference" "R1" ...))Extract:
- Position:
(at 100 100 0)= x=100, y=100, rotation=0° - Reference: "R1"
def get_absolute_pin_position(symbol_instance, pin_definition):
# Symbol position
symbol_x, symbol_y, symbol_rotation = symbol_instance.at.value
# Pin position relative to symbol
pin_x, pin_y, pin_angle = pin_definition.at.value
# Apply rotation transformation
if symbol_rotation != 0:
# Rotate pin coordinates around origin
rad = math.radians(symbol_rotation)
rotated_x = pin_x * math.cos(rad) - pin_y * math.sin(rad)
rotated_y = pin_x * math.sin(rad) + pin_y * math.cos(rad)
pin_x, pin_y = rotated_x, rotated_y
# Translate to absolute position
abs_x = symbol_x + pin_x
abs_y = symbol_y + pin_y
return [abs_x, abs_y]Simplest: single wire segment from pin A to pin B.
R1 pin 2 C1 pin 1
o-------------o
Pros: Simple, fast Cons: Diagonal wires (not standard practice)
Two segments: horizontal then vertical, or vertical then horizontal.
R1 pin 2 C1 pin 1
o-----┐
│
└------o
Algorithm:
- Calculate midpoint
- Route horizontal to midpoint
- Route vertical to target
- Or vice versa based on direction
Pros: Standard practice, cleaner schematics Cons: Slightly more complex
Complex multi-segment paths avoiding components.
Pros: Professional appearance Cons: Requires collision detection, path planning
Test individual functions:
test_add_wire()- Wire creationtest_get_pin_location()- Pin discoverytest_add_net_label()- Label creationtest_calculate_pin_position()- Coordinate math
Test complete workflows:
test_connect_two_resistors()- Wire R1 to R2test_connect_to_vcc_net()- Multiple components to VCCtest_generate_netlist()- Netlist accuracytest_schematic_opens_in_kicad()- File validity
- Create test schematic in KiCad manually
- Add same connections via MCP
- Compare results
- Verify electrical connectivity in KiCad
-
add_schematic_wireworks (coordinates) -
add_schematic_connectionworks (pin to pin) - Wires appear in KiCad schematic
- Netlist shows connections
- 3+ integration tests passing
- Net labels work (VCC, GND, etc.)
- Multiple components on same net
-
get_net_connectionsreturns correct results - Netlist includes named nets
- 5+ integration tests passing
- Junctions at wire intersections
- Orthogonal routing preferred
- No-connect flags on unused pins
- 10+ integration tests passing
- ERC detects errors
- 95%+ test coverage
- Complete documentation
- User can create functional circuits without errors
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| kicad-skip lacks wire API | High | High | Use S-expression fallback |
| Pin discovery complex | Medium | Medium | Test with multiple symbol types |
| Rotation math errors | Medium | High | Extensive testing, validation |
| Performance issues | Low | Medium | Optimize S-expression parsing |
| KiCad format changes | Low | High | Version detection, compatibility |
Required:
- kicad-skip >= 0.1.0 (or compatible)
- sexpdata (already dependency for dynamic loading)
- Python 3.8+
Optional:
- KiCad CLI for validation (
kicad-cli sch export netlist)
Phase 1: 1 week (26 hours) Phase 2: 1 week (28 hours) Phase 3: 1.5 weeks (28 hours) Phase 4: 1.5 weeks (28 hours)
Total: 5 weeks (110 hours)
Accelerated path (core features only): 2-3 weeks (Phases 1-2)
-
Research kicad-skip Wire API (TODAY)
- Test with Python REPL
- Document findings
- Choose implementation approach
-
Create Test Environment (TOMORROW)
- Set up test schematic
- Manual wire creation in KiCad
- Export for comparison
-
Implement Basic Wire (THIS WEEK)
- Update ConnectionManager.add_wire()
- Test with simple coordinates
- Verify in KiCad
-
Fix Pin Discovery (THIS WEEK)
- Parse symbol definitions
- Calculate absolute positions
- Test with rotated symbols
For Issue #26:
Update users that:
- ✅ Component placement is DONE (with 10,000+ symbols)
- ⏳ Wire/connection tools are IN PROGRESS
- 📅 Estimated completion: 2-3 weeks for core functionality
- 🎯 Goal: Complete functional schematics with wiring
Status: Ready for implementation Owner: TBD Priority: HIGH (user-blocking feature)