Merge pull request #89 from nhebling/feat/macos-setup-script
feat: Add macOS automated setup script and update platform documentation
This commit is contained in:
137
README.md
137
README.md
@@ -505,7 +505,9 @@ See [Windows Installation Guide](docs/WINDOWS_SETUP.md) for detailed instruction
|
|||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
**Important:** On macOS, use KiCAD's bundled Python to ensure proper access to pcbnew module.
|
**Important:** On macOS, use KiCAD's bundled Python to ensure proper access to the `pcbnew` module.
|
||||||
|
|
||||||
|
#### Manual Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install KiCAD 9.0 from kicad.org/download/macos
|
# Install KiCAD 9.0 from kicad.org/download/macos
|
||||||
@@ -529,7 +531,135 @@ pip install -r requirements.txt
|
|||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** The `--system-site-packages` flag is required to access KiCAD's pcbnew module from the virtual environment.
|
**Note:** The `--system-site-packages` flag is required to access KiCAD's `pcbnew` module from the virtual environment.
|
||||||
|
|
||||||
|
#### Automated Setup
|
||||||
|
|
||||||
|
To simplify configuration with Claude Desktop, this repository provides a macOS setup script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup-macos.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
In case of error `zsh: permission denied: ./setup-macos.sh` you can either:
|
||||||
|
|
||||||
|
- always allow the script to be executed by running: `chmod +x setup-macos.sh`.
|
||||||
|
- alternatively explicitly run it with bash: `bash setup-macos.sh` so no chmod change needed.
|
||||||
|
|
||||||
|
This script does **not replace the manual setup above** — it assumes dependencies are already installed and the project is built. Instead, it automates:
|
||||||
|
|
||||||
|
- detection of your environment (Node.js, KiCad Python, `pcbnew`)
|
||||||
|
- resolving the correct macOS `PYTHONPATH`
|
||||||
|
- generating the correct Claude Desktop MCP configuration
|
||||||
|
- safely merging the configuration into your existing Claude config
|
||||||
|
- optionally writing the configuration with backup support
|
||||||
|
|
||||||
|
##### Basic Usage
|
||||||
|
|
||||||
|
###### Verify setup (no changes)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup-macos.sh --verify
|
||||||
|
```
|
||||||
|
|
||||||
|
###### Preview configuration (dry run)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup-macos.sh --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
###### Apply configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup-macos.sh --apply
|
||||||
|
```
|
||||||
|
|
||||||
|
After applying, restart Claude Desktop.
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
###### Required parameters
|
||||||
|
|
||||||
|
None. The script works out-of-the-box using sensible defaults.
|
||||||
|
|
||||||
|
###### Optional parameters
|
||||||
|
|
||||||
|
##### `--name NAME`
|
||||||
|
|
||||||
|
Specify the MCP server name in Claude Desktop.
|
||||||
|
|
||||||
|
Default:
|
||||||
|
|
||||||
|
```text
|
||||||
|
kicad
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup-macos.sh --apply --name kicad-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Use this when:
|
||||||
|
|
||||||
|
- running multiple MCP configurations
|
||||||
|
- testing forks or development versions
|
||||||
|
- avoiding overwriting an existing setup
|
||||||
|
|
||||||
|
##### `--claude-config PATH`
|
||||||
|
|
||||||
|
Specify a custom Claude Desktop configuration file.
|
||||||
|
|
||||||
|
Default:
|
||||||
|
|
||||||
|
```text
|
||||||
|
~/Library/Application Support/Claude/claude_desktop_config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup-macos.sh --dry-run --claude-config ~/tmp/claude_config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Use this when:
|
||||||
|
|
||||||
|
- testing configurations safely
|
||||||
|
- using non-standard config locations
|
||||||
|
- debugging without modifying your main setup
|
||||||
|
|
||||||
|
##### `--yes`
|
||||||
|
|
||||||
|
Skip confirmation prompt when applying changes.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./setup-macos.sh --apply --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
##### After Setup
|
||||||
|
|
||||||
|
1. Fully quit Claude Desktop
|
||||||
|
2. Reopen Claude Desktop
|
||||||
|
3. Open a new chat
|
||||||
|
4. Click **+ → Connectors**
|
||||||
|
5. Verify the server appears (e.g. `kicad` or your custom name)
|
||||||
|
|
||||||
|
Test with prompt in Claude Desktop:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Use the kicad MCP server to run check_kicad_ui.
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Notes
|
||||||
|
|
||||||
|
- The script only modifies the `mcpServers` section and leaves all other configuration untouched
|
||||||
|
- Existing configurations are automatically backed up before changes
|
||||||
|
- macOS support relies on KiCad’s bundled Python; system Python will not work correctly
|
||||||
|
- If KiCad is updated or moved, re-run the script to refresh paths
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
@@ -537,7 +667,8 @@ npm run build
|
|||||||
|
|
||||||
Edit configuration file:
|
Edit configuration file:
|
||||||
|
|
||||||
- **Linux/macOS:** `~/.config/Claude/claude_desktop_config.json`
|
- **Linux:** `~/.config/Claude/claude_desktop_config.json`
|
||||||
|
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||||
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
||||||
|
|
||||||
**Configuration:**
|
**Configuration:**
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
# Platform Guide: Linux vs Windows
|
# Platform Guide: Linux, macOS & Windows
|
||||||
|
|
||||||
This guide explains the differences between using KiCAD MCP Server on Linux and Windows platforms.
|
This guide explains the differences between using KiCAD MCP Server on Linux, macOS, and Windows platforms.
|
||||||
|
|
||||||
**Last Updated:** 2025-11-05
|
**Last Updated:** 2026-04-11
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quick Comparison
|
## Quick Comparison
|
||||||
|
|
||||||
| Feature | Linux | Windows |
|
| Feature | Linux | Windows | macOS |
|
||||||
| ------------------------ | ------------------------- | ------------------------------- |
|
| ------------------------ | ------------------------- | ------------------------------- | ----------------------- |
|
||||||
| **Primary Support** | Full (tested extensively) | Community tested |
|
| **Primary Support** | Full (tested extensively) | Community tested | Community tested |
|
||||||
| **Setup Complexity** | Moderate | Easy (automated script) |
|
| **Setup Complexity** | Moderate | Easy (automated script) | Easy (automated script) |
|
||||||
| **Prerequisites** | Manual package management | Automated detection |
|
| **Prerequisites** | Manual package management | Automated detection | Automated detection |
|
||||||
| **KiCAD Python Access** | System paths | Bundled with KiCAD |
|
| **KiCAD Python Access** | System paths | Bundled with KiCAD | Bundled with KiCAD |
|
||||||
| **Path Separators** | Forward slash (/) | Backslash (\\) or forward slash |
|
| **Path Separators** | Forward slash (/) | Backslash (\\) or forward slash | Forward slash (/) |
|
||||||
| **Virtual Environments** | Recommended | Optional |
|
| **Virtual Environments** | Recommended | Optional | Optional |
|
||||||
| **Troubleshooting** | Standard Linux tools | PowerShell diagnostics |
|
| **Troubleshooting** | Standard Linux tools | PowerShell diagnostics | Bash diagnostics |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -65,6 +65,51 @@ Python: /usr/bin/python3
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### macOS Installation
|
||||||
|
|
||||||
|
**Advantages:**
|
||||||
|
|
||||||
|
- Automated setup script (`setup-macos.sh`) handles detection and configuration
|
||||||
|
- KiCAD includes bundled Python (no system Python needed for pcbnew)
|
||||||
|
- Prerequisite checks with clear pass/fail output
|
||||||
|
- Generates and merges Claude Desktop configuration automatically
|
||||||
|
|
||||||
|
**Process:**
|
||||||
|
|
||||||
|
1. Install KiCAD 9.0 from the official `.dmg` installer
|
||||||
|
2. Install Node.js (e.g. via Homebrew or nvm)
|
||||||
|
3. Clone repository
|
||||||
|
4. Run `npm install && npm run build`
|
||||||
|
5. Run `setup-macos.sh`:
|
||||||
|
- `bash setup-macos.sh --verify` — check prerequisites and detected paths
|
||||||
|
- `bash setup-macos.sh --dry-run` — preview the merged Claude Desktop config
|
||||||
|
- `bash setup-macos.sh --apply` — write the configuration
|
||||||
|
|
||||||
|
**Typical paths:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
KiCAD Python: /Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3
|
||||||
|
KiCAD Libraries: /Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/3.x/lib/python3.x/site-packages
|
||||||
|
Node.js: /usr/local/bin/node # or via nvm
|
||||||
|
```
|
||||||
|
|
||||||
|
**Configuration example:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"kicad": {
|
||||||
|
"command": "node",
|
||||||
|
"args": ["/Users/username/KiCAD-MCP-Server/dist/index.js"],
|
||||||
|
"env": {
|
||||||
|
"KICAD_PYTHON": "/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3",
|
||||||
|
"PYTHONPATH": "/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Windows Installation
|
### Windows Installation
|
||||||
|
|
||||||
**Advantages:**
|
**Advantages:**
|
||||||
@@ -130,6 +175,21 @@ export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
|||||||
python3 -c "import pcbnew"
|
python3 -c "import pcbnew"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### macOS Paths
|
||||||
|
|
||||||
|
- Use forward slashes: `/Users/username/project`
|
||||||
|
- Case-insensitive but case-preserving filesystem (APFS default)
|
||||||
|
- No drive letters
|
||||||
|
- KiCAD paths are inside the `.app` bundle
|
||||||
|
|
||||||
|
**Example commands:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/KiCAD-MCP-Server
|
||||||
|
export KICAD_PYTHON=/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3
|
||||||
|
"$KICAD_PYTHON" -c "import pcbnew"
|
||||||
|
```
|
||||||
|
|
||||||
### Windows Paths
|
### Windows Paths
|
||||||
|
|
||||||
- Use backslashes in native commands: `C:\Users\username`
|
- Use backslashes in native commands: `C:\Users\username`
|
||||||
@@ -199,6 +259,27 @@ export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
|||||||
echo 'export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages' >> ~/.bashrc
|
echo 'export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages' >> ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
**KiCAD Bundled Python:**
|
||||||
|
|
||||||
|
- KiCAD bundles Python inside the `.app` framework (versions 3.9–3.12)
|
||||||
|
- No system Python installation needed for pcbnew
|
||||||
|
- `setup-macos.sh` detects the correct path automatically
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check KiCAD Python
|
||||||
|
/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3 --version
|
||||||
|
|
||||||
|
# Verify pcbnew module
|
||||||
|
/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"
|
||||||
|
|
||||||
|
# Or use the setup script to verify everything at once
|
||||||
|
bash setup-macos.sh --verify
|
||||||
|
```
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
**KiCAD Bundled Python:**
|
**KiCAD Bundled Python:**
|
||||||
@@ -275,6 +356,32 @@ export PYTHONPATH=/usr/lib/kicad/lib/python3/dist-packages
|
|||||||
node dist/index.js
|
node dist/index.js
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
**Check KiCAD installation:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls /Applications/KiCad/KiCad.app
|
||||||
|
```
|
||||||
|
|
||||||
|
**Run automated diagnostics:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash setup-macos.sh --verify
|
||||||
|
```
|
||||||
|
|
||||||
|
**View logs:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tail -f ~/.kicad-mcp/logs/kicad_interface.log
|
||||||
|
```
|
||||||
|
|
||||||
|
**Start server manually:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node dist/index.js
|
||||||
|
```
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
**Check KiCAD installation:**
|
**Check KiCAD installation:**
|
||||||
@@ -356,6 +463,30 @@ sudo apt-get install python3-wxgtk4.0 python3-cairo
|
|||||||
ldd /usr/lib/kicad/lib/python3/dist-packages/pcbnew.so
|
ldd /usr/lib/kicad/lib/python3/dist-packages/pcbnew.so
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### macOS-Specific Issues
|
||||||
|
|
||||||
|
**1. KiCad Python Not Found**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verify the expected path exists
|
||||||
|
ls /Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3
|
||||||
|
|
||||||
|
# If installed elsewhere, set the override
|
||||||
|
export KICAD_PYTHON=/path/to/your/kicad/python3
|
||||||
|
bash setup-macos.sh --verify
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. pcbnew Import Fails**
|
||||||
|
|
||||||
|
- Run `bash setup-macos.sh --verify` — the Prerequisites section will show a ✗ if pcbnew can't be imported
|
||||||
|
- Reinstall KiCAD if the bundled Python is corrupted
|
||||||
|
|
||||||
|
**3. Claude Config Not Picked Up**
|
||||||
|
|
||||||
|
- Default path is `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||||
|
- Use `--claude-config` flag to point to a different location
|
||||||
|
- Fully quit and reopen Claude Desktop after changes
|
||||||
|
|
||||||
### Windows-Specific Issues
|
### Windows-Specific Issues
|
||||||
|
|
||||||
**1. Server Exits Immediately**
|
**1. Server Exits Immediately**
|
||||||
@@ -479,6 +610,14 @@ npm test
|
|||||||
4. **Check file permissions** if encountering access errors
|
4. **Check file permissions** if encountering access errors
|
||||||
5. **Monitor system logs** with `journalctl` if needed
|
5. **Monitor system logs** with `journalctl` if needed
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
1. **Run `setup-macos.sh --verify` first** — confirms all prerequisites
|
||||||
|
2. **Use `--dry-run` before `--apply`** — review the merged config before writing
|
||||||
|
3. **Use KiCAD's bundled Python** — don't rely on system or Homebrew Python for pcbnew
|
||||||
|
4. **Override with `KICAD_PYTHON` env var** if KiCAD is in a non-standard location
|
||||||
|
5. **Check logs** in `~/.kicad-mcp/logs/` when debugging
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
1. **Run setup-windows.ps1 first** - saves time troubleshooting
|
1. **Run setup-windows.ps1 first** - saves time troubleshooting
|
||||||
@@ -507,6 +646,13 @@ npm test
|
|||||||
4. Update PYTHONPATH to Linux format
|
4. Update PYTHONPATH to Linux format
|
||||||
5. Set file permissions: `chmod +x python/kicad_interface.py`
|
5. Set file permissions: `chmod +x python/kicad_interface.py`
|
||||||
|
|
||||||
|
### Moving to/from macOS
|
||||||
|
|
||||||
|
1. Clone repository on the target machine
|
||||||
|
2. Run `npm install && npm run build`
|
||||||
|
3. Run `bash setup-macos.sh --apply` (to macOS) or follow the target platform's setup
|
||||||
|
4. No project file changes needed
|
||||||
|
|
||||||
**KiCAD project files (.kicad_pro, .kicad_pcb) are identical across platforms.**
|
**KiCAD project files (.kicad_pro, .kicad_pcb) are identical across platforms.**
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -520,6 +666,13 @@ npm test
|
|||||||
- Search: GitHub Issues filtered by `linux` label
|
- Search: GitHub Issues filtered by `linux` label
|
||||||
- Community: Linux users in Discussions
|
- Community: Linux users in Discussions
|
||||||
|
|
||||||
|
### macOS Support
|
||||||
|
|
||||||
|
- Check: [README.md](../README.md) macOS installation section
|
||||||
|
- Run: `bash setup-macos.sh --verify` for automated diagnostics
|
||||||
|
- Search: GitHub Issues filtered by `macos` label
|
||||||
|
- Community: macOS users in Discussions
|
||||||
|
|
||||||
### Windows Support
|
### Windows Support
|
||||||
|
|
||||||
- Check: [README.md](../README.md) Windows installation section
|
- Check: [README.md](../README.md) Windows installation section
|
||||||
@@ -539,6 +692,12 @@ npm test
|
|||||||
- You're developing or contributing to the project
|
- You're developing or contributing to the project
|
||||||
- You need maximum performance
|
- You need maximum performance
|
||||||
|
|
||||||
|
**Choose macOS if:**
|
||||||
|
|
||||||
|
- You're already using KiCAD on macOS
|
||||||
|
- You want automated setup with `setup-macos.sh`
|
||||||
|
- You prefer a Unix-based development environment
|
||||||
|
|
||||||
**Choose Windows if:**
|
**Choose Windows if:**
|
||||||
|
|
||||||
- You want automated setup and diagnostics
|
- You want automated setup and diagnostics
|
||||||
@@ -546,16 +705,18 @@ npm test
|
|||||||
- You need detailed troubleshooting guidance
|
- You need detailed troubleshooting guidance
|
||||||
- You're a KiCAD user new to development tools
|
- You're a KiCAD user new to development tools
|
||||||
|
|
||||||
**Both platforms work well for PCB design with KiCAD MCP. Choose based on your comfort level and existing development environment.**
|
**All platforms work well for PCB design with KiCAD MCP. Choose based on your comfort level and existing development environment.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**For platform-specific installation instructions, see:**
|
**For platform-specific installation instructions, see:**
|
||||||
|
|
||||||
- Linux: [README.md - Linux Installation](../README.md#linux-ubuntudebian)
|
- Linux: [README.md - Linux Installation](../README.md#linux-ubuntudebian)
|
||||||
|
- macOS: [README.md - macOS Installation](../README.md#macos)
|
||||||
- Windows: [README.md - Windows Installation](../README.md#windows-1011)
|
- Windows: [README.md - Windows Installation](../README.md#windows-1011)
|
||||||
|
|
||||||
**For troubleshooting:**
|
**For troubleshooting:**
|
||||||
|
|
||||||
- Linux: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md)
|
- Linux: [KNOWN_ISSUES.md](./KNOWN_ISSUES.md)
|
||||||
|
- macOS: Run `bash setup-macos.sh --verify`
|
||||||
- Windows: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md)
|
- Windows: [WINDOWS_TROUBLESHOOTING.md](./WINDOWS_TROUBLESHOOTING.md)
|
||||||
|
|||||||
@@ -90,9 +90,11 @@ The server automatically selects the best backend:
|
|||||||
|
|
||||||
### macOS -- Community Supported
|
### macOS -- Community Supported
|
||||||
|
|
||||||
- Configuration provided
|
- Automated setup script (setup-macos.sh)
|
||||||
|
- Auto-detects KiCad Python and pcbnew
|
||||||
|
- Generates Claude Desktop configuration
|
||||||
- Process detection implemented
|
- Process detection implemented
|
||||||
- Library paths configured
|
- Library paths auto-configured
|
||||||
- Needs community testing
|
- Needs community testing
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -170,4 +172,4 @@ The server automatically selects the best backend:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Last Updated: 2026-03-21_
|
_Last Updated: 2026-04-11_
|
||||||
|
|||||||
317
setup-macos.sh
Normal file
317
setup-macos.sh
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MODE=""
|
||||||
|
ASSUME_YES=0
|
||||||
|
SERVER_NAME="kicad"
|
||||||
|
CLAUDE_CONFIG_PATH=""
|
||||||
|
|
||||||
|
SCRIPT_NAME="$(basename "$0")"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage:
|
||||||
|
$SCRIPT_NAME --verify [--name NAME] [--claude-config PATH]
|
||||||
|
$SCRIPT_NAME --dry-run [--name NAME] [--claude-config PATH]
|
||||||
|
$SCRIPT_NAME --apply [--name NAME] [--claude-config PATH] [--yes]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--verify Check prerequisites and print detected paths
|
||||||
|
--dry-run Show config and merged Claude Desktop config without writing
|
||||||
|
--apply Write/update Claude Desktop config
|
||||||
|
--yes Do not prompt before writing (only with --apply)
|
||||||
|
--name NAME MCP server name (default: kicad)
|
||||||
|
--claude-config PATH Path to Claude Desktop config file
|
||||||
|
(default: ~/Library/Application Support/Claude/claude_desktop_config.json)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Terminal formatting ---
|
||||||
|
if [[ -t 1 ]]; then
|
||||||
|
BOLD=$'\033[1m'
|
||||||
|
DIM=$'\033[2m'
|
||||||
|
RESET=$'\033[0m'
|
||||||
|
GREEN=$'\033[32m'
|
||||||
|
YELLOW=$'\033[33m'
|
||||||
|
RED=$'\033[31m'
|
||||||
|
CYAN=$'\033[36m'
|
||||||
|
else
|
||||||
|
BOLD="" DIM="" RESET="" GREEN="" YELLOW="" RED="" CYAN=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
SYM_OK="${GREEN}✓${RESET}"
|
||||||
|
SYM_WARN="${YELLOW}⚠${RESET}"
|
||||||
|
SYM_FAIL="${RED}✗${RESET}"
|
||||||
|
|
||||||
|
fail() { echo "${SYM_FAIL} ${RED}Error:${RESET} $1" >&2; exit 1; }
|
||||||
|
info() { echo "${SYM_OK} $1"; }
|
||||||
|
warn() { echo "${SYM_WARN} ${YELLOW}$1${RESET}"; }
|
||||||
|
|
||||||
|
section() {
|
||||||
|
echo
|
||||||
|
echo "${DIM}────────────────────────────────────────────────────${RESET}"
|
||||||
|
echo "${BOLD}${CYAN}$1${RESET}"
|
||||||
|
echo "${DIM}────────────────────────────────────────────────────${RESET}"
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--verify)
|
||||||
|
MODE="verify"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
MODE="dry-run"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--apply)
|
||||||
|
MODE="apply"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--yes)
|
||||||
|
ASSUME_YES=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--name)
|
||||||
|
[[ $# -ge 2 ]] || fail "--name requires a value"
|
||||||
|
SERVER_NAME="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--claude-config)
|
||||||
|
[[ $# -ge 2 ]] || fail "--claude-config requires a value"
|
||||||
|
CLAUDE_CONFIG_PATH="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
fail "Unknown argument: $1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -n "$MODE" ]] || { usage; exit 1; }
|
||||||
|
[[ -n "$SERVER_NAME" ]] || fail "Server name must not be empty"
|
||||||
|
|
||||||
|
if [[ -z "$CLAUDE_CONFIG_PATH" ]]; then
|
||||||
|
CLAUDE_CONFIG_PATH="$HOME/Library/Application Support/Claude/claude_desktop_config.json"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$CLAUDE_CONFIG_PATH" in
|
||||||
|
"~/"*)
|
||||||
|
CLAUDE_CONFIG_PATH="$HOME/${CLAUDE_CONFIG_PATH#~/}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLAUDE_CONFIG_DIR="$(dirname "$CLAUDE_CONFIG_PATH")"
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
if [[ -f "$SCRIPT_DIR/package.json" ]]; then
|
||||||
|
REPO_ROOT="$SCRIPT_DIR"
|
||||||
|
else
|
||||||
|
REPO_ROOT="$(pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
DIST_JS="$REPO_ROOT/dist/index.js"
|
||||||
|
|
||||||
|
DEFAULT_KICAD_PYTHON="/Applications/KiCad/KiCad.app/Contents/Frameworks/Python.framework/Versions/Current/bin/python3"
|
||||||
|
KICAD_PYTHON="${KICAD_PYTHON:-$DEFAULT_KICAD_PYTHON}"
|
||||||
|
|
||||||
|
command -v python3 >/dev/null 2>&1 || fail "python3 not found"
|
||||||
|
NODE_PATH="$(command -v node || true)"
|
||||||
|
[[ -n "$NODE_PATH" ]] || fail "node not found in PATH"
|
||||||
|
|
||||||
|
[[ -f "$DIST_JS" ]] || fail "Missing build artifact: $DIST_JS. Run 'npm install && npm run build' first."
|
||||||
|
[[ -x "$KICAD_PYTHON" ]] || fail "KiCad Python not found or not executable: $KICAD_PYTHON"
|
||||||
|
|
||||||
|
DETECT_JSON="$("$KICAD_PYTHON" - <<'PY'
|
||||||
|
import json, sys, sysconfig
|
||||||
|
result = {
|
||||||
|
"python_executable": sys.executable,
|
||||||
|
"python_version": sys.version.split()[0],
|
||||||
|
"purelib": sysconfig.get_paths().get("purelib"),
|
||||||
|
"pcbnew_ok": False,
|
||||||
|
"pcbnew_version": None,
|
||||||
|
"pcbnew_error": None,
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
import pcbnew
|
||||||
|
result["pcbnew_ok"] = True
|
||||||
|
if hasattr(pcbnew, "GetBuildVersion"):
|
||||||
|
result["pcbnew_version"] = pcbnew.GetBuildVersion()
|
||||||
|
except Exception as e:
|
||||||
|
result["pcbnew_error"] = repr(e)
|
||||||
|
print(json.dumps(result))
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
|
||||||
|
PYTHON_EXE="$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["python_executable"])' "$DETECT_JSON")"
|
||||||
|
PYTHON_VERSION="$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["python_version"])' "$DETECT_JSON")"
|
||||||
|
PYTHONPATH_VALUE="$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["purelib"])' "$DETECT_JSON")"
|
||||||
|
PCBNEW_OK="$(python3 -c 'import json,sys; print("true" if json.loads(sys.argv[1])["pcbnew_ok"] else "false")' "$DETECT_JSON")"
|
||||||
|
PCBNEW_VERSION="$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["pcbnew_version"] or "")' "$DETECT_JSON")"
|
||||||
|
PCBNEW_ERROR="$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["pcbnew_error"] or "")' "$DETECT_JSON")"
|
||||||
|
|
||||||
|
if [[ "$PCBNEW_OK" != "true" ]]; then
|
||||||
|
fail "KiCad Python could not import pcbnew. Details: $PCBNEW_ERROR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONFIG_FRAGMENT_JSON="$(python3 - "$NODE_PATH" "$DIST_JS" "$KICAD_PYTHON" "$PYTHONPATH_VALUE" <<'PY'
|
||||||
|
import json, sys
|
||||||
|
fragment = {
|
||||||
|
"command": sys.argv[1],
|
||||||
|
"args": [sys.argv[2]],
|
||||||
|
"env": {
|
||||||
|
"KICAD_PYTHON": sys.argv[3],
|
||||||
|
"PYTHONPATH": sys.argv[4],
|
||||||
|
"LOG_LEVEL": "info"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(json.dumps(fragment, indent=2))
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
|
||||||
|
show_detected() {
|
||||||
|
section "Prerequisites"
|
||||||
|
echo " ${SYM_OK} python3 $(command -v python3)"
|
||||||
|
echo " ${SYM_OK} node $NODE_PATH"
|
||||||
|
echo " ${SYM_OK} build artifact $DIST_JS"
|
||||||
|
echo " ${SYM_OK} KiCad Python $KICAD_PYTHON"
|
||||||
|
echo " ${SYM_OK} pcbnew import $PCBNEW_VERSION"
|
||||||
|
|
||||||
|
section "Configuration"
|
||||||
|
echo " Server name: ${BOLD}$SERVER_NAME${RESET}"
|
||||||
|
echo " Repo root: $REPO_ROOT"
|
||||||
|
echo " Python executable: $PYTHON_EXE"
|
||||||
|
echo " Python version: $PYTHON_VERSION"
|
||||||
|
echo " PYTHONPATH: $PYTHONPATH_VALUE"
|
||||||
|
echo " Claude config: $CLAUDE_CONFIG_PATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
merge_config() {
|
||||||
|
python3 - "$CLAUDE_CONFIG_PATH" "$CONFIG_FRAGMENT_JSON" "$SERVER_NAME" <<'PY'
|
||||||
|
import json, os, sys
|
||||||
|
|
||||||
|
config_path = sys.argv[1]
|
||||||
|
fragment = json.loads(sys.argv[2])
|
||||||
|
server_name = sys.argv[3]
|
||||||
|
|
||||||
|
existing = {}
|
||||||
|
status = {
|
||||||
|
"config_exists": False,
|
||||||
|
"config_valid": True,
|
||||||
|
"had_mcpServers": False,
|
||||||
|
"had_entry": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
status["config_exists"] = True
|
||||||
|
try:
|
||||||
|
with open(config_path, "r", encoding="utf-8") as f:
|
||||||
|
text = f.read().strip()
|
||||||
|
existing = json.loads(text) if text else {}
|
||||||
|
except Exception:
|
||||||
|
print(json.dumps({"error": "Existing Claude config is not valid JSON", "status": status}))
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
if not isinstance(existing, dict):
|
||||||
|
print(json.dumps({"error": "Existing Claude config root is not a JSON object", "status": status}))
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
if "mcpServers" in existing:
|
||||||
|
status["had_mcpServers"] = True
|
||||||
|
if not isinstance(existing["mcpServers"], dict):
|
||||||
|
print(json.dumps({"error": "'mcpServers' exists but is not an object", "status": status}))
|
||||||
|
sys.exit(2)
|
||||||
|
else:
|
||||||
|
existing["mcpServers"] = {}
|
||||||
|
|
||||||
|
if server_name in existing["mcpServers"]:
|
||||||
|
status["had_entry"] = True
|
||||||
|
|
||||||
|
existing["mcpServers"][server_name] = fragment
|
||||||
|
print(json.dumps({"status": status, "merged": existing}, indent=2))
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$MODE" == "verify" ]]; then
|
||||||
|
show_detected
|
||||||
|
section "Proposed Claude Desktop entry ('$SERVER_NAME')"
|
||||||
|
echo "$CONFIG_FRAGMENT_JSON"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
MERGE_RESULT="$(merge_config 2>&1)" || {
|
||||||
|
echo "$MERGE_RESULT"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
MERGED_JSON="$(python3 -c 'import json,sys; print(json.dumps(json.loads(sys.stdin.read())["merged"], indent=2))' <<<"$MERGE_RESULT")"
|
||||||
|
CONFIG_EXISTS="$(python3 -c 'import json,sys; print("true" if json.loads(sys.stdin.read())["status"]["config_exists"] else "false")' <<<"$MERGE_RESULT")"
|
||||||
|
HAD_ENTRY="$(python3 -c 'import json,sys; print("true" if json.loads(sys.stdin.read())["status"]["had_entry"] else "false")' <<<"$MERGE_RESULT")"
|
||||||
|
|
||||||
|
show_detected
|
||||||
|
|
||||||
|
section "Proposed MCP entry ('$SERVER_NAME')"
|
||||||
|
echo "$CONFIG_FRAGMENT_JSON"
|
||||||
|
|
||||||
|
section "Claude Desktop config"
|
||||||
|
if [[ "$CONFIG_EXISTS" == "true" ]]; then
|
||||||
|
if [[ "$HAD_ENTRY" == "true" ]]; then
|
||||||
|
warn "Existing config already has mcpServers.$SERVER_NAME — it will be replaced."
|
||||||
|
else
|
||||||
|
info "Existing config will be preserved; mcpServers.$SERVER_NAME will be added."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
info "Config does not exist yet. A new file will be created."
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo "${DIM}Merged config preview:${RESET}"
|
||||||
|
echo "$MERGED_JSON"
|
||||||
|
|
||||||
|
if [[ "$MODE" == "dry-run" ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$CLAUDE_CONFIG_DIR"
|
||||||
|
|
||||||
|
if [[ $ASSUME_YES -ne 1 ]]; then
|
||||||
|
echo
|
||||||
|
read -r -p "Write this configuration to $CLAUDE_CONFIG_PATH ? [y/N] " REPLY
|
||||||
|
case "$REPLY" in
|
||||||
|
y|Y|yes|YES) ;;
|
||||||
|
*)
|
||||||
|
echo "Aborted."
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
ORIG_MODE=""
|
||||||
|
if [[ -f "$CLAUDE_CONFIG_PATH" ]]; then
|
||||||
|
ORIG_MODE="$(stat -f '%Lp' "$CLAUDE_CONFIG_PATH")"
|
||||||
|
BACKUP_PATH="${CLAUDE_CONFIG_PATH}.bak.$(date +%Y%m%d-%H%M%S)"
|
||||||
|
cp "$CLAUDE_CONFIG_PATH" "$BACKUP_PATH"
|
||||||
|
info "Backup written to ${DIM}$BACKUP_PATH${RESET}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP_PATH="${CLAUDE_CONFIG_PATH}.tmp.$$"
|
||||||
|
(umask 077 && printf '%s\n' "$MERGED_JSON" > "$TMP_PATH")
|
||||||
|
if [[ -n "$ORIG_MODE" ]]; then
|
||||||
|
chmod "$ORIG_MODE" "$TMP_PATH"
|
||||||
|
fi
|
||||||
|
mv "$TMP_PATH" "$CLAUDE_CONFIG_PATH"
|
||||||
|
|
||||||
|
section "Done"
|
||||||
|
info "Claude Desktop configuration updated successfully."
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "${BOLD}Next steps:${RESET}"
|
||||||
|
echo " 1. Fully quit Claude Desktop"
|
||||||
|
echo " 2. Reopen Claude Desktop"
|
||||||
|
echo " 3. In a new chat, check: + → Connectors"
|
||||||
|
echo " 4. Verify with:"
|
||||||
|
echo " Use the ${BOLD}$SERVER_NAME${RESET} MCP server to run ${BOLD}check_kicad_ui${RESET}."
|
||||||
|
echo
|
||||||
Reference in New Issue
Block a user