Skip to main content
Glama
nibu147
by nibu147
README.md
# fitdays-mcp (Cloudflare Worker)

MCP server remoto per l'API non ufficiale FitDays / iComon, ospitato su un
tuo Cloudflare Worker, con login OAuth 2.1 (nessuna API key statica da
incollare nel Worker: ogni utente che si connette fa login con la propria
email/password FitDays tramite una pagina `/authorize`).

Basato su [`roquerodrigo/fitdays-mcp-server`](https://github.com/roquerodrigo/fitdays-mcp-server)
(che gira solo in stdio/locale) e riadattato per Cloudflare Workers seguendo
lo stesso pattern usato da [`chrisdoc/hevy-mcp`](https://github.com/chrisdoc/hevy-mcp).

## Come funziona

- `src/index.ts` — compone [`@cloudflare/workers-oauth-provider`](https://github.com/cloudflare/workers-oauth-provider)
  (gestisce PKCE, dynamic client registration, token, discovery OAuth) con:
  - `src/authorize.ts` — la pagina `/authorize`: mostra un form email/password/region,
    verifica le credenziali con un vero login su FitDays, poi salva
    `{ fitdaysEmail, fitdaysPassword, fitdaysRegion }` come *grant props*
    (cifrate a riposo dalla libreria di Cloudflare).
  - `src/mcp-handler.ts` — l'handler `/mcp`: protetto automaticamente dal
    provider (richiede un bearer token OAuth valido), legge le credenziali
    dal grant e serve il protocollo MCP via `WebStandardStreamableHTTPServerTransport`
    (dalla stessa versione di `@modelcontextprotocol/sdk` usata dal repo originale).
- `src/server.ts` — gli stessi 5 tool dell'originale: `list_users`,
  `list_devices`, `get_weight_history`, `get_latest_weight`, `refresh_sync`.
- `src/fitdays-session.ts` — client FitDays con cache in memoria per-isolate
  (5 minuti), per evitare login + resync completo ad ogni chiamata quando il
  Worker isolate è "caldo".

Nessuna credenziale gira mai su un server terzo: il login avviene nel tuo
Worker, i dati FitDays restano tra il Worker e l'API FitDays.

## Deploy

Richiede Node.js ≥ 22 e un account Cloudflare gratuito.

```sh
npm ci
npx wrangler login

# Crea il namespace KV che l'OAuth provider usa per grant e token
npx wrangler kv namespace create OAUTH_KV
# copia l'"id" restituito in wrangler.jsonc -> kv_namespaces[0].id

npm run worker:dry-run   # opzionale: verifica il bundle localmente
npm run worker:deploy    # pubblica su https://fitdays-mcp.<tuo-subdomain>.workers.dev
```

## Collegare Claude (o un altro client MCP)

1. Claude.ai → Impostazioni → Connettori → Aggiungi connettore personalizzato
2. URL: `https://fitdays-mcp.<tuo-subdomain>.workers.dev/mcp`
3. Clicca "Connect": si apre la pagina `/authorize` del tuo Worker → inserisci
   email, password e regione FitDays → autorizzi

Da quel momento Claude può chiamare i 5 tool FitDays senza mai vedere la tua
password (resta nel grant OAuth cifrato dentro il tuo KV namespace).

## Sviluppo locale

```sh
npm run dev
```

`wrangler dev` avvia il Worker in locale con una KV namespace locale
simulata — utile per testare il form di login e i tool senza deployare.

## Note

- **Usa sempre `npm ci`, mai `npm install`.** `npm ci` installa esattamente le
  versioni del `package-lock.json` e verifica ogni pacchetto contro il suo hash
  SHA-512: se il contenuto pubblicato su npm cambia, l'installazione fallisce con
  `EINTEGRITY` invece di installare silenziosamente codice diverso. `npm install`
  può invece aggiornare le dipendenze. Committa sempre il `package-lock.json`.
- Le dipendenze runtime sono tutte pinnate a versione esatta (nessun `^`), quindi
  non c'è drift nemmeno rieseguendo l'install a distanza di mesi.
- Il Worker deployato è **autocontenuto**: `wrangler deploy` fa il bundle di tutto
  il codice al momento del deploy. A runtime non scarica nulla da npm o GitHub, e
  modifiche successive fatte dagli autori upstream non toccano il Worker già
  pubblicato.
- `nodejs_compat` è richiesto in `wrangler.jsonc` perché `fitdays-api` usa
  `node:crypto` (MD5 per il login) e `randomUUID()`.
- Le credenziali FitDays sono email+password (non una singola API key come
  Hevy): per questo il form `/authorize` fa un vero tentativo di login prima
  di completare l'autorizzazione, così credenziali sbagliate vengono
  rifiutate subito invece di fallire silenziosamente alla prima chiamata tool.

## Dove finisce la password

Due sole destinazioni:

1. **I server FitDays** (`online-{us,eu}.fitdays.cn`) — inevitabile, è l'unico
   modo di autenticarsi. Inviata come MD5(MD5(password+salt)), ma il salt è una
   costante pubblica, quindi va considerata equivalente a password in chiaro:
   non riusare altrove la password FitDays.
2. **Il tuo KV namespace su Cloudflare**, dentro i grant props (cifrati a riposo
   dalla libreria OAuth di Cloudflare).

Nessun'altra terza parte. `fitdays-api` ha zero dipendenze runtime e un solo
punto di rete in tutto il codice; non c'è telemetria, analytics o error
reporting in nessuno dei due repo upstream né in questo Worker.