diff --git a/README.md b/README.md index bd70606..7a8be80 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,16 @@ KiCAD MCP is a Model Context Protocol (MCP) implementation that enables Large Language Models (LLMs) like Claude to directly interact with KiCAD for printed circuit board design. It creates a standardized communication bridge between AI assistants and the KiCAD PCB design software, allowing for natural language control of advanced PCB design operations. +## What is MCP? + +The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard from Anthropic that allows AI assistants like Claude to securely connect to external tools and data sources. Think of it as a universal adapter that lets Claude interact with your local software - in this case, KiCAD. + +**With this MCP server, you can:** +- Design PCBs by talking to Claude in natural language +- Automate complex KiCAD operations through AI assistance +- Get real-time feedback as Claude creates and modifies your boards +- Leverage AI to handle tedious PCB design tasks + ## NEW FEATURES ### Schematic Generation @@ -96,16 +106,53 @@ This enables a natural language-driven PCB design workflow where complex operati - **Python KiCAD Interface**: Handles actual KiCAD operations via pcbnew Python API and kicad-skip library with comprehensive error handling - **Modular Design**: Organizes functionality by domains (project, schematic, board, component, routing) for maintainability and extensibility -## System Requirements +## Prerequisites - READ THIS FIRST! -- **KiCAD 9.0 or higher** (must be fully installed with Python module) -- **Node.js v18 or higher** and npm -- **Python 3.10 or higher** with pip -- **Cline** (VSCode extension) or another MCP-compatible client -- **Operating System**: - - **Linux** (Ubuntu 22.04+, Fedora, Arch) - Primary platform - - **Windows 10/11** - Fully supported - - **macOS** - Experimental (untested) +Before installing this MCP server, you **MUST** have: + +### 1. KiCAD 9.0 or Higher (REQUIRED!) + +**This is the most critical requirement.** Without KiCAD properly installed with its Python module, this MCP server will not work. + +- **Download:** [kicad.org/download](https://www.kicad.org/download/) +- **Verify Python module:** After installing, run: + ```bash + python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())" + ``` + If this fails, your KiCAD installation is incomplete. + +### 2. Python 3.10 or Higher + +**Required Python packages:** +``` +kicad-skip>=0.1.0 # Schematic manipulation +Pillow>=9.0.0 # Image processing for board rendering +cairosvg>=2.7.0 # SVG rendering +colorlog>=6.7.0 # Colored logging +pydantic>=2.5.0 # Data validation +requests>=2.31.0 # HTTP requests (for future API features) +python-dotenv>=1.0.0 # Environment management +``` + +These will be installed automatically via `pip install -r requirements.txt` + +### 3. Node.js v18 or Higher + +- **Download:** [nodejs.org](https://nodejs.org/) +- **Verify:** Run `node --version` and `npm --version` + +### 4. An MCP-Compatible Client + +Choose one: +- **[Claude Desktop](https://claude.ai/download)** - Official Anthropic desktop app +- **[Claude Code](https://docs.claude.com/claude-code)** - Official Anthropic CLI tool +- **[Cline](https://github.com/cline/cline)** - Popular VSCode extension + +### 5. Operating System + +- **Linux** (Ubuntu 22.04+, Fedora, Arch) - Primary platform, fully tested +- **Windows 10/11** - Fully supported +- **macOS** - Experimental (untested, please report issues!) ## Installation @@ -141,8 +188,8 @@ npm --version ```bash # Clone repository -git clone https://github.com/yourusername/kicad-mcp-server.git -cd kicad-mcp-server +git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git +cd KiCAD-MCP-Server # Install Node.js dependencies npm install @@ -168,7 +215,7 @@ npm run build "mcpServers": { "kicad": { "command": "node", - "args": ["/home/YOUR_USERNAME/kicad-mcp-server/dist/index.js"], + "args": ["/home/YOUR_USERNAME/KiCAD-MCP-Server/dist/index.js"], "env": { "NODE_ENV": "production", "PYTHONPATH": "/usr/lib/kicad/lib/python3/dist-packages", @@ -221,8 +268,8 @@ pytest tests/ ```powershell # Clone repository -git clone https://github.com/yourusername/kicad-mcp-server.git -cd kicad-mcp-server +git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git +cd KiCAD-MCP-Server # Install dependencies npm install @@ -246,7 +293,7 @@ npm run build "mcpServers": { "kicad": { "command": "C:\\Program Files\\nodejs\\node.exe", - "args": ["C:\\path\\to\\kicad-mcp-server\\dist\\index.js"], + "args": ["C:\\Users\\YOUR_USERNAME\\KiCAD-MCP-Server\\dist\\index.js"], "env": { "PYTHONPATH": "C:\\Program Files\\KiCad\\9.0\\lib\\python3\\dist-packages" } @@ -281,8 +328,8 @@ npm --version ### Step 3: Clone and Build ```bash -git clone https://github.com/yourusername/kicad-mcp-server.git -cd kicad-mcp-server +git clone https://github.com/mixelpixx/KiCAD-MCP-Server.git +cd KiCAD-MCP-Server npm install pip3 install -r requirements.txt npm run build @@ -297,7 +344,7 @@ Edit `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-d "mcpServers": { "kicad": { "command": "node", - "args": ["/Users/YOUR_USERNAME/kicad-mcp-server/dist/index.js"], + "args": ["/Users/YOUR_USERNAME/KiCAD-MCP-Server/dist/index.js"], "env": { "PYTHONPATH": "/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages" } diff --git a/test/TestProject.kicad_pcb b/test/TestProject.kicad_pcb deleted file mode 100644 index 40bc2df..0000000 --- a/test/TestProject.kicad_pcb +++ /dev/null @@ -1,86 +0,0 @@ -(kicad_pcb - (version 20241229) - (generator "pcbnew") - (generator_version "9.0") - (general - (thickness 1.6) - (legacy_teardrops no) - ) - (paper "A4") - (title_block - (title "TestProject") - (date "2025-04-26") - ) - (layers - (0 "F.Cu" signal) - (2 "B.Cu" signal) - (9 "F.Adhes" user "F.Adhesive") - (11 "B.Adhes" user "B.Adhesive") - (13 "F.Paste" user) - (15 "B.Paste" user) - (5 "F.SilkS" user "F.Silkscreen") - (7 "B.SilkS" user "B.Silkscreen") - (1 "F.Mask" user) - (3 "B.Mask" user) - (17 "Dwgs.User" user "User.Drawings") - (19 "Cmts.User" user "User.Comments") - (21 "Eco1.User" user "User.Eco1") - (23 "Eco2.User" user "User.Eco2") - (25 "Edge.Cuts" user) - (27 "Margin" user) - (31 "F.CrtYd" user "F.Courtyard") - (29 "B.CrtYd" user "B.Courtyard") - (35 "F.Fab" user) - (33 "B.Fab" user) - (39 "User.1" user) - (41 "User.2" user) - (43 "User.3" user) - (45 "User.4" user) - ) - (setup - (pad_to_mask_clearance 0) - (allow_soldermask_bridges_in_footprints no) - (tenting front back) - (pcbplotparams - (layerselection 0x00000000_00000000_55555555_5755f5ff) - (plot_on_all_layers_selection 0x00000000_00000000_00000000_00000000) - (disableapertmacros no) - (usegerberextensions no) - (usegerberattributes yes) - (usegerberadvancedattributes yes) - (creategerberjobfile yes) - (dashed_line_dash_ratio 12.000000) - (dashed_line_gap_ratio 3.000000) - (svgprecision 4) - (plotframeref no) - (mode 1) - (useauxorigin no) - (hpglpennumber 1) - (hpglpenspeed 20) - (hpglpendiameter 15.000000) - (pdf_front_fp_property_popups yes) - (pdf_back_fp_property_popups yes) - (pdf_metadata yes) - (pdf_single_document no) - (dxfpolygonmode yes) - (dxfimperialunits yes) - (dxfusepcbnewfont yes) - (psnegative no) - (psa4output no) - (plot_black_and_white yes) - (sketchpadsonfab no) - (plotpadnumbers no) - (hidednponfab no) - (sketchdnponfab yes) - (crossoutdnponfab yes) - (subtractmaskfromsilk no) - (outputformat 1) - (mirror no) - (drillshape 1) - (scaleselection 1) - (outputdirectory "") - ) - ) - (net 0 "") - (embedded_fonts no) -) diff --git a/test/TestProject.kicad_pro b/test/TestProject.kicad_pro deleted file mode 100644 index a7b4074..0000000 --- a/test/TestProject.kicad_pro +++ /dev/null @@ -1,5 +0,0 @@ -{ - "board": { - "filename": "TestProject.kicad_pcb" - } -} diff --git a/test/check_skip.py b/test/check_skip.py deleted file mode 100644 index d67129d..0000000 --- a/test/check_skip.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple script to check if the skip module is available -""" - -import sys -import traceback - -print("Python executable:", sys.executable) -print("Python version:", sys.version) - -try: - print("Attempting to import skip module...") - import skip - print("Successfully imported skip module!") - print("Skip module version:", getattr(skip, "__version__", "Unknown")) - print("Skip module path:", skip.__file__) - - # Check if Schematic class is available - print("\nChecking for Schematic class...") - if hasattr(skip, "Schematic"): - print("Schematic class is available!") - - # Create a schematic object - print("Creating schematic object...") - sch = skip.Schematic() - print("Successfully created schematic object!") - - # Check for methods and attributes we use - print("\nChecking schematic methods/attributes:") - print("- add_symbol method:", hasattr(sch, "add_symbol")) - print("- add_wire method:", hasattr(sch, "add_wire")) - print("- save method:", hasattr(sch, "save")) - print("- version attribute:", hasattr(sch, "version")) - - else: - print("ERROR: Schematic class is NOT available in the skip module!") - - # List all available classes/functions in the skip module - print("\nAvailable members in skip module:") - for name in dir(skip): - if not name.startswith("_"): # Skip private/internal items - print(f"- {name}") - -except ImportError as e: - print(f"ERROR: Failed to import skip module: {e}") - traceback.print_exc() -except Exception as e: - print(f"ERROR: An unexpected error occurred: {e}") - traceback.print_exc() diff --git a/test/example_skip_usage.py b/test/example_skip_usage.py deleted file mode 100644 index 90e9dc0..0000000 --- a/test/example_skip_usage.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python3 -""" -Example script to inspect and document kicad-skip library capabilities -""" - -import sys -import inspect -import os -import traceback - -def main(): - """Examine the kicad-skip library functionality""" - print("=== Examining kicad-skip library ===") - - try: - # Import the module - print("Importing skip module...") - import skip - print(f"Skip module path: {skip.__file__}") - - # Display module contents - print("\nSkip module contents:") - for item_name in dir(skip): - if not item_name.startswith('_'): - try: - item = getattr(skip, item_name) - if inspect.isclass(item): - print(f" Class: {item_name}") - # List methods of the class - for method_name in dir(item): - if not method_name.startswith('_'): - method = getattr(item, method_name) - if inspect.ismethod(method) or inspect.isfunction(method): - print(f" - Method: {method_name}") - elif inspect.isfunction(item): - print(f" Function: {item_name}") - else: - print(f" Other: {item_name} (type: {type(item).__name__})") - except Exception as e: - print(f" Error examining {item_name}: {e}") - - # Test Schematic class specifically - print("\nExamining Schematic class:") - if hasattr(skip, 'Schematic'): - schematic_class = skip.Schematic - print(f"Schematic class: {schematic_class}") - - # Check initialization parameters - try: - sig = inspect.signature(schematic_class.__init__) - print(f"Schematic.__init__ signature: {sig}") - - # List required parameters - required_params = [ - name for name, param in sig.parameters.items() - if param.default == inspect.Parameter.empty and name != 'self' - ] - print(f"Required parameters: {required_params}") - - # Display initialization docstring - print(f"__init__ docstring: {schematic_class.__init__.__doc__}") - except Exception as e: - print(f"Error examining Schematic.__init__: {e}") - - # Create a simple test file - test_dir = os.path.dirname(__file__) - test_file = os.path.join(test_dir, 'test_example.kicad_sch') - - with open(test_file, 'w') as f: - f.write("(kicad_sch (version 20230121) (generator \"Test Example\"))\n") - - # Try loading the test file - print(f"\nLoading test file {test_file}") - try: - sch = skip.Schematic(test_file) - print("Successfully created Schematic object") - - # Examine the object's attributes and methods - print("\nSchematic object attributes:") - for attr_name in dir(sch): - if not attr_name.startswith('_'): - try: - attr = getattr(sch, attr_name) - if callable(attr): - print(f" Method: {attr_name}") - else: - print(f" Attribute: {attr_name} = {attr}") - except Exception as e: - print(f" Error examining {attr_name}: {e}") - - # Check for io-related methods - print("\nLooking for IO-related methods:") - for method_name in ['save', 'write', 'to_file', 'export', 'dump']: - print(f" Has '{method_name}' method: {hasattr(sch, method_name)}") - - # Examine the representation of the object - print(f"\nStr representation: {str(sch)}") - print(f"Repr representation: {repr(sch)}") - - # Clean up - os.remove(test_file) - except Exception as e: - print(f"Error testing Schematic: {e}") - traceback.print_exc() - - # Clean up even on error - if os.path.exists(test_file): - os.remove(test_file) - else: - print("Schematic class not found in skip module") - - except ImportError as e: - print(f"Failed to import skip module: {e}") - except Exception as e: - print(f"An unexpected error occurred: {e}") - traceback.print_exc() - - print("\n=== Examination completed ===") - -if __name__ == "__main__": - main() diff --git a/test/manual_test_schematic.py b/test/manual_test_schematic.py deleted file mode 100644 index 5437391..0000000 --- a/test/manual_test_schematic.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 -""" -Manual test script for the schematic functionality -""" - -import sys -import os - -# Add the parent directory to the module search path -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - -# Import our schematic modules -from python.commands.schematic import SchematicManager -from python.commands.component_schematic import ComponentManager -from python.commands.connection_schematic import ConnectionManager - -def main(): - """Run a basic test of schematic functionality""" - print("=== Starting manual schematic test ===") - - # Set up test output directory - test_dir = os.path.join(os.path.dirname(__file__), 'schematic_test_output') - if not os.path.exists(test_dir): - os.makedirs(test_dir) - - # 1. Create a new schematic - schematic_name = "TestCircuitManual" - schematic_path = os.path.join(test_dir, f"{schematic_name}.kicad_sch") - print(f"Creating schematic: {schematic_name}") - - schematic = SchematicManager.create_schematic(schematic_name) - - # 2. Add components to the schematic - print("Adding components to schematic...") - - # Add resistor R1 - r1_def = { - "type": "R", - "reference": "R1", - "value": "10k", - "library": "Device", - "x": 100, - "y": 100 - } - r1 = ComponentManager.add_component(schematic, r1_def) - - # Add resistor R2 - r2_def = { - "type": "R", - "reference": "R2", - "value": "4.7k", - "library": "Device", - "x": 100, - "y": 200 - } - r2 = ComponentManager.add_component(schematic, r2_def) - - # Add capacitor C1 - c1_def = { - "type": "C", - "reference": "C1", - "value": "0.1uF", - "library": "Device", - "x": 200, - "y": 150 - } - c1 = ComponentManager.add_component(schematic, c1_def) - - # 3. Add wires to connect components - print("Adding wires to connect components...") - - # Connect R1 to R2 - wire1 = ConnectionManager.add_wire(schematic, [150, 100], [150, 200]) - - # Connect R2 to C1 - wire2 = ConnectionManager.add_wire(schematic, [150, 200], [200, 200]) - - # Connect C1 to R1 - wire3 = ConnectionManager.add_wire(schematic, [200, 100], [150, 100]) - - # 4. Save the schematic - print(f"Saving schematic to: {schematic_path}") - success = SchematicManager.save_schematic(schematic, schematic_path) - - if success: - print(f"Successfully saved schematic to: {schematic_path}") - else: - print("Failed to save schematic") - - print("=== Manual schematic test completed ===") - -if __name__ == "__main__": - main() diff --git a/test/skip_test.py b/test/skip_test.py deleted file mode 100644 index 3df8518..0000000 --- a/test/skip_test.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple test script for the kicad-skip library functionality -This test doesn't depend on KiCAD's Python modules like pcbnew. -""" - -import sys -import os -import traceback - -def main(): - """Test basic kicad-skip functionality""" - print("=== Testing kicad-skip schematic functionality ===") - - # Set up test output directory - test_dir = os.path.join(os.path.dirname(__file__), 'schematic_test_output') - if not os.path.exists(test_dir): - os.makedirs(test_dir) - - print("Test directory:", test_dir) - - try: - # Import skip module - print("Importing skip module...") - from skip import Schematic - print("Successfully imported skip module") - - # Create a new schematic - print("Creating new schematic...") - sch = Schematic() - sch.version = "20230121" - sch.generator = "KiCAD-MCP-Server-Test" - print("Created schematic object with version:", sch.version) - - # Add resistor component - print("Adding resistor component...") - resistor = sch.add_symbol( - lib="Device", - name="R", - reference="R1", - at=[100, 100], - unit=1 - ) - resistor.property.Value.value = "10k" - print("Added resistor:", resistor.reference, resistor.property.Value.value) - - # Add capacitor component - print("Adding capacitor component...") - capacitor = sch.add_symbol( - lib="Device", - name="C", - reference="C1", - at=[200, 100], - unit=1 - ) - capacitor.property.Value.value = "0.1uF" - print("Added capacitor:", capacitor.reference, capacitor.property.Value.value) - - # Add wire connection - print("Adding wire connection...") - wire = sch.add_wire(start=[100, 150], end=[200, 150]) - print("Added wire from", wire.start, "to", wire.end) - - # Save the schematic - schematic_path = os.path.join(test_dir, "skip_test.kicad_sch") - print(f"Saving schematic to: {schematic_path}") - sch.save(schematic_path) - print(f"Schematic saved to: {schematic_path}") - - # Verify the file exists - if os.path.exists(schematic_path): - print(f"SUCCESS: Schematic file created at: {schematic_path}") - print(f"File size: {os.path.getsize(schematic_path)} bytes") - else: - print(f"ERROR: Failed to create schematic file at: {schematic_path}") - - except ImportError as e: - print(f"ERROR: Failed to import required modules: {e}") - traceback.print_exc() - except Exception as e: - print(f"ERROR: An unexpected error occurred: {e}") - traceback.print_exc() - - print("=== Test completed ===") - -if __name__ == "__main__": - main() diff --git a/test/test_schematic.js b/test/test_schematic.js deleted file mode 100644 index c6eb757..0000000 --- a/test/test_schematic.js +++ /dev/null @@ -1,230 +0,0 @@ -import { spawn } from 'child_process'; -import path from 'path'; -import fs from 'fs'; -import { fileURLToPath } from 'url'; - -// Get current file directory (ESM equivalent of __dirname) -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -/** - * Test script for the schematic generation functionality - * - * This script tests the KiCAD MCP server's schematic generation capabilities by: - * 1. Creating a new schematic - * 2. Adding components (resistors, capacitors) - * 3. Adding connections between them - * 4. Exporting the schematic to PDF - */ - -// Directory for test outputs -const TEST_OUTPUT_DIR = path.join(__dirname, 'schematic_test_output'); -if (!fs.existsSync(TEST_OUTPUT_DIR)) { - fs.mkdirSync(TEST_OUTPUT_DIR, { recursive: true }); -} - -// Function to send a command to the KiCAD MCP server -function sendCommand(serverProcess, command, params) { - return new Promise((resolve, reject) => { - // Create request object - const request = { - command, - params - }; - - // Convert to JSON and add newline - const requestStr = JSON.stringify(request) + '\n'; - - // Write to stdin of server process - console.log(`Sending request to server: ${requestStr}`); - serverProcess.stdin.write(requestStr); - -// Set up response handler - let responseData = ''; - const responseHandler = (data) => { - const chunk = data.toString(); - console.log(`Received data: ${chunk}`); - responseData += chunk; - try { - // Try to parse as JSON - const response = JSON.parse(responseData); - // Got a complete response - console.log(`Parsed complete response: ${JSON.stringify(response)}`); - serverProcess.stdout.removeListener('data', responseHandler); - resolve(response); - } catch (e) { - // Not complete JSON yet, keep collecting - console.log(`JSON parsing failed, continuing to collect data: ${e.message}`); - } - }; - - // Set a timeout to prevent hanging indefinitely - const timeoutId = setTimeout(() => { - console.log("Command timeout after 10 seconds"); - serverProcess.stdout.removeListener('data', responseHandler); - resolve({ - success: false, - message: "Timeout waiting for response from server" - }); - }, 10000); // 10 second timeout - - // Listen for response - serverProcess.stdout.on('data', responseHandler); - - // Handle errors - serverProcess.stderr.on('data', (data) => { - console.error(`Server stderr: ${data.toString()}`); - }); - }); -} - -async function runTest() { - console.log('\n=== TESTING SCHEMATIC GENERATION ===\n'); - - // Start the KiCAD MCP server - console.log('Starting KiCAD MCP server...'); - // Use shell: true to ensure proper command execution in Windows - const serverProcess = spawn('node', ['dist/kicad-server.js'], { - stdio: ['pipe', 'pipe', 'pipe'], - shell: true - }); - - // Log server startup messages - serverProcess.stderr.on('data', (data) => { - console.log(`Server startup: ${data.toString()}`); - }); - - // Give server time to start - console.log('Waiting for server to start...'); - await new Promise(resolve => setTimeout(resolve, 5000)); - console.log('Server should be ready now'); - - try { - // 1. Create a new schematic - const schematicName = 'TestCircuit'; - const schematicPath = path.join(TEST_OUTPUT_DIR, `${schematicName}.kicad_sch`); - console.log(`Creating schematic: ${schematicName}...`); - - const createResult = await sendCommand(serverProcess, 'create_schematic', { - projectName: schematicName, - path: TEST_OUTPUT_DIR, - metadata: { - description: 'Test circuit schematic', - author: 'KiCAD MCP Test' - } - }); - - console.log('Create schematic result:', createResult); - - if (!createResult.success) { - throw new Error(`Failed to create schematic: ${createResult.message}`); - } - - // 2. Add components: resistors, capacitor, and power/ground connections - console.log('Adding components to schematic...'); - - // Add resistor R1 - const addR1Result = await sendCommand(serverProcess, 'add_schematic_component', { - schematicPath: schematicPath, - component: { - type: 'R', - reference: 'R1', - value: '10k', - library: 'Device', - x: 100, - y: 100 - } - }); - - console.log('Add R1 result:', addR1Result); - - // Add resistor R2 - const addR2Result = await sendCommand(serverProcess, 'add_schematic_component', { - schematicPath: schematicPath, - component: { - type: 'R', - reference: 'R2', - value: '4.7k', - library: 'Device', - x: 100, - y: 200 - } - }); - - console.log('Add R2 result:', addR2Result); - - // Add capacitor C1 - const addC1Result = await sendCommand(serverProcess, 'add_schematic_component', { - schematicPath: schematicPath, - component: { - type: 'C', - reference: 'C1', - value: '0.1uF', - library: 'Device', - x: 200, - y: 150 - } - }); - - console.log('Add C1 result:', addC1Result); - - // 3. Add wires to connect components - console.log('Adding wires to connect components...'); - - // Connect R1 to R2 - const addWire1Result = await sendCommand(serverProcess, 'add_schematic_wire', { - schematicPath: schematicPath, - startPoint: [150, 100], - endPoint: [150, 200] - }); - - console.log('Add wire 1 result:', addWire1Result); - - // Connect R2 to C1 - const addWire2Result = await sendCommand(serverProcess, 'add_schematic_wire', { - schematicPath: schematicPath, - startPoint: [150, 200], - endPoint: [200, 200] - }); - - console.log('Add wire 2 result:', addWire2Result); - - // Connect C1 to R1 - const addWire3Result = await sendCommand(serverProcess, 'add_schematic_wire', { - schematicPath: schematicPath, - startPoint: [200, 100], - endPoint: [150, 100] - }); - - console.log('Add wire 3 result:', addWire3Result); - - // 4. Export to PDF - console.log('Exporting schematic to PDF...'); - const pdfPath = path.join(TEST_OUTPUT_DIR, `${schematicName}.pdf`); - - const exportResult = await sendCommand(serverProcess, 'export_schematic_pdf', { - schematicPath: schematicPath, - outputPath: pdfPath - }); - - console.log('Export PDF result:', exportResult); - - if (exportResult.success) { - console.log(`PDF successfully created at: ${pdfPath}`); - } else { - console.log(`Failed to create PDF: ${exportResult.message}`); - } - - console.log('\n=== SCHEMATIC GENERATION TEST COMPLETED ===\n'); - console.log(`Schematic file: ${schematicPath}`); - console.log(`PDF file: ${pdfPath}`); - } catch (error) { - console.error('Test error:', error); - } finally { - // Kill the server process - serverProcess.kill(); - } -} - -// Run the test -runTest().catch(console.error); diff --git a/test/test_schematic_debug.py b/test/test_schematic_debug.py deleted file mode 100644 index 223344d..0000000 --- a/test/test_schematic_debug.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python3 -""" -Debug test script for the schematic manager implementation -""" - -import sys -import os -import traceback - -# Add the parent directory to the module search path -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - -def main(): - """Test the SchematicManager functions with detailed debug output""" - print("=== DEBUGGING SchematicManager functionality ===") - - # Set up test output directory - test_dir = os.path.join(os.path.dirname(__file__), 'schematic_test_output') - if not os.path.exists(test_dir): - os.makedirs(test_dir) - - print("Test directory:", test_dir) - - try: - # Import directly from skip for comparison - print("Importing skip module...") - from skip import Schematic - print("Successfully imported skip module") - - # Create a template file directly - template_path = os.path.join(test_dir, "debug_template.kicad_sch") - print(f"Creating template file at: {template_path}") - with open(template_path, 'w') as f: - f.write("(kicad_sch (version 20230121) (generator \"KiCAD-MCP-Server-Debug\"))\n") - - print(f"Template file created, size: {os.path.getsize(template_path)} bytes") - - # Load the template with skip directly - print("Loading template with skip.Schematic...") - try: - sch = Schematic(template_path) - print("Successfully loaded template") - - # Save directly - output_path = os.path.join(test_dir, "direct_save.kicad_sch") - print(f"Saving with skip.Schematic.save() to: {output_path}") - sch.save(output_path) - - if os.path.exists(output_path): - print(f"Direct save successful, file size: {os.path.getsize(output_path)} bytes") - else: - print("Direct save failed, no file created") - except Exception as e: - print(f"Error using skip directly: {e}") - traceback.print_exc() - - print("\n--- Now testing SchematicManager ---\n") - - # Import our SchematicManager - print("Importing SchematicManager...") - from python.commands.schematic import SchematicManager - print("Successfully imported SchematicManager") - - # Create a new schematic - print("\nCreating new schematic with SchematicManager...") - schematic_name = "TestDebugManager" - metadata = { - "description": "Debug test schematic", - "author": "Debug script" - } - - try: - sch = SchematicManager.create_schematic(schematic_name, metadata) - print("Successfully created schematic object") - - # Print schematic properties - print("Schematic properties:") - print(f" Version: {sch.version}") - print(f" Generator: {sch.generator}") - - # Save the schematic - schematic_path = os.path.join(test_dir, f"{schematic_name}.kicad_sch") - print(f"\nSaving schematic to: {schematic_path}") - - try: - success = SchematicManager.save_schematic(sch, schematic_path) - - if success: - print(f"Successfully saved schematic to: {schematic_path}") - print(f"File size: {os.path.getsize(schematic_path)} bytes") - else: - print("SchematicManager.save_schematic returned False") - except Exception as e: - print(f"Error in save_schematic: {e}") - traceback.print_exc() - - except Exception as e: - print(f"Error in create_schematic: {e}") - traceback.print_exc() - - except ImportError as e: - print(f"ERROR: Failed to import required modules: {e}") - traceback.print_exc() - except Exception as e: - print(f"ERROR: An unexpected error occurred: {e}") - traceback.print_exc() - - print("\n=== Debug test completed ===") - -if __name__ == "__main__": - main() diff --git a/test/test_schematic_manager.py b/test/test_schematic_manager.py deleted file mode 100644 index 8d1356f..0000000 --- a/test/test_schematic_manager.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 -""" -Test script for the schematic manager implementation using KiCAD python -""" - -import sys -import os -import traceback - -# Add the parent directory to the module search path -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - -def main(): - """Test the SchematicManager functions""" - print("=== Testing SchematicManager functionality ===") - - try: - # Set up test output directory - test_dir = os.path.join(os.path.dirname(__file__), 'schematic_test_output') - if not os.path.exists(test_dir): - os.makedirs(test_dir) - - print("Test directory:", test_dir) - - # Import our SchematicManager - print("Importing SchematicManager...") - from python.commands.schematic import SchematicManager - print("Successfully imported SchematicManager") - - # Create a new schematic - print("\nCreating new schematic...") - schematic_name = "TestSchemManager" - metadata = { - "description": "Test schematic", - "author": "Test script" - } - sch = SchematicManager.create_schematic(schematic_name, metadata) - print("Successfully created schematic object") - - # Save the schematic - schematic_path = os.path.join(test_dir, f"{schematic_name}.kicad_sch") - print(f"\nSaving schematic to: {schematic_path}") - success = SchematicManager.save_schematic(sch, schematic_path) - - if success: - print(f"Successfully saved schematic to: {schematic_path}") - else: - print("Failed to save schematic") - return - - # Load the schematic - print("\nLoading schematic from file...") - loaded_sch = SchematicManager.load_schematic(schematic_path) - - if loaded_sch: - print("Successfully loaded schematic") - - # Get metadata - print("\nGetting schematic metadata...") - metadata = SchematicManager.get_schematic_metadata(loaded_sch) - print(f"Metadata: {metadata}") - else: - print("Failed to load schematic") - - # Verify the file exists - if os.path.exists(schematic_path): - print(f"\nSCHEMATIC TEST SUCCESSFUL: File created at: {schematic_path}") - print(f"File size: {os.path.getsize(schematic_path)} bytes") - else: - print(f"\nERROR: File not found at: {schematic_path}") - - except ImportError as e: - print(f"ERROR: Failed to import required modules: {e}") - traceback.print_exc() - except Exception as e: - print(f"ERROR: An unexpected error occurred: {e}") - traceback.print_exc() - - print("\n=== Test completed ===") - -if __name__ == "__main__": - main()