feat: Enhance schematic functionality with pin-to-pin connections and netlist generation
Major improvements to schematic editing capabilities: ## Python Implementation (connection_schematic.py) - Implemented pin-to-pin connection logic using kicad-skip - Added get_pin_location() to find absolute pin positions - Implemented add_connection() for wire connections between component pins - Added add_net_label() for creating net labels - Added connect_to_net() to connect pins to named nets - Implemented get_net_connections() to query net connectivity - Added generate_netlist() for schematic netlist extraction ## MCP Handlers (kicad_interface.py) - Added 5 new command handlers: - add_schematic_connection - Pin-to-pin wiring - add_schematic_net_label - Net label placement - connect_to_net - Connect pin to named net - get_net_connections - Query net connectivity - generate_netlist - Export netlist data ## TypeScript Tools (schematic.ts) - Added 5 new MCP tools with proper schemas and validation - Enhanced user feedback with descriptive messages - Total schematic tools increased from 3 to 8 ## Features - Pin location calculation with symbol rotation support - Automatic wire stub creation for net labels - Comprehensive netlist generation with component and net info - Full logging for debugging connection issues This resolves the schematic editing limitations and enables users to: - Wire component pins together directly - Use net labels for cleaner schematics - Query schematic connectivity - Generate netlists for manufacturing 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -73,4 +73,168 @@ export function registerSchematicTools(server: McpServer, callKicadScript: Funct
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Add pin-to-pin connection
|
||||
server.tool(
|
||||
"add_schematic_connection",
|
||||
"Connect two component pins with a wire",
|
||||
{
|
||||
schematicPath: z.string().describe("Path to the schematic file"),
|
||||
sourceRef: z.string().describe("Source component reference (e.g., R1)"),
|
||||
sourcePin: z.string().describe("Source pin name/number (e.g., 1, 2, GND)"),
|
||||
targetRef: z.string().describe("Target component reference (e.g., C1)"),
|
||||
targetPin: z.string().describe("Target pin name/number (e.g., 1, 2, VCC)")
|
||||
},
|
||||
async (args: { schematicPath: string; sourceRef: string; sourcePin: string; targetRef: string; targetPin: string }) => {
|
||||
const result = await callKicadScript("add_schematic_connection", args);
|
||||
if (result.success) {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Successfully connected ${args.sourceRef}/${args.sourcePin} to ${args.targetRef}/${args.targetPin}`
|
||||
}]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Failed to add connection: ${result.message || 'Unknown error'}`
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Add net label
|
||||
server.tool(
|
||||
"add_schematic_net_label",
|
||||
"Add a net label to the schematic",
|
||||
{
|
||||
schematicPath: z.string().describe("Path to the schematic file"),
|
||||
netName: z.string().describe("Name of the net (e.g., VCC, GND, SIGNAL_1)"),
|
||||
position: z.array(z.number()).length(2).describe("Position [x, y] for the label")
|
||||
},
|
||||
async (args: { schematicPath: string; netName: string; position: number[] }) => {
|
||||
const result = await callKicadScript("add_schematic_net_label", args);
|
||||
if (result.success) {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Successfully added net label '${args.netName}' at position [${args.position}]`
|
||||
}]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Failed to add net label: ${result.message || 'Unknown error'}`
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Connect pin to net
|
||||
server.tool(
|
||||
"connect_to_net",
|
||||
"Connect a component pin to a named net",
|
||||
{
|
||||
schematicPath: z.string().describe("Path to the schematic file"),
|
||||
componentRef: z.string().describe("Component reference (e.g., U1, R1)"),
|
||||
pinName: z.string().describe("Pin name/number to connect"),
|
||||
netName: z.string().describe("Name of the net to connect to")
|
||||
},
|
||||
async (args: { schematicPath: string; componentRef: string; pinName: string; netName: string }) => {
|
||||
const result = await callKicadScript("connect_to_net", args);
|
||||
if (result.success) {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Successfully connected ${args.componentRef}/${args.pinName} to net '${args.netName}'`
|
||||
}]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Failed to connect to net: ${result.message || 'Unknown error'}`
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Get net connections
|
||||
server.tool(
|
||||
"get_net_connections",
|
||||
"Get all connections for a named net",
|
||||
{
|
||||
schematicPath: z.string().describe("Path to the schematic file"),
|
||||
netName: z.string().describe("Name of the net to query")
|
||||
},
|
||||
async (args: { schematicPath: string; netName: string }) => {
|
||||
const result = await callKicadScript("get_net_connections", args);
|
||||
if (result.success && result.connections) {
|
||||
const connectionList = result.connections.map((conn: any) =>
|
||||
` - ${conn.component}/${conn.pin}`
|
||||
).join('\n');
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Net '${args.netName}' connections:\n${connectionList}`
|
||||
}]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Failed to get net connections: ${result.message || 'Unknown error'}`
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Generate netlist
|
||||
server.tool(
|
||||
"generate_netlist",
|
||||
"Generate a netlist from the schematic",
|
||||
{
|
||||
schematicPath: z.string().describe("Path to the schematic file")
|
||||
},
|
||||
async (args: { schematicPath: string }) => {
|
||||
const result = await callKicadScript("generate_netlist", args);
|
||||
if (result.success && result.netlist) {
|
||||
const netlist = result.netlist;
|
||||
const output = [
|
||||
`=== Netlist for ${args.schematicPath} ===`,
|
||||
`\nComponents (${netlist.components.length}):`,
|
||||
...netlist.components.map((comp: any) =>
|
||||
` ${comp.reference}: ${comp.value} (${comp.footprint || 'No footprint'})`
|
||||
),
|
||||
`\nNets (${netlist.nets.length}):`,
|
||||
...netlist.nets.map((net: any) => {
|
||||
const connections = net.connections.map((conn: any) =>
|
||||
`${conn.component}/${conn.pin}`
|
||||
).join(', ');
|
||||
return ` ${net.name}: ${connections}`;
|
||||
})
|
||||
].join('\n');
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: output
|
||||
}]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Failed to generate netlist: ${result.message || 'Unknown error'}`
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user