style: revert Prettier formatting in TS files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,307 +1,308 @@
|
|||||||
/**
|
/**
|
||||||
* Tool Registry for KiCAD MCP Server
|
* Tool Registry for KiCAD MCP Server
|
||||||
*
|
*
|
||||||
* Centralizes all tool definitions and provides lookup/search functionality
|
* Centralizes all tool definitions and provides lookup/search functionality
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { z } from "zod";
|
import { z } from 'zod';
|
||||||
|
|
||||||
export interface ToolDefinition {
|
export interface ToolDefinition {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
inputSchema: z.ZodObject<any> | z.ZodType<any>;
|
inputSchema: z.ZodObject<any> | z.ZodType<any>;
|
||||||
// Handler will be registered separately in the existing tool files
|
// Handler will be registered separately in the existing tool files
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ToolCategory {
|
export interface ToolCategory {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
tools: string[]; // Tool names in this category
|
tools: string[]; // Tool names in this category
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tool category definitions
|
* Tool category definitions
|
||||||
* Each category groups related tools for better organization
|
* Each category groups related tools for better organization
|
||||||
*/
|
*/
|
||||||
export const toolCategories: ToolCategory[] = [
|
export const toolCategories: ToolCategory[] = [
|
||||||
{
|
{
|
||||||
name: "board",
|
name: "board",
|
||||||
description:
|
description: "Board configuration: layers, mounting holes, zones, visualization",
|
||||||
"Board configuration: layers, mounting holes, zones, visualization",
|
tools: [
|
||||||
tools: [
|
"add_layer",
|
||||||
"add_layer",
|
"set_active_layer",
|
||||||
"set_active_layer",
|
"get_layer_list",
|
||||||
"get_layer_list",
|
"add_mounting_hole",
|
||||||
"add_mounting_hole",
|
"add_board_text",
|
||||||
"add_board_text",
|
"add_zone",
|
||||||
"add_zone",
|
"get_board_extents",
|
||||||
"get_board_extents",
|
"get_board_2d_view",
|
||||||
"get_board_2d_view",
|
"launch_kicad_ui"
|
||||||
"launch_kicad_ui",
|
]
|
||||||
],
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "component",
|
||||||
name: "component",
|
description: "Advanced component operations: edit, delete, search, group, annotate",
|
||||||
description:
|
tools: [
|
||||||
"Advanced component operations: edit, delete, search, group, annotate",
|
"rotate_component",
|
||||||
tools: [
|
"delete_component",
|
||||||
"rotate_component",
|
"edit_component",
|
||||||
"delete_component",
|
"find_component",
|
||||||
"edit_component",
|
"get_component_properties",
|
||||||
"find_component",
|
"add_component_annotation",
|
||||||
"get_component_properties",
|
"group_components",
|
||||||
"add_component_annotation",
|
"replace_component"
|
||||||
"group_components",
|
]
|
||||||
"replace_component",
|
},
|
||||||
],
|
{
|
||||||
},
|
name: "export",
|
||||||
{
|
description: "File export for fabrication and documentation: Gerber, PDF, BOM, 3D models",
|
||||||
name: "export",
|
tools: [
|
||||||
description:
|
"export_gerber",
|
||||||
"File export for fabrication and documentation: Gerber, PDF, BOM, 3D models",
|
"export_pdf",
|
||||||
tools: [
|
"export_svg",
|
||||||
"export_gerber",
|
"export_3d",
|
||||||
"export_pdf",
|
"export_bom",
|
||||||
"export_svg",
|
"export_netlist",
|
||||||
"export_3d",
|
"export_position_file",
|
||||||
"export_bom",
|
"export_vrml"
|
||||||
"export_netlist",
|
]
|
||||||
"export_position_file",
|
},
|
||||||
"export_vrml",
|
{
|
||||||
],
|
name: "drc",
|
||||||
},
|
description: "Design rule checking and electrical validation: DRC, net classes, clearances",
|
||||||
{
|
tools: [
|
||||||
name: "drc",
|
"set_design_rules",
|
||||||
description:
|
"get_design_rules",
|
||||||
"Design rule checking and electrical validation: DRC, net classes, clearances",
|
"run_drc",
|
||||||
tools: [
|
"add_net_class",
|
||||||
"set_design_rules",
|
"assign_net_to_class",
|
||||||
"get_design_rules",
|
"set_layer_constraints",
|
||||||
"run_drc",
|
"check_clearance",
|
||||||
"add_net_class",
|
"get_drc_violations"
|
||||||
"assign_net_to_class",
|
]
|
||||||
"set_layer_constraints",
|
},
|
||||||
"check_clearance",
|
{
|
||||||
"get_drc_violations",
|
name: "schematic",
|
||||||
],
|
description: "Schematic operations: create, inspect, add/edit/delete components, wire connections, netlists, annotation",
|
||||||
},
|
tools: [
|
||||||
{
|
"create_schematic",
|
||||||
name: "schematic",
|
"add_schematic_component",
|
||||||
description:
|
"list_schematic_components",
|
||||||
"Schematic operations: create, inspect, add/edit/delete components, wire connections, netlists, annotation",
|
"move_schematic_component",
|
||||||
tools: [
|
"rotate_schematic_component",
|
||||||
"create_schematic",
|
"annotate_schematic",
|
||||||
"add_schematic_component",
|
"add_schematic_wire",
|
||||||
"list_schematic_components",
|
"delete_schematic_wire",
|
||||||
"move_schematic_component",
|
"add_schematic_junction",
|
||||||
"rotate_schematic_component",
|
"add_schematic_net_label",
|
||||||
"annotate_schematic",
|
"delete_schematic_net_label",
|
||||||
"add_schematic_wire",
|
"connect_to_net",
|
||||||
"delete_schematic_wire",
|
"connect_passthrough",
|
||||||
"add_schematic_junction",
|
"get_net_connections",
|
||||||
"add_schematic_net_label",
|
"list_schematic_nets",
|
||||||
"delete_schematic_net_label",
|
"list_schematic_wires",
|
||||||
"connect_to_net",
|
"list_schematic_labels",
|
||||||
"connect_passthrough",
|
"get_wire_connections",
|
||||||
"get_net_connections",
|
"generate_netlist",
|
||||||
"list_schematic_nets",
|
"sync_schematic_to_board",
|
||||||
"list_schematic_wires",
|
"get_schematic_view",
|
||||||
"list_schematic_labels",
|
"export_schematic_svg",
|
||||||
"get_wire_connections",
|
"export_schematic_pdf"
|
||||||
"generate_netlist",
|
]
|
||||||
"sync_schematic_to_board",
|
},
|
||||||
"get_schematic_view",
|
{
|
||||||
"export_schematic_svg",
|
name: "library",
|
||||||
"export_schematic_pdf",
|
description: "Footprint library access: search, browse, get footprint information",
|
||||||
],
|
tools: [
|
||||||
},
|
"list_libraries",
|
||||||
{
|
"search_footprints",
|
||||||
name: "library",
|
"list_library_footprints",
|
||||||
description:
|
"get_footprint_info"
|
||||||
"Footprint library access: search, browse, get footprint information",
|
]
|
||||||
tools: [
|
},
|
||||||
"list_libraries",
|
{
|
||||||
"search_footprints",
|
name: "routing",
|
||||||
"list_library_footprints",
|
description: "Advanced routing operations: vias, copper pours",
|
||||||
"get_footprint_info",
|
tools: [
|
||||||
],
|
"add_via",
|
||||||
},
|
"add_copper_pour"
|
||||||
{
|
]
|
||||||
name: "routing",
|
},
|
||||||
description: "Advanced routing operations: vias, copper pours",
|
{
|
||||||
tools: ["add_via", "add_copper_pour"],
|
name: "autoroute",
|
||||||
},
|
description: "Freerouting autorouter: automatic PCB routing via Specctra DSN/SES",
|
||||||
{
|
tools: [
|
||||||
name: "autoroute",
|
"autoroute",
|
||||||
description:
|
"export_dsn",
|
||||||
"Freerouting autorouter: automatic PCB routing via Specctra DSN/SES",
|
"import_ses",
|
||||||
tools: ["autoroute", "export_dsn", "import_ses", "check_freerouting"],
|
"check_freerouting"
|
||||||
},
|
]
|
||||||
];
|
}
|
||||||
|
];
|
||||||
/**
|
|
||||||
* Direct tools that are always visible (not routed)
|
/**
|
||||||
* These are the most frequently used tools
|
* Direct tools that are always visible (not routed)
|
||||||
*/
|
* These are the most frequently used tools
|
||||||
export const directToolNames = [
|
*/
|
||||||
// Project lifecycle
|
export const directToolNames = [
|
||||||
"create_project",
|
// Project lifecycle
|
||||||
"open_project",
|
"create_project",
|
||||||
"save_project",
|
"open_project",
|
||||||
"snapshot_project",
|
"save_project",
|
||||||
"get_project_info",
|
"snapshot_project",
|
||||||
|
"get_project_info",
|
||||||
// Core PCB operations
|
|
||||||
"place_component",
|
// Core PCB operations
|
||||||
"move_component",
|
"place_component",
|
||||||
"add_net",
|
"move_component",
|
||||||
"route_trace",
|
"add_net",
|
||||||
"get_board_info",
|
"route_trace",
|
||||||
"set_board_size",
|
"get_board_info",
|
||||||
|
"set_board_size",
|
||||||
// Board setup
|
|
||||||
"add_board_outline",
|
// Board setup
|
||||||
|
"add_board_outline",
|
||||||
// Schematic essentials (always visible so AI uses them correctly)
|
|
||||||
"add_schematic_component",
|
// Schematic essentials (always visible so AI uses them correctly)
|
||||||
"list_schematic_components",
|
"add_schematic_component",
|
||||||
"annotate_schematic",
|
"list_schematic_components",
|
||||||
"connect_passthrough",
|
"annotate_schematic",
|
||||||
"connect_to_net",
|
"connect_passthrough",
|
||||||
"add_schematic_net_label",
|
"connect_to_net",
|
||||||
|
"add_schematic_net_label",
|
||||||
// Schematic <-> PCB sync (F8 equivalent)
|
|
||||||
"sync_schematic_to_board",
|
// Schematic <-> PCB sync (F8 equivalent)
|
||||||
|
"sync_schematic_to_board",
|
||||||
// UI management
|
|
||||||
"check_kicad_ui",
|
// UI management
|
||||||
];
|
"check_kicad_ui"
|
||||||
|
];
|
||||||
// Build lookup maps at module load time
|
|
||||||
const categoryMap = new Map<string, ToolCategory>();
|
// Build lookup maps at module load time
|
||||||
const toolCategoryMap = new Map<string, string>();
|
const categoryMap = new Map<string, ToolCategory>();
|
||||||
|
const toolCategoryMap = new Map<string, string>();
|
||||||
export function initializeRegistry() {
|
|
||||||
// Build category map
|
export function initializeRegistry() {
|
||||||
for (const category of toolCategories) {
|
// Build category map
|
||||||
categoryMap.set(category.name, category);
|
for (const category of toolCategories) {
|
||||||
|
categoryMap.set(category.name, category);
|
||||||
// Build tool -> category map
|
|
||||||
for (const toolName of category.tools) {
|
// Build tool -> category map
|
||||||
toolCategoryMap.set(toolName, category.name);
|
for (const toolName of category.tools) {
|
||||||
}
|
toolCategoryMap.set(toolName, category.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Get a category by name
|
/**
|
||||||
*/
|
* Get a category by name
|
||||||
export function getCategory(name: string): ToolCategory | undefined {
|
*/
|
||||||
return categoryMap.get(name);
|
export function getCategory(name: string): ToolCategory | undefined {
|
||||||
}
|
return categoryMap.get(name);
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Get the category name for a tool
|
/**
|
||||||
*/
|
* Get the category name for a tool
|
||||||
export function getToolCategory(toolName: string): string | undefined {
|
*/
|
||||||
return toolCategoryMap.get(toolName);
|
export function getToolCategory(toolName: string): string | undefined {
|
||||||
}
|
return toolCategoryMap.get(toolName);
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Get all categories
|
/**
|
||||||
*/
|
* Get all categories
|
||||||
export function getAllCategories(): ToolCategory[] {
|
*/
|
||||||
return toolCategories;
|
export function getAllCategories(): ToolCategory[] {
|
||||||
}
|
return toolCategories;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Get all routed tool names (excludes direct tools)
|
/**
|
||||||
*/
|
* Get all routed tool names (excludes direct tools)
|
||||||
export function getRoutedToolNames(): string[] {
|
*/
|
||||||
const allRoutedTools: string[] = [];
|
export function getRoutedToolNames(): string[] {
|
||||||
for (const category of toolCategories) {
|
const allRoutedTools: string[] = [];
|
||||||
allRoutedTools.push(...category.tools);
|
for (const category of toolCategories) {
|
||||||
}
|
allRoutedTools.push(...category.tools);
|
||||||
return allRoutedTools;
|
}
|
||||||
}
|
return allRoutedTools;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Check if a tool is a direct tool
|
/**
|
||||||
*/
|
* Check if a tool is a direct tool
|
||||||
export function isDirectTool(toolName: string): boolean {
|
*/
|
||||||
return directToolNames.includes(toolName);
|
export function isDirectTool(toolName: string): boolean {
|
||||||
}
|
return directToolNames.includes(toolName);
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Check if a tool is a routed tool
|
/**
|
||||||
*/
|
* Check if a tool is a routed tool
|
||||||
export function isRoutedTool(toolName: string): boolean {
|
*/
|
||||||
return toolCategoryMap.has(toolName);
|
export function isRoutedTool(toolName: string): boolean {
|
||||||
}
|
return toolCategoryMap.has(toolName);
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Search for tools by keyword
|
/**
|
||||||
* Searches tool names, descriptions, and category names
|
* Search for tools by keyword
|
||||||
*/
|
* Searches tool names, descriptions, and category names
|
||||||
export interface SearchResult {
|
*/
|
||||||
category: string;
|
export interface SearchResult {
|
||||||
tool: string;
|
category: string;
|
||||||
description: string;
|
tool: string;
|
||||||
}
|
description: string;
|
||||||
|
}
|
||||||
export function searchTools(query: string): SearchResult[] {
|
|
||||||
const q = query.toLowerCase();
|
export function searchTools(query: string): SearchResult[] {
|
||||||
const matches: SearchResult[] = [];
|
const q = query.toLowerCase();
|
||||||
|
const matches: SearchResult[] = [];
|
||||||
// Search direct tools first
|
|
||||||
for (const toolName of directToolNames) {
|
// Search direct tools first
|
||||||
if (toolName.toLowerCase().includes(q)) {
|
for (const toolName of directToolNames) {
|
||||||
matches.push({
|
if (toolName.toLowerCase().includes(q)) {
|
||||||
category: "direct",
|
matches.push({
|
||||||
tool: toolName,
|
category: "direct",
|
||||||
description: `${toolName} (direct tool — call directly, no execute_tool needed)`,
|
tool: toolName,
|
||||||
});
|
description: `${toolName} (direct tool — call directly, no execute_tool needed)`
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Search routed tools by name and category
|
|
||||||
for (const category of toolCategories) {
|
// Search routed tools by name and category
|
||||||
const categoryMatch =
|
for (const category of toolCategories) {
|
||||||
category.name.toLowerCase().includes(q) ||
|
const categoryMatch =
|
||||||
category.description.toLowerCase().includes(q);
|
category.name.toLowerCase().includes(q) ||
|
||||||
|
category.description.toLowerCase().includes(q);
|
||||||
for (const toolName of category.tools) {
|
|
||||||
if (toolName.toLowerCase().includes(q) || categoryMatch) {
|
for (const toolName of category.tools) {
|
||||||
matches.push({
|
if (toolName.toLowerCase().includes(q) || categoryMatch) {
|
||||||
category: category.name,
|
matches.push({
|
||||||
tool: toolName,
|
category: category.name,
|
||||||
description: `${toolName} (${category.name})`,
|
tool: toolName,
|
||||||
});
|
description: `${toolName} (${category.name})`
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return matches.slice(0, 20); // Limit results
|
|
||||||
}
|
return matches.slice(0, 20); // Limit results
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Get statistics about the tool registry
|
/**
|
||||||
*/
|
* Get statistics about the tool registry
|
||||||
export function getRegistryStats() {
|
*/
|
||||||
const routedToolCount = getRoutedToolNames().length;
|
export function getRegistryStats() {
|
||||||
const directToolCount = directToolNames.length;
|
const routedToolCount = getRoutedToolNames().length;
|
||||||
|
const directToolCount = directToolNames.length;
|
||||||
return {
|
|
||||||
total_categories: toolCategories.length,
|
return {
|
||||||
total_routed_tools: routedToolCount,
|
total_categories: toolCategories.length,
|
||||||
total_direct_tools: directToolCount,
|
total_routed_tools: routedToolCount,
|
||||||
total_tools: routedToolCount + directToolCount,
|
total_direct_tools: directToolCount,
|
||||||
categories: toolCategories.map((c) => ({
|
total_tools: routedToolCount + directToolCount,
|
||||||
name: c.name,
|
categories: toolCategories.map(c => ({
|
||||||
tool_count: c.tools.length,
|
name: c.name,
|
||||||
})),
|
tool_count: c.tools.length
|
||||||
};
|
}))
|
||||||
}
|
};
|
||||||
|
}
|
||||||
// Initialize on module load
|
|
||||||
initializeRegistry();
|
// Initialize on module load
|
||||||
|
initializeRegistry();
|
||||||
|
|||||||
@@ -161,37 +161,15 @@ preserves the component's position and UUID.
|
|||||||
Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_component.`,
|
Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_component.`,
|
||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
reference: z
|
reference: z.string().describe("Current reference designator of the component (e.g. R1, U3)"),
|
||||||
.string()
|
footprint: z.string().optional().describe("New KiCAD footprint string (e.g. Resistor_SMD:R_0603_1608Metric)"),
|
||||||
.describe(
|
value: z.string().optional().describe("New value string (e.g. 10k, 100nF)"),
|
||||||
"Current reference designator of the component (e.g. R1, U3)",
|
newReference: z.string().optional().describe("Rename the reference designator (e.g. R1 → R10)"),
|
||||||
),
|
fieldPositions: z.record(z.object({
|
||||||
footprint: z
|
x: z.number(),
|
||||||
.string()
|
y: z.number(),
|
||||||
.optional()
|
angle: z.number().optional().default(0),
|
||||||
.describe(
|
})).optional().describe("Reposition field labels: map of field name to {x, y, angle} (e.g. {\"Reference\": {\"x\": 12.5, \"y\": 17.0}})"),
|
||||||
"New KiCAD footprint string (e.g. Resistor_SMD:R_0603_1608Metric)",
|
|
||||||
),
|
|
||||||
value: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("New value string (e.g. 10k, 100nF)"),
|
|
||||||
newReference: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Rename the reference designator (e.g. R1 → R10)"),
|
|
||||||
fieldPositions: z
|
|
||||||
.record(
|
|
||||||
z.object({
|
|
||||||
x: z.number(),
|
|
||||||
y: z.number(),
|
|
||||||
angle: z.number().optional().default(0),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.optional()
|
|
||||||
.describe(
|
|
||||||
'Reposition field labels: map of field name to {x, y, angle} (e.g. {"Reference": {"x": 12.5, "y": 17.0}})',
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
@@ -232,9 +210,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"Get full component info from a schematic: position, field values, and each field's label position (at x/y/angle). Use this to inspect or prepare repositioning of Reference/Value labels.",
|
"Get full component info from a schematic: position, field values, and each field's label position (at x/y/angle). Use this to inspect or prepare repositioning of Reference/Value labels.",
|
||||||
{
|
{
|
||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
reference: z
|
reference: z.string().describe("Component reference designator (e.g. R1, U1)"),
|
||||||
.string()
|
|
||||||
.describe("Component reference designator (e.g. R1, U1)"),
|
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string; reference: string }) => {
|
async (args: { schematicPath: string; reference: string }) => {
|
||||||
const result = await callKicadScript("get_schematic_component", args);
|
const result = await callKicadScript("get_schematic_component", args);
|
||||||
@@ -244,24 +220,20 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
: "unknown";
|
: "unknown";
|
||||||
const fieldLines = Object.entries(result.fields ?? {}).map(
|
const fieldLines = Object.entries(result.fields ?? {}).map(
|
||||||
([name, f]: [string, any]) =>
|
([name, f]: [string, any]) =>
|
||||||
` ${name}: "${f.value}" @ (${f.x}, ${f.y}, angle=${f.angle}°)`,
|
` ${name}: "${f.value}" @ (${f.x}, ${f.y}, angle=${f.angle}°)`
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{
|
||||||
{
|
type: "text",
|
||||||
type: "text",
|
text: `Component ${result.reference} at ${pos}\nFields:\n${fieldLines.join("\n")}`,
|
||||||
text: `Component ${result.reference} at ${pos}\nFields:\n${fieldLines.join("\n")}`,
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{
|
||||||
{
|
type: "text",
|
||||||
type: "text",
|
text: `Failed to get component: ${result.message || "Unknown error"}`,
|
||||||
text: `Failed to get component: ${result.message || "Unknown error"}`,
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -608,14 +580,8 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
filter: z
|
filter: z
|
||||||
.object({
|
.object({
|
||||||
libId: z
|
libId: z.string().optional().describe("Filter by library ID (e.g., 'Device:R')"),
|
||||||
.string()
|
referencePrefix: z.string().optional().describe("Filter by reference prefix (e.g., 'R', 'C', 'U')"),
|
||||||
.optional()
|
|
||||||
.describe("Filter by library ID (e.g., 'Device:R')"),
|
|
||||||
referencePrefix: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Filter by reference prefix (e.g., 'R', 'C', 'U')"),
|
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Optional filters"),
|
.describe("Optional filters"),
|
||||||
@@ -629,9 +595,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
const comps = result.components || [];
|
const comps = result.components || [];
|
||||||
if (comps.length === 0) {
|
if (comps.length === 0) {
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{ type: "text", text: "No components found in schematic." }],
|
||||||
{ type: "text", text: "No components found in schematic." },
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const lines = comps.map(
|
const lines = comps.map(
|
||||||
@@ -692,10 +656,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{ type: "text", text: `Failed to list nets: ${result.message || "Unknown error"}` },
|
||||||
type: "text",
|
|
||||||
text: `Failed to list nets: ${result.message || "Unknown error"}`,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
isError: true,
|
isError: true,
|
||||||
};
|
};
|
||||||
@@ -733,10 +694,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{ type: "text", text: `Failed to list wires: ${result.message || "Unknown error"}` },
|
||||||
type: "text",
|
|
||||||
text: `Failed to list wires: ${result.message || "Unknown error"}`,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
isError: true,
|
isError: true,
|
||||||
};
|
};
|
||||||
@@ -774,10 +732,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{ type: "text", text: `Failed to list labels: ${result.message || "Unknown error"}` },
|
||||||
type: "text",
|
|
||||||
text: `Failed to list labels: ${result.message || "Unknown error"}`,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
isError: true,
|
isError: true,
|
||||||
};
|
};
|
||||||
@@ -834,7 +789,10 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
schematicPath: z.string().describe("Path to the .kicad_sch file"),
|
||||||
reference: z.string().describe("Reference designator (e.g., R1, U1)"),
|
reference: z.string().describe("Reference designator (e.g., R1, U1)"),
|
||||||
angle: z.number().describe("Rotation angle in degrees (0, 90, 180, 270)"),
|
angle: z.number().describe("Rotation angle in degrees (0, 90, 180, 270)"),
|
||||||
mirror: z.enum(["x", "y"]).optional().describe("Optional mirror axis"),
|
mirror: z
|
||||||
|
.enum(["x", "y"])
|
||||||
|
.optional()
|
||||||
|
.describe("Optional mirror axis"),
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
@@ -1078,14 +1036,8 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
.enum(["png", "svg"])
|
.enum(["png", "svg"])
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Output format (default: png)"),
|
.describe("Output format (default: png)"),
|
||||||
width: z
|
width: z.number().optional().describe("Image width in pixels (default: 1200)"),
|
||||||
.number()
|
height: z.number().optional().describe("Image height in pixels (default: 900)"),
|
||||||
.optional()
|
|
||||||
.describe("Image width in pixels (default: 1200)"),
|
|
||||||
height: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Image height in pixels (default: 900)"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
@@ -1255,35 +1207,19 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"get_schematic_view_region",
|
"get_schematic_view_region",
|
||||||
"Export a cropped region of the schematic as an image (PNG or SVG). Specify bounding box coordinates in schematic mm. Useful for zooming into a specific area to inspect wiring or layout.",
|
"Export a cropped region of the schematic as an image (PNG or SVG). Specify bounding box coordinates in schematic mm. Useful for zooming into a specific area to inspect wiring or layout.",
|
||||||
{
|
{
|
||||||
schematicPath: z
|
schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
|
||||||
.string()
|
|
||||||
.describe("Path to the .kicad_sch schematic file"),
|
|
||||||
x1: z.number().describe("Left X coordinate of the region in mm"),
|
x1: z.number().describe("Left X coordinate of the region in mm"),
|
||||||
y1: z.number().describe("Top Y coordinate of the region in mm"),
|
y1: z.number().describe("Top Y coordinate of the region in mm"),
|
||||||
x2: z.number().describe("Right X coordinate of the region in mm"),
|
x2: z.number().describe("Right X coordinate of the region in mm"),
|
||||||
y2: z.number().describe("Bottom Y coordinate of the region in mm"),
|
y2: z.number().describe("Bottom Y coordinate of the region in mm"),
|
||||||
format: z
|
format: z.enum(["png", "svg"]).optional().describe("Output image format (default: png)"),
|
||||||
.enum(["png", "svg"])
|
width: z.number().optional().describe("Output image width in pixels (default: 800)"),
|
||||||
.optional()
|
height: z.number().optional().describe("Output image height in pixels (default: 600)"),
|
||||||
.describe("Output image format (default: png)"),
|
|
||||||
width: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Output image width in pixels (default: 800)"),
|
|
||||||
height: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Output image height in pixels (default: 600)"),
|
|
||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
x1: number;
|
x1: number; y1: number; x2: number; y2: number;
|
||||||
y1: number;
|
format?: string; width?: number; height?: number;
|
||||||
x2: number;
|
|
||||||
y2: number;
|
|
||||||
format?: string;
|
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
}) => {
|
}) => {
|
||||||
const result = await callKicadScript("get_schematic_view_region", args);
|
const result = await callKicadScript("get_schematic_view_region", args);
|
||||||
if (result.success && result.imageData) {
|
if (result.success && result.imageData) {
|
||||||
@@ -1291,40 +1227,27 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
return { content: [{ type: "text", text: result.imageData }] };
|
return { content: [{ type: "text", text: result.imageData }] };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{
|
||||||
{
|
type: "image",
|
||||||
type: "image",
|
data: result.imageData,
|
||||||
data: result.imageData,
|
mimeType: "image/png",
|
||||||
mimeType: "image/png",
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{ type: "text", text: `Failed: ${result.message || "Unknown error"}` }],
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
text: `Failed: ${result.message || "Unknown error"}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Find overlapping elements
|
// Find overlapping elements
|
||||||
server.tool(
|
server.tool(
|
||||||
"find_overlapping_elements",
|
"find_overlapping_elements",
|
||||||
"Detect spatially overlapping symbols, wires, and labels in the schematic. Finds duplicate power symbols at the same position, collinear overlapping wires, and labels stacked on top of each other.",
|
"Detect spatially overlapping symbols, wires, and labels in the schematic. Finds duplicate power symbols at the same position, collinear overlapping wires, and labels stacked on top of each other.",
|
||||||
{
|
{
|
||||||
schematicPath: z
|
schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
|
||||||
.string()
|
tolerance: z.number().optional().describe("Distance threshold in mm for label proximity and wire collinearity checks. Symbol overlap uses bounding-box intersection. (default: 0.5)"),
|
||||||
.describe("Path to the .kicad_sch schematic file"),
|
|
||||||
tolerance: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe(
|
|
||||||
"Distance threshold in mm for label proximity and wire collinearity checks. Symbol overlap uses bounding-box intersection. (default: 0.5)",
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string; tolerance?: number }) => {
|
async (args: { schematicPath: string; tolerance?: number }) => {
|
||||||
const result = await callKicadScript("find_overlapping_elements", args);
|
const result = await callKicadScript("find_overlapping_elements", args);
|
||||||
@@ -1336,36 +1259,25 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
if (syms.length) {
|
if (syms.length) {
|
||||||
lines.push(`\nOverlapping symbols (${syms.length}):`);
|
lines.push(`\nOverlapping symbols (${syms.length}):`);
|
||||||
syms.slice(0, 20).forEach((o: any) => {
|
syms.slice(0, 20).forEach((o: any) => {
|
||||||
lines.push(
|
lines.push(` ${o.element1.reference} ↔ ${o.element2.reference} (${o.distance}mm) [${o.type}]`);
|
||||||
` ${o.element1.reference} ↔ ${o.element2.reference} (${o.distance}mm) [${o.type}]`,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (lbls.length) {
|
if (lbls.length) {
|
||||||
lines.push(`\nOverlapping labels (${lbls.length}):`);
|
lines.push(`\nOverlapping labels (${lbls.length}):`);
|
||||||
lbls.slice(0, 20).forEach((o: any) => {
|
lbls.slice(0, 20).forEach((o: any) => {
|
||||||
lines.push(
|
lines.push(` "${o.element1.name}" ↔ "${o.element2.name}" (${o.distance}mm)`);
|
||||||
` "${o.element1.name}" ↔ "${o.element2.name}" (${o.distance}mm)`,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (wires.length) {
|
if (wires.length) {
|
||||||
lines.push(`\nOverlapping wires (${wires.length}):`);
|
lines.push(`\nOverlapping wires (${wires.length}):`);
|
||||||
wires.slice(0, 20).forEach((o: any) => {
|
wires.slice(0, 20).forEach((o: any) => {
|
||||||
lines.push(
|
lines.push(` wire @ (${o.wire1.start.x},${o.wire1.start.y})→(${o.wire1.end.x},${o.wire1.end.y}) overlaps with another`);
|
||||||
` wire @ (${o.wire1.start.x},${o.wire1.start.y})→(${o.wire1.end.x},${o.wire1.end.y}) overlaps with another`,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { content: [{ type: "text", text: lines.join("\n") }] };
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{ type: "text", text: `Failed: ${result.message || "Unknown error"}` }],
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
text: `Failed: ${result.message || "Unknown error"}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -1375,9 +1287,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"get_elements_in_region",
|
"get_elements_in_region",
|
||||||
"List all symbols, wires, and labels within a rectangular region of the schematic. Useful for understanding what is in a specific area before modifying it.",
|
"List all symbols, wires, and labels within a rectangular region of the schematic. Useful for understanding what is in a specific area before modifying it.",
|
||||||
{
|
{
|
||||||
schematicPath: z
|
schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
|
||||||
.string()
|
|
||||||
.describe("Path to the .kicad_sch schematic file"),
|
|
||||||
x1: z.number().describe("Left X coordinate of the region in mm"),
|
x1: z.number().describe("Left X coordinate of the region in mm"),
|
||||||
y1: z.number().describe("Top Y coordinate of the region in mm"),
|
y1: z.number().describe("Top Y coordinate of the region in mm"),
|
||||||
x2: z.number().describe("Right X coordinate of the region in mm"),
|
x2: z.number().describe("Right X coordinate of the region in mm"),
|
||||||
@@ -1385,56 +1295,39 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
},
|
},
|
||||||
async (args: {
|
async (args: {
|
||||||
schematicPath: string;
|
schematicPath: string;
|
||||||
x1: number;
|
x1: number; y1: number; x2: number; y2: number;
|
||||||
y1: number;
|
|
||||||
x2: number;
|
|
||||||
y2: number;
|
|
||||||
}) => {
|
}) => {
|
||||||
const result = await callKicadScript("get_elements_in_region", args);
|
const result = await callKicadScript("get_elements_in_region", args);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const c = result.counts;
|
const c = result.counts;
|
||||||
const lines = [
|
const lines = [`Region (${args.x1},${args.y1})→(${args.x2},${args.y2}): ${c.symbols} symbols, ${c.wires} wires, ${c.labels} labels`];
|
||||||
`Region (${args.x1},${args.y1})→(${args.x2},${args.y2}): ${c.symbols} symbols, ${c.wires} wires, ${c.labels} labels`,
|
|
||||||
];
|
|
||||||
const syms: any[] = result.symbols || [];
|
const syms: any[] = result.symbols || [];
|
||||||
if (syms.length) {
|
if (syms.length) {
|
||||||
lines.push("\nSymbols:");
|
lines.push("\nSymbols:");
|
||||||
syms.forEach((s: any) => {
|
syms.forEach((s: any) => {
|
||||||
const pinCount = s.pins ? Object.keys(s.pins).length : 0;
|
const pinCount = s.pins ? Object.keys(s.pins).length : 0;
|
||||||
lines.push(
|
lines.push(` ${s.reference} (${s.libId}) @ (${s.position.x}, ${s.position.y}) [${pinCount} pins]`);
|
||||||
` ${s.reference} (${s.libId}) @ (${s.position.x}, ${s.position.y}) [${pinCount} pins]`,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const wires: any[] = result.wires || [];
|
const wires: any[] = result.wires || [];
|
||||||
if (wires.length) {
|
if (wires.length) {
|
||||||
lines.push(`\nWires (${wires.length}):`);
|
lines.push(`\nWires (${wires.length}):`);
|
||||||
wires.slice(0, 30).forEach((w: any) => {
|
wires.slice(0, 30).forEach((w: any) => {
|
||||||
lines.push(
|
lines.push(` (${w.start.x},${w.start.y}) → (${w.end.x},${w.end.y})`);
|
||||||
` (${w.start.x},${w.start.y}) → (${w.end.x},${w.end.y})`,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
if (wires.length > 30)
|
if (wires.length > 30) lines.push(` ... and ${wires.length - 30} more`);
|
||||||
lines.push(` ... and ${wires.length - 30} more`);
|
|
||||||
}
|
}
|
||||||
const labels: any[] = result.labels || [];
|
const labels: any[] = result.labels || [];
|
||||||
if (labels.length) {
|
if (labels.length) {
|
||||||
lines.push(`\nLabels (${labels.length}):`);
|
lines.push(`\nLabels (${labels.length}):`);
|
||||||
labels.forEach((l: any) => {
|
labels.forEach((l: any) => {
|
||||||
lines.push(
|
lines.push(` "${l.name}" [${l.type}] @ (${l.position.x}, ${l.position.y})`);
|
||||||
` "${l.name}" [${l.type}] @ (${l.position.x}, ${l.position.y})`,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { content: [{ type: "text", text: lines.join("\n") }] };
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{ type: "text", text: `Failed: ${result.message || "Unknown error"}` }],
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
text: `Failed: ${result.message || "Unknown error"}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -1444,9 +1337,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
"find_wires_crossing_symbols",
|
"find_wires_crossing_symbols",
|
||||||
"Find all wires that cross over component symbol bodies. Wires passing over symbols are unacceptable in schematics — they indicate routing mistakes where a wire was drawn across a component instead of around it.",
|
"Find all wires that cross over component symbol bodies. Wires passing over symbols are unacceptable in schematics — they indicate routing mistakes where a wire was drawn across a component instead of around it.",
|
||||||
{
|
{
|
||||||
schematicPath: z
|
schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
|
||||||
.string()
|
|
||||||
.describe("Path to the .kicad_sch schematic file"),
|
|
||||||
},
|
},
|
||||||
async (args: { schematicPath: string }) => {
|
async (args: { schematicPath: string }) => {
|
||||||
const result = await callKicadScript("find_wires_crossing_symbols", args);
|
const result = await callKicadScript("find_wires_crossing_symbols", args);
|
||||||
@@ -1455,20 +1346,14 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
|
|||||||
const lines = [`Found ${collisions.length} wire(s) crossing symbols:`];
|
const lines = [`Found ${collisions.length} wire(s) crossing symbols:`];
|
||||||
collisions.slice(0, 30).forEach((c: any, i: number) => {
|
collisions.slice(0, 30).forEach((c: any, i: number) => {
|
||||||
lines.push(
|
lines.push(
|
||||||
` ${i + 1}. Wire (${c.wire.start.x},${c.wire.start.y})→(${c.wire.end.x},${c.wire.end.y}) crosses ${c.component.reference} (${c.component.libId})`,
|
` ${i + 1}. Wire (${c.wire.start.x},${c.wire.start.y})→(${c.wire.end.x},${c.wire.end.y}) crosses ${c.component.reference} (${c.component.libId})`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (collisions.length > 30)
|
if (collisions.length > 30) lines.push(` ... and ${collisions.length - 30} more`);
|
||||||
lines.push(` ... and ${collisions.length - 30} more`);
|
|
||||||
return { content: [{ type: "text", text: lines.join("\n") }] };
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [{ type: "text", text: `Failed: ${result.message || "Unknown error"}` }],
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
text: `Failed: ${result.message || "Unknown error"}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user