feat: add macOS automated setup script and update platform documentation
Add setup-macos.sh, a shell script that automates Claude Desktop MCP configuration on macOS. The script detects KiCad's bundled Python, resolves PYTHONPATH, generates the correct MCP server config, and safely merges it into the existing Claude Desktop configuration with backup support. Supports --verify, --dry-run, and --apply modes. Update README.md with documentation for the automated setup workflow, including usage examples, parameter reference, and post-setup steps. Extend docs/PLATFORM_GUIDE.md with macOS-specific sections covering installation, path handling, Python environment, troubleshooting, best practices, cross-platform migration, and support resources. Update docs/STATUS_SUMMARY.md to reflect the new macOS automation capabilities and bump the last-updated date.
This commit is contained in:
134
README.md
134
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
|
||||||
|
~/.config/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
|
||||||
|
|
||||||
|
|||||||
@@ -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 `~/.config/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: ~/.config/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/.config/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)" || {
|
||||||
|
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