mcp-start-claude
by kongo97
README.md
# mcp-start-claude
Server **MCP** (trasporto **SSE**) che espone un tool per avviare **Claude Code**
in una cartella di progetto specifica, aprendo una sessione interattiva in un
nuovo terminale.
Pensato principalmente per **Linux**: rileva automaticamente l'emulatore di
terminale disponibile, in ordine di preferenza:
`gnome-terminal`, `ptyxis`, `konsole`, `xfce4-terminal`, `tilix`, `terminator`,
`alacritty`, `kitty`, `wezterm`, `foot`, `x-terminal-emulator` (fallback Debian),
`xterm`.
Su **WSL**, se non è installato alcun terminale Linux, ricade su **Windows
Terminal** (`wt.exe`) entrando nel distro WSL.
## Requisiti
- Node.js ≥ 18
- `claude` (Claude Code CLI) nel `PATH` dell'utente che avvia il server
- Un emulatore di terminale tra quelli sopra **e** una sessione grafica
(`DISPLAY` o `WAYLAND_DISPLAY`). In ambiente headless il tool restituisce un
errore esplicito anziché fingere un avvio riuscito.
## Installazione
```bash
npm install
npm run build
```
## Avvio
La **radice di accesso è obbligatoria**: si passa come argomento (o via
`BASE_DIR`). Il tool potrà aprire solo cartelle al suo interno; senza una radice
valida il server non parte.
Il modo più comodo è creare un file `.env` (copiando `.env.example`): all'avvio
viene caricato in automatico, così basta `npm start` senza argomenti.
```bash
cp .env.example .env # poi modifica BASE_DIR ecc.
npm start # http://127.0.0.1:3939/sse — legge .env
# In alternativa, passando i parametri a mano (hanno la PRECEDENZA sul .env):
npm start -- /home/ubuntu/projects
BASE_DIR=/home/ubuntu/projects npm start
```
Variabili d'ambiente (da `.env`, env reali o argomenti):
| Variabile | Default | Descrizione |
| -------------- | ------------- | ------------------------------------------------------------------ |
| `PORT` | `3939` | Porta del server SSE |
| `HOST` | `127.0.0.1` | Host di bind |
| `BASE_DIR` | **obbligatoria** | Radice di accesso. Alternativa all'argomento CLI. Il tool apre solo cartelle al suo interno (con protezione anti-traversal e anti-symlink) |
| `MCP_TERMINAL` | autodetect | Forza il terminale per nome del binario (es. `gnome-terminal`, `konsole`, `alacritty`, `kitty`, `wt.exe`) |
| `CLAUDE_REMOTE_CONTROL` | attivo | Avvia con `--remote-control`. Imposta `0`/`false`/`off`/`no` per disattivarlo |
## Endpoint
- `GET /sse` — stream SSE (handshake MCP, trasporto SSE)
- `POST /messages?sessionId=...` — messaggi del client (trasporto SSE)
- `POST /mcp` — trasporto **Streamable HTTP** stateless (standard MCP attuale)
- `GET /health` — stato e numero di sessioni attive
Il server espone **entrambi** i trasporti: SSE (come da requisito) e Streamable
HTTP. Per i client moderni (es. `mcp-remote`, connettori nativi) usa `/mcp`, che
è la prima scelta ed evita il client SSE di fallback.
## Tool esposto
### `start_claude_code`
| Parametro | Tipo | Obbligatorio | Descrizione |
| ------------- | -------- | ------------ | -------------------------------------------------------- |
| `projectPath` | `string` | sì | Cartella in cui avviare Claude Code. Deve stare dentro la radice di accesso (relativa ad essa o assoluta al suo interno); fuori radice è rifiutata |
| `prompt` | `string` | no | Prompt iniziale della sessione |
Apre un nuovo terminale, entra nella cartella e lancia `claude --remote-control`
(Remote Control abilitato all'avvio; disattivabile con `CLAUDE_REMOTE_CONTROL`).
L'eventuale `prompt` è passato come messaggio iniziale. Dopo l'uscita di Claude
Code resta una shell interattiva (lo script si autoelimina).
## Registrazione in Claude Code
Con il server in esecuzione:
```bash
claude mcp add --transport sse start-claude http://127.0.0.1:3939/sse
```
Poi, da Claude Code, basta chiedere di avviare Claude Code in una cartella e
verrà invocato il tool `start_claude_code`.
## Uso con Claude Desktop (da WSL)
Claude Desktop gira su Windows, il server in WSL. Si usa il bridge `mcp-remote`
**dentro WSL** (così parla col server su `127.0.0.1`, senza forwarding
Windows↔WSL). Entry in `claude_desktop_config.json`:
```json
{
"mcpServers": {
"start-claude": {
"command": "wsl.exe",
"args": [
"bash",
"-lc",
"export NVM_DIR=/home/ubuntu/.nvm; . /home/ubuntu/.nvm/nvm.sh; exec npx -y mcp-remote http://127.0.0.1:3939/mcp --allow-http"
]
}
}
}
```
> ⚠️ Due trappole, entrambe già gestite nel comando sopra:
> 1. La login shell avviata da `wsl.exe` **non** carica nvm e cadrebbe sul Node
> di sistema (es. v18), troppo vecchio per `mcp-remote` (`ReferenceError: File
> is not defined`). Per questo si fa il source esplicito di `nvm.sh`.
> 2. Le **virgolette doppie** dentro il comando vengono mangiate passando per
> `wsl.exe` (es. `"$HOME/.nvm"` → variabile vuota). Usare quindi un **path
> assoluto senza virgolette** (`/home/<utente>/.nvm`).
Procedura:
1. In WSL, **dal tuo terminale interattivo aperto sul desktop**, avvia il server
indicando la radice di accesso: `npm start -- /home/ubuntu/projects`
(lasciarlo in esecuzione). Vedi sotto perché il terminale conta.
2. Riavviare **completamente** Claude Desktop (uscire dalla tray, non solo
chiudere la finestra) così ricarica il config e avvia il bridge.
3. Il tool `start_claude_code` diventa disponibile in chat.
> ⚠️ **Il server va avviato dalla tua sessione desktop interattiva.** `wt.exe`
> viene lanciato tramite la WSL interop (`WSL_INTEROP`) del processo che lo
> esegue: se il server gira in un'altra sessione WSL (es. avviato da un agente,
> da un servizio o via SSH), `wt.exe` *esegue* ma la finestra compare in una
> sessione non visibile. Avviando `npm start` dal tuo terminale, le finestre si
> aprono sul tuo schermo. (Verifica veloce della sessione: lancia `wt.exe` dal
> terminale; se si apre una finestra, è quella giusta per `npm start`.)
## Accesso da mobile: Cloudflare Tunnel + Access
I connettori di Claude (web e **mobile**) vengono raggiunti dal **cloud di
Anthropic**, non dal tuo dispositivo: serve quindi un endpoint **pubblico** con
**certificato valido** (una VPN privata non basta). Si ottiene con un Cloudflare
Tunnel, e l'autenticazione la gestisce **Cloudflare Access** (nessun codice OAuth
da scrivere lato server).
```
[Cloud Anthropic] → https://mcp.pawsolutions.it (TLS valido, Cloudflare)
→ Cloudflare Access (gate OAuth: passa solo chi rispetta la policy)
→ Cloudflare Tunnel (cloudflared, connessione in uscita: nessuna porta aperta)
→ http://localhost:3939/mcp (server MCP locale) → apre il terminale
```
### Setup (una tantum, dashboard Cloudflare Zero Trust)
1. **Networks → Tunnels → Create a tunnel** (tipo *Cloudflared*). Copia il
**token** e mettilo in `.env` come `TUNNEL_TOKEN=...`.
2. Nel tunnel, **Public Hostname**: `mcp.pawsolutions.it` → **Service**
`http://localhost:3939`. (Il record DNS viene creato da Cloudflare.)
3. **Access → Applications → Add → Self-hosted**, dominio `mcp.pawsolutions.it`.
Aggiungi una **policy** che consenta solo la tua identità (es. *Emails* = la
tua email; metodo di login Google/GitHub/OTP). Access gestirà l'intero flusso
OAuth per il client MCP.
### Avvio
```bash
npm start # server MCP sull'host (HOST=0.0.0.0)
docker compose up -d # avvia il tunnel cloudflared
```
### Aggiungere il connettore (Claude Desktop / mobile)
Connettori → "Aggiungi connettore personalizzato" → URL
`https://mcp.pawsolutions.it/mcp`, **campi OAuth vuoti**. Claude aprirà un login
Cloudflare nel browser: autenticati una volta → Access rilascia i token → solo la
tua identità potrà usare il server.
### ⚠️ Sicurezza
- Il server MCP **non ha autenticazione propria**: l'autenticazione è demandata a
**Cloudflare Access**. Senza una policy Access corretta, l'URL pubblico esporrebbe
un launcher di terminali a chiunque — la policy è **obbligatoria**.
- Difesa in profondità (opzionale): il server può validare l'header
`Cf-Access-Jwt-Assertion` iniettato da Access.
- `HOST=0.0.0.0` espone la `3939` in chiaro sulla LAN (per il bridge Desktop e per
cloudflared): se non ti serve l'accesso LAN, limitala con un firewall.
> La vecchia variante con Caddy + certificato self-signed (`Caddyfile`,
> `install_certificate.sh`) **non** funziona con i connettori remoti (cert non
> pubblico) ed è superata da questo setup. I file restano nel repo solo come
> riferimento per un eventuale client che giri sullo stesso host.
## Note tecniche
- Ogni connessione SSE crea un'istanza isolata del server MCP, indicizzata per `sessionId`.
- Il comando viene generato in uno **script temporaneo** per evitare problemi di
escaping su più livelli (`wt.exe` → `wsl.exe` → `bash`); il prompt è quotato in POSIX.
- Il path assoluto di `claude` viene risolto lato server (ereditando nvm), così
il terminale appena aperto non deve ricaricare l'ambiente.
- Gli errori di spawn sono gestiti per non far cadere il server.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues