kicad-sch-api 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kicad-sch-api might be problematic. Click here for more details.
- kicad_sch_api/cli.py +345 -0
- kicad_sch_api/discovery/__init__.py +10 -0
- kicad_sch_api/discovery/search_index.py +421 -0
- kicad_sch_api/mcp/__init__.py +7 -0
- kicad_sch_api/mcp/server.py +1509 -0
- kicad_sch_api-0.1.2.dist-info/METADATA +326 -0
- {kicad_sch_api-0.1.1.dist-info → kicad_sch_api-0.1.2.dist-info}/RECORD +11 -6
- {kicad_sch_api-0.1.1.dist-info → kicad_sch_api-0.1.2.dist-info}/entry_points.txt +1 -0
- kicad_sch_api-0.1.1.dist-info/METADATA +0 -207
- {kicad_sch_api-0.1.1.dist-info → kicad_sch_api-0.1.2.dist-info}/WHEEL +0 -0
- {kicad_sch_api-0.1.1.dist-info → kicad_sch_api-0.1.2.dist-info}/licenses/LICENSE +0 -0
- {kicad_sch_api-0.1.1.dist-info → kicad_sch_api-0.1.2.dist-info}/top_level.txt +0 -0
kicad_sch_api/cli.py
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
KiCAD Schematic API - Command Line Interface
|
|
4
|
+
|
|
5
|
+
Provides helpful commands for setup, testing, and usage of the MCP server.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import subprocess
|
|
12
|
+
import argparse
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, Any
|
|
15
|
+
|
|
16
|
+
def get_claude_config_path() -> Path:
|
|
17
|
+
"""Get the Claude Code configuration file path for current platform."""
|
|
18
|
+
if sys.platform == "darwin":
|
|
19
|
+
return Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
|
|
20
|
+
elif sys.platform == "win32":
|
|
21
|
+
return Path(os.environ["APPDATA"]) / "Claude/claude_desktop_config.json"
|
|
22
|
+
else: # Linux and others
|
|
23
|
+
return Path.home() / ".config/Claude/claude_desktop_config.json"
|
|
24
|
+
|
|
25
|
+
def setup_claude_code() -> bool:
|
|
26
|
+
"""Automatically configure Claude Code MCP settings."""
|
|
27
|
+
print("🔧 Setting up Claude Code MCP configuration...")
|
|
28
|
+
|
|
29
|
+
config_path = get_claude_config_path()
|
|
30
|
+
|
|
31
|
+
# Create directory if it doesn't exist
|
|
32
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
|
|
34
|
+
# Backup existing config
|
|
35
|
+
if config_path.exists():
|
|
36
|
+
backup_path = config_path.with_suffix(f".backup.{config_path.stat().st_mtime:.0f}.json")
|
|
37
|
+
backup_path.write_text(config_path.read_text())
|
|
38
|
+
print(f"📁 Backed up existing config to: {backup_path}")
|
|
39
|
+
|
|
40
|
+
# Determine MCP command path
|
|
41
|
+
mcp_command = os.environ.get('FOUND_MCP_PATH', 'kicad-sch-mcp')
|
|
42
|
+
|
|
43
|
+
# If still using default, try to find the actual path
|
|
44
|
+
if mcp_command == 'kicad-sch-mcp':
|
|
45
|
+
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
46
|
+
possible_paths = [
|
|
47
|
+
f"/Library/Frameworks/Python.framework/Versions/{python_version}/bin/kicad-sch-mcp",
|
|
48
|
+
os.path.expanduser(f"~/Library/Python/{python_version}/bin/kicad-sch-mcp"),
|
|
49
|
+
os.path.expanduser("~/.local/bin/kicad-sch-mcp"),
|
|
50
|
+
"/usr/local/bin/kicad-sch-mcp"
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
for path_to_try in possible_paths:
|
|
54
|
+
if os.path.exists(path_to_try) and os.access(path_to_try, os.X_OK):
|
|
55
|
+
mcp_command = path_to_try
|
|
56
|
+
print(f"📍 Using MCP command at: {mcp_command}")
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
# Create new configuration
|
|
60
|
+
config = {
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"kicad-sch-api": {
|
|
63
|
+
"command": mcp_command,
|
|
64
|
+
"args": [],
|
|
65
|
+
"env": {}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Write configuration
|
|
71
|
+
with open(config_path, 'w') as f:
|
|
72
|
+
json.dump(config, f, indent=2)
|
|
73
|
+
|
|
74
|
+
print(f"✅ Configuration written to: {config_path}")
|
|
75
|
+
print("🔄 Please restart Claude Code to apply changes")
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
def test_installation() -> bool:
|
|
79
|
+
"""Test that the MCP server is working correctly."""
|
|
80
|
+
print("🧪 Testing KiCAD Schematic MCP Server...")
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
# Test import
|
|
84
|
+
from kicad_sch_api.mcp.server import main as mcp_main
|
|
85
|
+
print("✅ MCP server module imports successfully")
|
|
86
|
+
|
|
87
|
+
# Test component discovery
|
|
88
|
+
from kicad_sch_api.discovery.search_index import get_search_index
|
|
89
|
+
print("✅ Component discovery system available")
|
|
90
|
+
|
|
91
|
+
# Test KiCAD library access
|
|
92
|
+
from kicad_sch_api.library.cache import get_symbol_cache
|
|
93
|
+
cache = get_symbol_cache()
|
|
94
|
+
stats = cache.get_performance_stats()
|
|
95
|
+
print(f"✅ Symbol cache initialized: {stats['total_symbols_cached']} symbols")
|
|
96
|
+
|
|
97
|
+
print("🎉 All tests passed!")
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
print(f"❌ Test failed: {e}")
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
def show_status() -> bool:
|
|
105
|
+
"""Show current installation and configuration status."""
|
|
106
|
+
print("📊 KiCAD Schematic MCP Server Status")
|
|
107
|
+
print("=" * 40)
|
|
108
|
+
|
|
109
|
+
# Check installation
|
|
110
|
+
try:
|
|
111
|
+
import kicad_sch_api
|
|
112
|
+
version = getattr(kicad_sch_api, '__version__', 'unknown')
|
|
113
|
+
print(f"✅ Package installed: v{version}")
|
|
114
|
+
except ImportError:
|
|
115
|
+
print("❌ Package not installed")
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
# Check MCP command
|
|
119
|
+
mcp_cmd_path = None
|
|
120
|
+
try:
|
|
121
|
+
result = subprocess.run(['kicad-sch-mcp', '--help'],
|
|
122
|
+
capture_output=True, timeout=5)
|
|
123
|
+
if result.returncode == 0:
|
|
124
|
+
print("✅ MCP command available")
|
|
125
|
+
mcp_cmd_path = "kicad-sch-mcp"
|
|
126
|
+
else:
|
|
127
|
+
print("⚠️ MCP command found but returns error")
|
|
128
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
129
|
+
# Try to find the command in common locations
|
|
130
|
+
import sys
|
|
131
|
+
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
132
|
+
possible_paths = [
|
|
133
|
+
f"/Library/Frameworks/Python.framework/Versions/{python_version}/bin/kicad-sch-mcp",
|
|
134
|
+
os.path.expanduser(f"~/Library/Python/{python_version}/bin/kicad-sch-mcp"),
|
|
135
|
+
os.path.expanduser("~/.local/bin/kicad-sch-mcp"),
|
|
136
|
+
"/usr/local/bin/kicad-sch-mcp"
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
for path_to_try in possible_paths:
|
|
140
|
+
if os.path.exists(path_to_try) and os.access(path_to_try, os.X_OK):
|
|
141
|
+
print(f"✅ MCP command found at: {path_to_try}")
|
|
142
|
+
print("⚠️ Note: Command not in PATH, but found at above location")
|
|
143
|
+
mcp_cmd_path = path_to_try
|
|
144
|
+
break
|
|
145
|
+
|
|
146
|
+
if not mcp_cmd_path:
|
|
147
|
+
print("❌ MCP command not found in PATH")
|
|
148
|
+
print(" You may need to add Python scripts directory to your PATH")
|
|
149
|
+
print(f" Try: export PATH=\"/Library/Frameworks/Python.framework/Versions/{python_version}/bin:$PATH\"")
|
|
150
|
+
|
|
151
|
+
# Store found path for potential use in configuration
|
|
152
|
+
if mcp_cmd_path:
|
|
153
|
+
os.environ['FOUND_MCP_PATH'] = mcp_cmd_path
|
|
154
|
+
|
|
155
|
+
# Check Claude Code configuration
|
|
156
|
+
config_path = get_claude_config_path()
|
|
157
|
+
if config_path.exists():
|
|
158
|
+
try:
|
|
159
|
+
with open(config_path) as f:
|
|
160
|
+
config = json.load(f)
|
|
161
|
+
if "kicad-sch-api" in config.get("mcpServers", {}):
|
|
162
|
+
print("✅ Claude Code MCP configuration found")
|
|
163
|
+
else:
|
|
164
|
+
print("⚠️ Claude Code config exists but kicad-sch-api not configured")
|
|
165
|
+
except json.JSONDecodeError:
|
|
166
|
+
print("❌ Claude Code config file is invalid JSON")
|
|
167
|
+
else:
|
|
168
|
+
print("❌ Claude Code configuration not found")
|
|
169
|
+
|
|
170
|
+
# Check KiCAD libraries
|
|
171
|
+
try:
|
|
172
|
+
from kicad_sch_api.library.cache import get_symbol_cache
|
|
173
|
+
cache = get_symbol_cache()
|
|
174
|
+
stats = cache.get_performance_stats()
|
|
175
|
+
print(f"✅ KiCAD libraries: {len(cache._lib_stats)} libraries, {stats['total_symbols_cached']} symbols")
|
|
176
|
+
except Exception as e:
|
|
177
|
+
print(f"⚠️ KiCAD library access: {e}")
|
|
178
|
+
|
|
179
|
+
return True
|
|
180
|
+
|
|
181
|
+
def create_demo() -> bool:
|
|
182
|
+
"""Create a demo schematic to test functionality."""
|
|
183
|
+
print("🎨 Creating demo schematic...")
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
import kicad_sch_api as ksa
|
|
187
|
+
|
|
188
|
+
# Create demo schematic
|
|
189
|
+
sch = ksa.create_schematic("Demo_Circuit")
|
|
190
|
+
|
|
191
|
+
# Add components
|
|
192
|
+
resistor = sch.components.add('Device:R', reference='R1', value='10k', position=(100, 100))
|
|
193
|
+
capacitor = sch.components.add('Device:C', reference='C1', value='100nF', position=(150, 100))
|
|
194
|
+
led = sch.components.add('Device:LED', reference='D1', value='LED', position=(200, 100))
|
|
195
|
+
|
|
196
|
+
# Add a hierarchical sheet
|
|
197
|
+
sheet_uuid = sch.add_sheet(
|
|
198
|
+
name="Subcircuit",
|
|
199
|
+
filename="subcircuit_demo.kicad_sch",
|
|
200
|
+
position=(100, 150),
|
|
201
|
+
size=(60, 40)
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Add sheet pins
|
|
205
|
+
sch.add_sheet_pin(sheet_uuid, "VCC", "input", (0, 10))
|
|
206
|
+
sch.add_sheet_pin(sheet_uuid, "GND", "input", (0, 30))
|
|
207
|
+
|
|
208
|
+
# Save schematic
|
|
209
|
+
sch.save("demo_circuit.kicad_sch")
|
|
210
|
+
|
|
211
|
+
print("✅ Demo schematic created: demo_circuit.kicad_sch")
|
|
212
|
+
print("📁 Contains: resistor, capacitor, LED, and hierarchical sheet")
|
|
213
|
+
print("🔗 Try opening in KiCAD: kicad demo_circuit.kicad_sch")
|
|
214
|
+
|
|
215
|
+
return True
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
print(f"❌ Demo creation failed: {e}")
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
def init_cache() -> bool:
|
|
222
|
+
"""Initialize the component discovery cache."""
|
|
223
|
+
print("🔄 Initializing component discovery cache...")
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
from kicad_sch_api.discovery.search_index import ensure_index_built
|
|
227
|
+
component_count = ensure_index_built()
|
|
228
|
+
print(f"✅ Component cache initialized: {component_count} components indexed")
|
|
229
|
+
return True
|
|
230
|
+
except Exception as e:
|
|
231
|
+
print(f"❌ Cache initialization failed: {e}")
|
|
232
|
+
return False
|
|
233
|
+
|
|
234
|
+
def check_kicad() -> bool:
|
|
235
|
+
"""Check KiCAD installation and library access."""
|
|
236
|
+
print("🔍 Checking KiCAD installation...")
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
# Check if KiCAD command is available
|
|
240
|
+
result = subprocess.run(['kicad', '--version'],
|
|
241
|
+
capture_output=True, timeout=10)
|
|
242
|
+
if result.returncode == 0:
|
|
243
|
+
version_output = result.stdout.decode().strip()
|
|
244
|
+
print(f"✅ KiCAD found: {version_output}")
|
|
245
|
+
else:
|
|
246
|
+
print("⚠️ KiCAD command found but version check failed")
|
|
247
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
248
|
+
print("❌ KiCAD command not found in PATH")
|
|
249
|
+
print(" Please ensure KiCAD is installed and accessible")
|
|
250
|
+
|
|
251
|
+
# Check library directories
|
|
252
|
+
try:
|
|
253
|
+
from kicad_sch_api.library.cache import get_symbol_cache
|
|
254
|
+
cache = get_symbol_cache()
|
|
255
|
+
|
|
256
|
+
print("📚 KiCAD Library Status:")
|
|
257
|
+
for lib_name, lib_stats in cache._lib_stats.items():
|
|
258
|
+
print(f" • {lib_name}: {lib_stats.symbol_count} symbols")
|
|
259
|
+
|
|
260
|
+
return True
|
|
261
|
+
except Exception as e:
|
|
262
|
+
print(f"❌ Library access failed: {e}")
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
def show_logs():
|
|
266
|
+
"""Show recent MCP server logs."""
|
|
267
|
+
print("📜 Recent MCP Server Logs")
|
|
268
|
+
print("=" * 25)
|
|
269
|
+
|
|
270
|
+
# For now, just run the server with debug output
|
|
271
|
+
print("To view live logs, run:")
|
|
272
|
+
print(" kicad-sch-mcp --debug")
|
|
273
|
+
print()
|
|
274
|
+
print("Or check Claude Code logs in:")
|
|
275
|
+
if sys.platform == "darwin":
|
|
276
|
+
print(" ~/Library/Logs/Claude/mcp-server-kicad-sch-api.log")
|
|
277
|
+
elif sys.platform == "win32":
|
|
278
|
+
print(" %USERPROFILE%\\AppData\\Local\\Claude\\Logs\\mcp-server-kicad-sch-api.log")
|
|
279
|
+
else:
|
|
280
|
+
print(" ~/.local/share/Claude/logs/mcp-server-kicad-sch-api.log")
|
|
281
|
+
|
|
282
|
+
def main():
|
|
283
|
+
"""Main CLI entry point."""
|
|
284
|
+
parser = argparse.ArgumentParser(
|
|
285
|
+
description="KiCAD Schematic API - Command Line Interface",
|
|
286
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
287
|
+
epilog="""
|
|
288
|
+
Examples:
|
|
289
|
+
kicad-sch-api --setup-claude-code # Configure Claude Code MCP
|
|
290
|
+
kicad-sch-api --test # Test installation
|
|
291
|
+
kicad-sch-api --demo # Create demo schematic
|
|
292
|
+
kicad-sch-api --status # Show status
|
|
293
|
+
"""
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
parser.add_argument('--setup-claude-code', action='store_true',
|
|
297
|
+
help='Configure Claude Code MCP settings automatically')
|
|
298
|
+
parser.add_argument('--test', action='store_true',
|
|
299
|
+
help='Test that the installation is working')
|
|
300
|
+
parser.add_argument('--status', action='store_true',
|
|
301
|
+
help='Show installation and configuration status')
|
|
302
|
+
parser.add_argument('--demo', action='store_true',
|
|
303
|
+
help='Create a demo schematic')
|
|
304
|
+
parser.add_argument('--init-cache', action='store_true',
|
|
305
|
+
help='Initialize component discovery cache')
|
|
306
|
+
parser.add_argument('--check-kicad', action='store_true',
|
|
307
|
+
help='Check KiCAD installation and libraries')
|
|
308
|
+
parser.add_argument('--logs', action='store_true',
|
|
309
|
+
help='Show recent MCP server logs')
|
|
310
|
+
|
|
311
|
+
args = parser.parse_args()
|
|
312
|
+
|
|
313
|
+
# If no arguments provided, show help
|
|
314
|
+
if not any(vars(args).values()):
|
|
315
|
+
parser.print_help()
|
|
316
|
+
return
|
|
317
|
+
|
|
318
|
+
# Execute requested actions
|
|
319
|
+
success = True
|
|
320
|
+
|
|
321
|
+
if args.setup_claude_code:
|
|
322
|
+
success &= setup_claude_code()
|
|
323
|
+
|
|
324
|
+
if args.test:
|
|
325
|
+
success &= test_installation()
|
|
326
|
+
|
|
327
|
+
if args.status:
|
|
328
|
+
success &= show_status()
|
|
329
|
+
|
|
330
|
+
if args.demo:
|
|
331
|
+
success &= create_demo()
|
|
332
|
+
|
|
333
|
+
if args.init_cache:
|
|
334
|
+
success &= init_cache()
|
|
335
|
+
|
|
336
|
+
if args.check_kicad:
|
|
337
|
+
success &= check_kicad()
|
|
338
|
+
|
|
339
|
+
if args.logs:
|
|
340
|
+
show_logs()
|
|
341
|
+
|
|
342
|
+
sys.exit(0 if success else 1)
|
|
343
|
+
|
|
344
|
+
if __name__ == "__main__":
|
|
345
|
+
main()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Component discovery tools for KiCAD schematic API.
|
|
3
|
+
|
|
4
|
+
This module provides fast search and discovery capabilities for KiCAD components
|
|
5
|
+
using a SQLite search index built from the existing symbol cache.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .search_index import ComponentSearchIndex, get_search_index
|
|
9
|
+
|
|
10
|
+
__all__ = ["ComponentSearchIndex", "get_search_index"]
|