style: apply Prettier formatting to TS/JS/JSON/MD files
Add Prettier as a dev dependency with .prettierrc.json config and .prettierignore. Hook added via mirrors-prettier in pre-commit config. All TypeScript, JSON, Markdown, and YAML files auto-formatted. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,354 +1,372 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* to the LLM, enabling better context-aware assistance.
|
||||
*/
|
||||
|
||||
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { logger } from '../logger.js';
|
||||
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { logger } from "../logger.js";
|
||||
|
||||
// Command function type for KiCAD script calls
|
||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||
@@ -17,43 +17,46 @@ type CommandFunction = (command: string, params: Record<string, unknown>) => Pro
|
||||
* @param server MCP server instance
|
||||
* @param callKicadScript Function to call KiCAD script commands
|
||||
*/
|
||||
export function registerComponentResources(server: McpServer, callKicadScript: CommandFunction): void {
|
||||
logger.info('Registering component resources');
|
||||
export function registerComponentResources(
|
||||
server: McpServer,
|
||||
callKicadScript: CommandFunction,
|
||||
): void {
|
||||
logger.info("Registering component resources");
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component List Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_list",
|
||||
"kicad://components",
|
||||
async (uri) => {
|
||||
logger.debug('Retrieving component list');
|
||||
const result = await callKicadScript("get_component_list", {});
|
||||
server.resource("component_list", "kicad://components", async (uri) => {
|
||||
logger.debug("Retrieving component list");
|
||||
const result = await callKicadScript("get_component_list", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component list: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component list: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve component list",
|
||||
details: result.errorDetails
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.components?.length || 0} components`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.components?.length || 0} components`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Details Resource
|
||||
@@ -61,38 +64,42 @@ export function registerComponentResources(server: McpServer, callKicadScript: C
|
||||
server.resource(
|
||||
"component_details",
|
||||
new ResourceTemplate("kicad://component/{reference}/details", {
|
||||
list: undefined
|
||||
list: undefined,
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { reference } = params;
|
||||
logger.debug(`Retrieving details for component: ${reference}`);
|
||||
const result = await callKicadScript("get_component_properties", {
|
||||
reference
|
||||
reference,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component details: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve details for component ${reference}`,
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve details for component ${reference}`,
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved details for component: ${reference}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
@@ -101,109 +108,113 @@ export function registerComponentResources(server: McpServer, callKicadScript: C
|
||||
server.resource(
|
||||
"component_connections",
|
||||
new ResourceTemplate("kicad://component/{reference}/connections", {
|
||||
list: undefined
|
||||
list: undefined,
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { reference } = params;
|
||||
logger.debug(`Retrieving connections for component: ${reference}`);
|
||||
const result = await callKicadScript("get_component_connections", {
|
||||
reference
|
||||
reference,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component connections: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve connections for component ${reference}`,
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve connections for component ${reference}`,
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved connections for component: ${reference}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Placement Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_placement",
|
||||
"kicad://components/placement",
|
||||
async (uri) => {
|
||||
logger.debug('Retrieving component placement information');
|
||||
const result = await callKicadScript("get_component_placement", {});
|
||||
server.resource("component_placement", "kicad://components/placement", async (uri) => {
|
||||
logger.debug("Retrieving component placement information");
|
||||
const result = await callKicadScript("get_component_placement", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component placement: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component placement: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve component placement information",
|
||||
details: result.errorDetails
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug('Successfully retrieved component placement information');
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
logger.debug("Successfully retrieved component placement information");
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Groups Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_groups",
|
||||
"kicad://components/groups",
|
||||
async (uri) => {
|
||||
logger.debug('Retrieving component groups');
|
||||
const result = await callKicadScript("get_component_groups", {});
|
||||
server.resource("component_groups", "kicad://components/groups", async (uri) => {
|
||||
logger.debug("Retrieving component groups");
|
||||
const result = await callKicadScript("get_component_groups", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component groups: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component groups: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve component groups",
|
||||
details: result.errorDetails
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.groups?.length || 0} component groups`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.groups?.length || 0} component groups`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Visualization Resource
|
||||
@@ -211,39 +222,43 @@ export function registerComponentResources(server: McpServer, callKicadScript: C
|
||||
server.resource(
|
||||
"component_visualization",
|
||||
new ResourceTemplate("kicad://component/{reference}/visualization", {
|
||||
list: undefined
|
||||
list: undefined,
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { reference } = params;
|
||||
logger.debug(`Generating visualization for component: ${reference}`);
|
||||
const result = await callKicadScript("get_component_visualization", {
|
||||
reference
|
||||
reference,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to generate component visualization: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to generate visualization for component ${reference}`,
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to generate visualization for component ${reference}`,
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully generated visualization for component: ${reference}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
blob: result.imageData, // Base64 encoded image data
|
||||
mimeType: "image/png"
|
||||
}]
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
blob: result.imageData, // Base64 encoded image data
|
||||
mimeType: "image/png",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
logger.info('Component resources registered');
|
||||
logger.info("Component resources registered");
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* Resources index for KiCAD MCP server
|
||||
*
|
||||
* Exports all resource registration functions
|
||||
*/
|
||||
|
||||
export { registerProjectResources } from './project.js';
|
||||
export { registerBoardResources } from './board.js';
|
||||
export { registerComponentResources } from './component.js';
|
||||
export { registerLibraryResources } from './library.js';
|
||||
/**
|
||||
* Resources index for KiCAD MCP server
|
||||
*
|
||||
* Exports all resource registration functions
|
||||
*/
|
||||
|
||||
export { registerProjectResources } from "./project.js";
|
||||
export { registerBoardResources } from "./board.js";
|
||||
export { registerComponentResources } from "./component.js";
|
||||
export { registerLibraryResources } from "./library.js";
|
||||
|
||||
@@ -1,290 +1,323 @@
|
||||
/**
|
||||
* Library resources for KiCAD MCP server
|
||||
*
|
||||
* These resources provide information about KiCAD component libraries
|
||||
* 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';
|
||||
|
||||
// Command function type for KiCAD script calls
|
||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||
|
||||
/**
|
||||
* Register library resources with the MCP server
|
||||
*
|
||||
* @param server MCP server instance
|
||||
* @param callKicadScript Function to call KiCAD script commands
|
||||
*/
|
||||
export function registerLibraryResources(server: McpServer, callKicadScript: CommandFunction): void {
|
||||
logger.info('Registering library resources');
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Library Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_library",
|
||||
new ResourceTemplate("kicad://components/{filter?}/{library?}", {
|
||||
list: async () => ({
|
||||
resources: [
|
||||
{ uri: "kicad://components", name: "All Components" }
|
||||
]
|
||||
})
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const filter = params.filter || '';
|
||||
const library = params.library || '';
|
||||
const limit = Number(params.limit) || undefined;
|
||||
|
||||
logger.debug(`Retrieving component library${filter ? ` with filter: ${filter}` : ''}${library ? ` from library: ${library}` : ''}`);
|
||||
|
||||
const result = await callKicadScript("get_component_library", {
|
||||
filter,
|
||||
library,
|
||||
limit
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component library: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve component library",
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.components?.length || 0} components from library`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Library List Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"library_list",
|
||||
"kicad://libraries",
|
||||
async (uri) => {
|
||||
logger.debug('Retrieving library list');
|
||||
const result = await callKicadScript("get_library_list", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve library list: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve library list",
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.libraries?.length || 0} libraries`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Library Component Details Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"library_component_details",
|
||||
new ResourceTemplate("kicad://library/component/{componentId}/{library?}", {
|
||||
list: undefined
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { componentId, library } = params;
|
||||
logger.debug(`Retrieving details for component: ${componentId}${library ? ` from library: ${library}` : ''}`);
|
||||
|
||||
const result = await callKicadScript("get_component_details", {
|
||||
componentId,
|
||||
library
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component details: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve details for component ${componentId}`,
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved details for component: ${componentId}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Footprint Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_footprint",
|
||||
new ResourceTemplate("kicad://footprint/{componentId}/{footprint?}", {
|
||||
list: undefined
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { componentId, footprint } = params;
|
||||
logger.debug(`Retrieving footprint for component: ${componentId}${footprint ? ` (${footprint})` : ''}`);
|
||||
|
||||
const result = await callKicadScript("get_component_footprint", {
|
||||
componentId,
|
||||
footprint
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component footprint: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve footprint for component ${componentId}`,
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved footprint for component: ${componentId}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Symbol Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_symbol",
|
||||
new ResourceTemplate("kicad://symbol/{componentId}", {
|
||||
list: undefined
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { componentId } = params;
|
||||
logger.debug(`Retrieving symbol for component: ${componentId}`);
|
||||
|
||||
const result = await callKicadScript("get_component_symbol", {
|
||||
componentId
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component symbol: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve symbol for component ${componentId}`,
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved symbol for component: ${componentId}`);
|
||||
|
||||
// If the result includes SVG data, return it as SVG
|
||||
if (result.svgData) {
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: result.svgData,
|
||||
mimeType: "image/svg+xml"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise return the JSON result
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component 3D Model Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_3d_model",
|
||||
new ResourceTemplate("kicad://3d-model/{componentId}/{footprint?}", {
|
||||
list: undefined
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { componentId, footprint } = params;
|
||||
logger.debug(`Retrieving 3D model for component: ${componentId}${footprint ? ` (${footprint})` : ''}`);
|
||||
|
||||
const result = await callKicadScript("get_component_3d_model", {
|
||||
componentId,
|
||||
footprint
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component 3D model: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve 3D model for component ${componentId}`,
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved 3D model for component: ${componentId}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
logger.info('Library resources registered');
|
||||
}
|
||||
/**
|
||||
* Library resources for KiCAD MCP server
|
||||
*
|
||||
* These resources provide information about KiCAD component libraries
|
||||
* 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";
|
||||
|
||||
// Command function type for KiCAD script calls
|
||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||
|
||||
/**
|
||||
* Register library resources with the MCP server
|
||||
*
|
||||
* @param server MCP server instance
|
||||
* @param callKicadScript Function to call KiCAD script commands
|
||||
*/
|
||||
export function registerLibraryResources(
|
||||
server: McpServer,
|
||||
callKicadScript: CommandFunction,
|
||||
): void {
|
||||
logger.info("Registering library resources");
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Library Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_library",
|
||||
new ResourceTemplate("kicad://components/{filter?}/{library?}", {
|
||||
list: async () => ({
|
||||
resources: [{ uri: "kicad://components", name: "All Components" }],
|
||||
}),
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const filter = params.filter || "";
|
||||
const library = params.library || "";
|
||||
const limit = Number(params.limit) || undefined;
|
||||
|
||||
logger.debug(
|
||||
`Retrieving component library${filter ? ` with filter: ${filter}` : ""}${library ? ` from library: ${library}` : ""}`,
|
||||
);
|
||||
|
||||
const result = await callKicadScript("get_component_library", {
|
||||
filter,
|
||||
library,
|
||||
limit,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component library: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve component library",
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
`Successfully retrieved ${result.components?.length || 0} components from library`,
|
||||
);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Library List Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource("library_list", "kicad://libraries", async (uri) => {
|
||||
logger.debug("Retrieving library list");
|
||||
const result = await callKicadScript("get_library_list", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve library list: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve library list",
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.libraries?.length || 0} libraries`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Library Component Details Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"library_component_details",
|
||||
new ResourceTemplate("kicad://library/component/{componentId}/{library?}", {
|
||||
list: undefined,
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { componentId, library } = params;
|
||||
logger.debug(
|
||||
`Retrieving details for component: ${componentId}${library ? ` from library: ${library}` : ""}`,
|
||||
);
|
||||
|
||||
const result = await callKicadScript("get_component_details", {
|
||||
componentId,
|
||||
library,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component details: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve details for component ${componentId}`,
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved details for component: ${componentId}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Footprint Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_footprint",
|
||||
new ResourceTemplate("kicad://footprint/{componentId}/{footprint?}", {
|
||||
list: undefined,
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { componentId, footprint } = params;
|
||||
logger.debug(
|
||||
`Retrieving footprint for component: ${componentId}${footprint ? ` (${footprint})` : ""}`,
|
||||
);
|
||||
|
||||
const result = await callKicadScript("get_component_footprint", {
|
||||
componentId,
|
||||
footprint,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component footprint: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve footprint for component ${componentId}`,
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved footprint for component: ${componentId}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component Symbol Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_symbol",
|
||||
new ResourceTemplate("kicad://symbol/{componentId}", {
|
||||
list: undefined,
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { componentId } = params;
|
||||
logger.debug(`Retrieving symbol for component: ${componentId}`);
|
||||
|
||||
const result = await callKicadScript("get_component_symbol", {
|
||||
componentId,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component symbol: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve symbol for component ${componentId}`,
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved symbol for component: ${componentId}`);
|
||||
|
||||
// If the result includes SVG data, return it as SVG
|
||||
if (result.svgData) {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: result.svgData,
|
||||
mimeType: "image/svg+xml",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise return the JSON result
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Component 3D Model Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"component_3d_model",
|
||||
new ResourceTemplate("kicad://3d-model/{componentId}/{footprint?}", {
|
||||
list: undefined,
|
||||
}),
|
||||
async (uri, params) => {
|
||||
const { componentId, footprint } = params;
|
||||
logger.debug(
|
||||
`Retrieving 3D model for component: ${componentId}${footprint ? ` (${footprint})` : ""}`,
|
||||
);
|
||||
|
||||
const result = await callKicadScript("get_component_3d_model", {
|
||||
componentId,
|
||||
footprint,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve component 3D model: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: `Failed to retrieve 3D model for component ${componentId}`,
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved 3D model for component: ${componentId}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
logger.info("Library resources registered");
|
||||
}
|
||||
|
||||
@@ -1,260 +1,267 @@
|
||||
/**
|
||||
* Project resources for KiCAD MCP server
|
||||
*
|
||||
* These resources provide information about the KiCAD project
|
||||
* to the LLM, enabling better context-aware assistance.
|
||||
*/
|
||||
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { logger } from '../logger.js';
|
||||
|
||||
// Command function type for KiCAD script calls
|
||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||
|
||||
/**
|
||||
* Register project resources with the MCP server
|
||||
*
|
||||
* @param server MCP server instance
|
||||
* @param callKicadScript Function to call KiCAD script commands
|
||||
*/
|
||||
export function registerProjectResources(server: McpServer, callKicadScript: CommandFunction): void {
|
||||
logger.info('Registering project resources');
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Information Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"project_info",
|
||||
"kicad://project/info",
|
||||
async (uri) => {
|
||||
logger.debug('Retrieving project information');
|
||||
const result = await callKicadScript("get_project_info", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve project information: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve project information",
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug('Successfully retrieved project information');
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Properties Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"project_properties",
|
||||
"kicad://project/properties",
|
||||
async (uri) => {
|
||||
logger.debug('Retrieving project properties');
|
||||
const result = await callKicadScript("get_project_properties", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve project properties: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve project properties",
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug('Successfully retrieved project properties');
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Files Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"project_files",
|
||||
"kicad://project/files",
|
||||
async (uri) => {
|
||||
logger.debug('Retrieving project files');
|
||||
const result = await callKicadScript("get_project_files", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve project files: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve project files",
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.files?.length || 0} project files`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Status Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"project_status",
|
||||
"kicad://project/status",
|
||||
async (uri) => {
|
||||
logger.debug('Retrieving project status');
|
||||
const result = await callKicadScript("get_project_status", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve project status: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve project status",
|
||||
details: result.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug('Successfully retrieved project status');
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Summary Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource(
|
||||
"project_summary",
|
||||
"kicad://project/summary",
|
||||
async (uri) => {
|
||||
logger.debug('Generating project summary');
|
||||
|
||||
// Get project info
|
||||
const infoResult = await callKicadScript("get_project_info", {});
|
||||
if (!infoResult.success) {
|
||||
logger.error(`Failed to retrieve project information: ${infoResult.errorDetails}`);
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to generate project summary",
|
||||
details: infoResult.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
// 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 project summary",
|
||||
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 project summary",
|
||||
details: componentsResult.errorDetails
|
||||
}),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
// Combine all information into a summary
|
||||
const summary = {
|
||||
project: infoResult.project,
|
||||
board: {
|
||||
size: boardResult.size,
|
||||
layers: boardResult.layers?.length || 0,
|
||||
title: boardResult.title
|
||||
},
|
||||
components: {
|
||||
count: componentsResult.components?.length || 0,
|
||||
types: countComponentTypes(componentsResult.components || [])
|
||||
}
|
||||
};
|
||||
|
||||
logger.debug('Successfully generated project summary');
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(summary),
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
logger.info('Project 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;
|
||||
}
|
||||
/**
|
||||
* Project resources for KiCAD MCP server
|
||||
*
|
||||
* These resources provide information about the KiCAD project
|
||||
* to the LLM, enabling better context-aware assistance.
|
||||
*/
|
||||
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { logger } from "../logger.js";
|
||||
|
||||
// Command function type for KiCAD script calls
|
||||
type CommandFunction = (command: string, params: Record<string, unknown>) => Promise<any>;
|
||||
|
||||
/**
|
||||
* Register project resources with the MCP server
|
||||
*
|
||||
* @param server MCP server instance
|
||||
* @param callKicadScript Function to call KiCAD script commands
|
||||
*/
|
||||
export function registerProjectResources(
|
||||
server: McpServer,
|
||||
callKicadScript: CommandFunction,
|
||||
): void {
|
||||
logger.info("Registering project resources");
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Information Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource("project_info", "kicad://project/info", async (uri) => {
|
||||
logger.debug("Retrieving project information");
|
||||
const result = await callKicadScript("get_project_info", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve project information: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve project information",
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug("Successfully retrieved project information");
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Properties Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource("project_properties", "kicad://project/properties", async (uri) => {
|
||||
logger.debug("Retrieving project properties");
|
||||
const result = await callKicadScript("get_project_properties", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve project properties: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve project properties",
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug("Successfully retrieved project properties");
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Files Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource("project_files", "kicad://project/files", async (uri) => {
|
||||
logger.debug("Retrieving project files");
|
||||
const result = await callKicadScript("get_project_files", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve project files: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve project files",
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug(`Successfully retrieved ${result.files?.length || 0} project files`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Status Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource("project_status", "kicad://project/status", async (uri) => {
|
||||
logger.debug("Retrieving project status");
|
||||
const result = await callKicadScript("get_project_status", {});
|
||||
|
||||
if (!result.success) {
|
||||
logger.error(`Failed to retrieve project status: ${result.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to retrieve project status",
|
||||
details: result.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug("Successfully retrieved project status");
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(result),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Project Summary Resource
|
||||
// ------------------------------------------------------
|
||||
server.resource("project_summary", "kicad://project/summary", async (uri) => {
|
||||
logger.debug("Generating project summary");
|
||||
|
||||
// Get project info
|
||||
const infoResult = await callKicadScript("get_project_info", {});
|
||||
if (!infoResult.success) {
|
||||
logger.error(`Failed to retrieve project information: ${infoResult.errorDetails}`);
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify({
|
||||
error: "Failed to generate project summary",
|
||||
details: infoResult.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// 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 project summary",
|
||||
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 project summary",
|
||||
details: componentsResult.errorDetails,
|
||||
}),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// Combine all information into a summary
|
||||
const summary = {
|
||||
project: infoResult.project,
|
||||
board: {
|
||||
size: boardResult.size,
|
||||
layers: boardResult.layers?.length || 0,
|
||||
title: boardResult.title,
|
||||
},
|
||||
components: {
|
||||
count: componentsResult.components?.length || 0,
|
||||
types: countComponentTypes(componentsResult.components || []),
|
||||
},
|
||||
};
|
||||
|
||||
logger.debug("Successfully generated project summary");
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
text: JSON.stringify(summary),
|
||||
mimeType: "application/json",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
logger.info("Project 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user