Skip to main content
Glama
kongo97

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.