Switchboard
by nnnunezr
README.md
# ⏻ Switchboard
**Mission control for your localhosts.** Register every dev server you run, flip them on and off from one dark, fast dashboard — and hand the keys to Claude, which can discover, start, stop and debug them over [MCP](https://modelcontextprotocol.io).
- One board for all your projects: status, port, pid, uptime, CPU/memory
- Start / stop / restart with one click — kills the whole process tree, no orphaned Vite daemons
- Live log tailing (stdout + stderr) streamed over SSE
- Port scanner: see **everything** listening on your machine, adopt unmanaged servers into the board, or kill them
- Crash detection with exit codes, port-conflict guards, process re-adoption after Switchboard restarts
- Claude integration two ways (HTTP or stdio MCP) plus a plain REST API for everything else
- Zero build step, zero external assets, works offline. Node 18+.
## Quickstart
```bash
git clone https://github.com/nnnunezr/switchboard.git
cd switchboard
npm install
npm start
```
Open **http://localhost:4200**. Register a project (name, directory, start command, port), hit **Start**.
```
usage: switchboard [--port N]
env:
PORT preferred port (default 4200, walks upward if taken)
SWITCHBOARD_TOKEN require "Authorization: Bearer <token>" on /api and /mcp
SWITCHBOARD_DATA data directory (default ~/.switchboard)
```
## Connect Claude
Switchboard speaks MCP, so Claude can find and administrate your localhosts by itself — "what's running?", "start the backend and tail its logs", "something is squatting port 3000, kill it". Use whichever transport you prefer (the **Connect Claude** button in the dashboard shows these commands pre-filled):
**Claude Code — streamable HTTP** (app must be running):
```bash
claude mcp add --transport http switchboard http://127.0.0.1:4200/mcp
```
**Claude Code — stdio** (proxies to the running app, auto-discovers its port):
```bash
claude mcp add switchboard -- node /path/to/switchboard/mcp-stdio.js
```
**Claude Desktop** — add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"switchboard": {
"command": "node",
"args": ["/path/to/switchboard/mcp-stdio.js"]
}
}
}
```
### MCP tools
| Tool | What it does |
|------|--------------|
| `list_projects` | Every registered project with live status, port, uptime, URL |
| `scan_ports` | All TCP listeners on the machine, attributed to projects where possible |
| `start_project` / `stop_project` / `restart_project` | Lifecycle control by name or id |
| `get_logs` | Tail captured stdout/stderr |
| `add_project` / `update_project` / `remove_project` | Manage the registry |
| `kill_process` | Signal an unmanaged pid found via scan |
| `app_info` | Switchboard's own version, URLs, data dir |
## REST API
Everything the UI and MCP tools do is plain HTTP on `http://127.0.0.1:4200`:
| Method & path | Purpose |
|---|---|
| `GET /api/projects?metrics=1` | List projects (optionally with CPU/mem) |
| `POST /api/projects` | Register `{name, cwd, command, port?, env?, notes?}` |
| `PUT /api/projects/:idOrName` | Update fields |
| `DELETE /api/projects/:idOrName` | Unregister |
| `POST /api/projects/:idOrName/start` \| `/stop` \| `/restart` | Lifecycle |
| `GET /api/projects/:idOrName/logs?lines=200` | Log tail |
| `GET /api/scan` | Port sweep |
| `POST /api/kill` | `{pid, signal?}` |
| `GET /api/events` | SSE stream: `projects` + `log` events |
| `GET /api/health`, `GET /api/info` | Liveness / metadata |
## How it works
- Projects are spawned through your login shell (`$SHELL -lc`) in their **own process group**, so stopping a project SIGTERMs the entire tree (with SIGKILL escalation after 5s) — dev-server child processes don't survive.
- A port probe promotes `starting → running` when the project's port opens; a non-zero exit marks it `crashed` with the exit code and captured stderr.
- Started pids are persisted, so if Switchboard itself restarts it **re-adopts** still-running servers instead of losing track of them.
- The registry lives in `~/.switchboard/projects.json` — plain JSON, edit it by hand if you like.
## Security notes
- Binds to `127.0.0.1` only, and rejects requests whose `Host` header isn't local (DNS-rebinding guard).
- Optional bearer auth: set `SWITCHBOARD_TOKEN=...` and every `/api` and `/mcp` request must carry `Authorization: Bearer <token>`. The dashboard prompts for the token and keeps it in localStorage.
- Switchboard executes the shell commands you register, with your user's privileges. That is its job — but only register commands you trust, and treat `add_project` from any connected agent accordingly.
## Changelog
See [CHANGELOG.md](CHANGELOG.md) for the list of bugs found and fixes made.
## License
MIT
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues