/** * Library tools for KiCAD MCP server * Provides access to KiCAD footprint libraries and symbols */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; export function registerLibraryTools(server: McpServer, callKicadScript: Function) { // List available footprint libraries server.tool( "list_libraries", "List all available KiCAD footprint libraries", { search_paths: z .array(z.string()) .optional() .describe("Optional additional search paths for libraries"), }, async (args: { search_paths?: string[] }) => { const result = await callKicadScript("list_libraries", args); if (result.success && result.libraries) { return { content: [ { type: "text", text: `Found ${result.libraries.length} footprint libraries:\n${result.libraries.join("\n")}`, }, ], }; } return { content: [ { type: "text", text: `Failed to list libraries: ${result.message || "Unknown error"}`, }, ], }; }, ); // Search for footprints across all libraries server.tool( "search_footprints", "Search for footprints matching a pattern across all libraries", { search_term: z.string().describe("Search term or pattern to match footprint names"), library: z.string().optional().describe("Optional specific library to search in"), limit: z.number().optional().default(50).describe("Maximum number of results to return"), }, async (args: { search_term: string; library?: string; limit?: number }) => { const result = await callKicadScript("search_footprints", { pattern: args.search_term, library: args.library, limit: args.limit, }); if (result.success && result.footprints) { const footprintList = result.footprints .map( (fp: any) => `${fp.full_name || fp.library + ":" + fp.footprint}${fp.description ? " - " + fp.description : ""}`, ) .join("\n"); return { content: [ { type: "text", text: `Found ${result.footprints.length} matching footprints:\n${footprintList}`, }, ], }; } return { content: [ { type: "text", text: `Failed to search footprints: ${result.message || "Unknown error"}`, }, ], }; }, ); // List footprints in a specific library server.tool( "list_library_footprints", "List all footprints in a specific KiCAD library", { library_name: z.string().describe("Name of the library to list footprints from"), filter: z.string().optional().describe("Optional filter pattern for footprint names"), limit: z.number().optional().default(100).describe("Maximum number of footprints to list"), }, async (args: { library_name: string; filter?: string; limit?: number }) => { const result = await callKicadScript("list_library_footprints", args); if (result.success && result.footprints) { const footprintList = result.footprints.map((fp: string) => ` - ${fp}`).join("\n"); return { content: [ { type: "text", text: `Library ${args.library_name} contains ${result.footprints.length} footprints:\n${footprintList}`, }, ], }; } return { content: [ { type: "text", text: `Failed to list footprints in library ${args.library_name}: ${result.message || "Unknown error"}`, }, ], }; }, ); // Get detailed information about a specific footprint server.tool( "get_footprint_info", "Get detailed information about a specific footprint", { library_name: z.string().describe("Name of the library containing the footprint"), footprint_name: z.string().describe("Name of the footprint to get information about"), }, async (args: { library_name: string; footprint_name: string }) => { const result = await callKicadScript("get_footprint_info", args); if (result.success && result.info) { const info = result.info; // pads is a list of {number, type, shape} objects const padsArray: Array<{ number: string; type: string; shape: string }> = Array.isArray( info.pads, ) ? info.pads : []; const padsSummary = padsArray.length ? `${padsArray.length} pads: ${padsArray.map((p) => p.number).join(", ")}` : ""; const padsDetail = padsArray.length ? padsArray.map((p) => ` pad ${p.number}: ${p.type} ${p.shape}`).join("\n") : ""; const details = [ `Footprint: ${info.name}`, `Library: ${info.library}`, info.description ? `Description: ${info.description}` : "", info.keywords ? `Keywords: ${info.keywords}` : "", padsSummary, padsDetail, info.layers ? `Layers used: ${info.layers.join(", ")}` : "", info.courtyard ? `Courtyard size: ${info.courtyard.width}mm x ${info.courtyard.height}mm` : "", info.attributes ? `Attributes: ${JSON.stringify(info.attributes)}` : "", ] .filter((line) => line) .join("\n"); return { content: [ { type: "text", text: details, }, ], }; } return { content: [ { type: "text", text: `Failed to get footprint info: ${result.message || "Unknown error"}`, }, ], }; }, ); }