feat: datasheet tools + fix missing delete_schematic_component
New tools - datasheet: - get_datasheet_url: construct LCSC datasheet PDF URL + product page URL without any API key (URL schema: https://www.lcsc.com/datasheet/<C#>.pdf) - enrich_datasheets: scan .kicad_sch, write LCSC datasheet URL into every symbol that has an LCSC property but an empty Datasheet field; supports dry_run=true for preview; text-based implementation (no skip writes) Implementation: python/commands/datasheet_manager.py New tool - schematic: - delete_schematic_component: remove a placed symbol from a .kicad_sch file by reference designator (e.g. R1, U3) Bug fix - delete_schematic_component (two separate root causes): 1. No MCP tool named delete_schematic_component was registered at all. Any delete-symbol request fell through to the PCB-only delete_component tool which searches pcbnew.BOARD and always returned 'Component not found' for schematic symbols. 2. component_schematic.py::remove_component() still used skip for writes. PR #40 rewrote DynamicSymbolLoader (add path) to avoid skip-induced schematic corruption, but the delete path was not touched by that PR. Fix: _handle_delete_schematic_component in kicad_interface.py uses direct text manipulation with parenthesis-depth tracking (same technique as PR #40), bypassing component_schematic.py entirely. Error message explicitly guides users: 'use delete_component for PCB footprints'. Files changed: - python/commands/datasheet_manager.py (new) - src/tools/datasheet.ts (new) - python/kicad_interface.py: 3 new handlers + dispatch entries - src/tools/schematic.ts: delete_schematic_component tool - src/server.ts: registerDatasheetTools import + call - src/tools/index.ts: export registerDatasheetTools - CHANGELOG.md: document all above
This commit is contained in:
123
src/tools/datasheet.ts
Normal file
123
src/tools/datasheet.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Datasheet tools for KiCAD MCP server
|
||||
*
|
||||
* Enriches KiCAD schematic symbols with LCSC datasheet URLs.
|
||||
* URL schema: https://www.lcsc.com/datasheet/<LCSC#>.pdf (no API key required)
|
||||
*/
|
||||
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { z } from "zod";
|
||||
|
||||
export function registerDatasheetTools(
|
||||
server: McpServer,
|
||||
callKicadScript: Function,
|
||||
) {
|
||||
// ── enrich_datasheets ──────────────────────────────────────────────────────
|
||||
server.tool(
|
||||
"enrich_datasheets",
|
||||
`Fill in missing Datasheet URLs in a KiCAD schematic using LCSC part numbers.
|
||||
|
||||
For every placed symbol that has:
|
||||
• (property "LCSC" "C123456") set
|
||||
• (property "Datasheet" "~") or empty
|
||||
|
||||
Sets the Datasheet field to:
|
||||
https://www.lcsc.com/datasheet/C123456.pdf
|
||||
|
||||
The URL is then visible in KiCAD's footprint browser, symbol properties dialog,
|
||||
and any tool that reads the standard KiCAD Datasheet field.
|
||||
No API key or internet lookup required – the URL is constructed directly.
|
||||
|
||||
Use dry_run=true to preview changes without writing.`,
|
||||
{
|
||||
schematic_path: z
|
||||
.string()
|
||||
.describe("Path to the .kicad_sch file to enrich"),
|
||||
dry_run: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(false)
|
||||
.describe(
|
||||
"If true, show what would be changed without writing to disk (default: false)",
|
||||
),
|
||||
},
|
||||
async (args: { schematic_path: string; dry_run?: boolean }) => {
|
||||
const result = await callKicadScript("enrich_datasheets", args);
|
||||
if (result.success) {
|
||||
const lines: string[] = [];
|
||||
|
||||
if (args.dry_run) {
|
||||
lines.push(`[DRY RUN] Schematic: ${result.schematic}\n`);
|
||||
} else {
|
||||
lines.push(`Schematic: ${result.schematic}\n`);
|
||||
}
|
||||
|
||||
lines.push(`✓ Updated: ${result.updated}`);
|
||||
lines.push(` Already set: ${result.already_set}`);
|
||||
lines.push(` No LCSC number: ${result.no_lcsc}`);
|
||||
lines.push(` No field: ${result.no_datasheet_field}`);
|
||||
|
||||
if (result.details && result.details.length > 0) {
|
||||
lines.push("\nComponents updated:");
|
||||
for (const d of result.details) {
|
||||
lines.push(` ${d.reference.padEnd(6)} ${d.lcsc.padEnd(12)} → ${d.url}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.updated === 0 && !args.dry_run) {
|
||||
lines.push(
|
||||
"\nNo changes needed – all LCSC components already have a Datasheet URL.",
|
||||
);
|
||||
}
|
||||
|
||||
return { content: [{ type: "text", text: lines.join("\n") }] };
|
||||
}
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `Failed to enrich datasheets: ${result.message || "Unknown error"}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// ── get_datasheet_url ──────────────────────────────────────────────────────
|
||||
server.tool(
|
||||
"get_datasheet_url",
|
||||
`Get the LCSC datasheet URL for a component by LCSC number.
|
||||
|
||||
Returns the direct PDF URL and product page URL.
|
||||
No network request – URL is constructed from the LCSC number alone.
|
||||
|
||||
Example: get_datasheet_url("C179739")
|
||||
→ https://www.lcsc.com/datasheet/C179739.pdf`,
|
||||
{
|
||||
lcsc: z
|
||||
.string()
|
||||
.describe(
|
||||
'LCSC part number, with or without "C" prefix (e.g. "C179739" or "179739")',
|
||||
),
|
||||
},
|
||||
async (args: { lcsc: string }) => {
|
||||
const result = await callKicadScript("get_datasheet_url", { lcsc: args.lcsc });
|
||||
if (result.success) {
|
||||
const lines = [
|
||||
`LCSC: ${result.lcsc}`,
|
||||
`Datasheet PDF: ${result.datasheet_url}`,
|
||||
`Product page: ${result.product_url}`,
|
||||
];
|
||||
return { content: [{ type: "text", text: lines.join("\n") }] };
|
||||
}
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `Invalid LCSC number: ${args.lcsc}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user