Skip to main content
Glama
board.ts11.2 kB
/** * Board resources for KiCAD MCP server * * These resources provide information about the PCB board * to the LLM, enabling better context-aware assistance. */ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { logger } from '../logger.js'; import { createJsonResponse, createBinaryResponse } from '../utils/resource-helpers.js'; // Command function type for KiCAD script calls type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>; /** * Register board resources with the MCP server * * @param server MCP server instance * @param callKicadScript Function to call KiCAD script commands */ export function registerBoardResources(server: McpServer, callKicadScript: CommandFunction): void { logger.info('Registering board resources'); // ------------------------------------------------------ // Board Information Resource // ------------------------------------------------------ server.resource( "board_info", "kicad://board/info", async (uri) => { logger.debug('Retrieving board information'); const result = await callKicadScript("get_board_info", {}); if (!result.success) { logger.error(`Failed to retrieve board information: ${result.errorDetails}`); return { contents: [{ uri: uri.href, text: JSON.stringify({ error: "Failed to retrieve board information", details: result.errorDetails }), mimeType: "application/json" }] }; } logger.debug('Successfully retrieved board information'); return { contents: [{ uri: uri.href, text: JSON.stringify(result), mimeType: "application/json" }] }; } ); // ------------------------------------------------------ // Layer List Resource // ------------------------------------------------------ server.resource( "layer_list", "kicad://board/layers", async (uri) => { logger.debug('Retrieving layer list'); const result = await callKicadScript("get_layer_list", {}); if (!result.success) { logger.error(`Failed to retrieve layer list: ${result.errorDetails}`); return { contents: [{ uri: uri.href, text: JSON.stringify({ error: "Failed to retrieve layer list", details: result.errorDetails }), mimeType: "application/json" }] }; } logger.debug(`Successfully retrieved ${result.layers?.length || 0} layers`); return { contents: [{ uri: uri.href, text: JSON.stringify(result), mimeType: "application/json" }] }; } ); // ------------------------------------------------------ // Board Extents Resource // ------------------------------------------------------ server.resource( "board_extents", new ResourceTemplate("kicad://board/extents/{unit?}", { list: async () => ({ resources: [ { uri: "kicad://board/extents/mm", name: "Millimeters" }, { uri: "kicad://board/extents/inch", name: "Inches" } ] }) }), async (uri, params) => { const unit = params.unit || 'mm'; logger.debug(`Retrieving board extents in ${unit}`); const result = await callKicadScript("get_board_extents", { unit }); if (!result.success) { logger.error(`Failed to retrieve board extents: ${result.errorDetails}`); return { contents: [{ uri: uri.href, text: JSON.stringify({ error: "Failed to retrieve board extents", details: result.errorDetails }), mimeType: "application/json" }] }; } logger.debug('Successfully retrieved board extents'); return { contents: [{ uri: uri.href, text: JSON.stringify(result), mimeType: "application/json" }] }; } ); // ------------------------------------------------------ // Board 2D View Resource // ------------------------------------------------------ server.resource( "board_2d_view", new ResourceTemplate("kicad://board/2d-view/{format?}", { list: async () => ({ resources: [ { uri: "kicad://board/2d-view/png", name: "PNG Format" }, { uri: "kicad://board/2d-view/jpg", name: "JPEG Format" }, { uri: "kicad://board/2d-view/svg", name: "SVG Format" } ] }) }), async (uri, params) => { const format = (params.format || 'png') as 'png' | 'jpg' | 'svg'; const width = params.width ? parseInt(params.width as string) : undefined; const height = params.height ? parseInt(params.height as string) : undefined; // Handle layers parameter - could be string or array const layers = typeof params.layers === 'string' ? params.layers.split(',') : params.layers; logger.debug('Retrieving 2D board view'); const result = await callKicadScript("get_board_2d_view", { layers, width, height, format }); if (!result.success) { logger.error(`Failed to retrieve 2D board view: ${result.errorDetails}`); return { contents: [{ uri: uri.href, text: JSON.stringify({ error: "Failed to retrieve 2D board view", details: result.errorDetails }), mimeType: "application/json" }] }; } logger.debug('Successfully retrieved 2D board view'); if (format === 'svg') { return { contents: [{ uri: uri.href, text: result.imageData, mimeType: "image/svg+xml" }] }; } else { return { contents: [{ uri: uri.href, blob: result.imageData, mimeType: format === "jpg" ? "image/jpeg" : "image/png" }] }; } } ); // ------------------------------------------------------ // Board 3D View Resource // ------------------------------------------------------ server.resource( "board_3d_view", new ResourceTemplate("kicad://board/3d-view/{angle?}", { list: async () => ({ resources: [ { uri: "kicad://board/3d-view/isometric", name: "Isometric View" }, { uri: "kicad://board/3d-view/top", name: "Top View" }, { uri: "kicad://board/3d-view/bottom", name: "Bottom View" } ] }) }), async (uri, params) => { const angle = params.angle || 'isometric'; const width = params.width ? parseInt(params.width as string) : undefined; const height = params.height ? parseInt(params.height as string) : undefined; logger.debug(`Retrieving 3D board view from ${angle} angle`); const result = await callKicadScript("get_board_3d_view", { width, height, angle }); if (!result.success) { logger.error(`Failed to retrieve 3D board view: ${result.errorDetails}`); return { contents: [{ uri: uri.href, text: JSON.stringify({ error: "Failed to retrieve 3D board view", details: result.errorDetails }), mimeType: "application/json" }] }; } logger.debug('Successfully retrieved 3D board view'); return { contents: [{ uri: uri.href, blob: result.imageData, mimeType: "image/png" }] }; } ); // ------------------------------------------------------ // Board Statistics Resource // ------------------------------------------------------ server.resource( "board_statistics", "kicad://board/statistics", async (uri) => { logger.debug('Generating board statistics'); // Get board info const boardResult = await callKicadScript("get_board_info", {}); if (!boardResult.success) { logger.error(`Failed to retrieve board information: ${boardResult.errorDetails}`); return { contents: [{ uri: uri.href, text: JSON.stringify({ error: "Failed to generate board statistics", details: boardResult.errorDetails }), mimeType: "application/json" }] }; } // Get component list const componentsResult = await callKicadScript("get_component_list", {}); if (!componentsResult.success) { logger.error(`Failed to retrieve component list: ${componentsResult.errorDetails}`); return { contents: [{ uri: uri.href, text: JSON.stringify({ error: "Failed to generate board statistics", details: componentsResult.errorDetails }), mimeType: "application/json" }] }; } // Get nets list const netsResult = await callKicadScript("get_nets_list", {}); if (!netsResult.success) { logger.error(`Failed to retrieve nets list: ${netsResult.errorDetails}`); return { contents: [{ uri: uri.href, text: JSON.stringify({ error: "Failed to generate board statistics", details: netsResult.errorDetails }), mimeType: "application/json" }] }; } // Combine all information into statistics const statistics = { board: { size: boardResult.size, layers: boardResult.layers?.length || 0, title: boardResult.title }, components: { count: componentsResult.components?.length || 0, types: countComponentTypes(componentsResult.components || []) }, nets: { count: netsResult.nets?.length || 0 } }; logger.debug('Successfully generated board statistics'); return { contents: [{ uri: uri.href, text: JSON.stringify(statistics), mimeType: "application/json" }] }; } ); logger.info('Board resources registered'); } /** * Helper function to count component types */ function countComponentTypes(components: any[]): Record<string, number> { const typeCounts: Record<string, number> = {}; for (const component of components) { const type = component.value?.split(' ')[0] || 'Unknown'; typeCounts[type] = (typeCounts[type] || 0) + 1; } return typeCounts; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mixelpixx/KiCAD-MCP-Server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server