Skip to main content
Glama
README.md
# Apple Forme MCP

Serveur MCP qui expose 2 tools basés sur tes données Apple Watch (via l'app
**Health Auto Export**, puisqu'Apple Health n'a pas d'API web) :

- `resume_hebdo` : distance, allure, régularité, tendance
- `charge_entrainement` : ratio charge aiguë/chronique (ACWR), avec fallback
  si l'historique est trop court

S'y ajoute un **dashboard web** (`/dashboard`) servi par le même serveur :
stats filtrables par période (7/30/90 jours, tout) et par type d'exercice
(course, cyclisme, marche, yoga, cardio, pilates), avec comparaison vs la
période précédente et mode sombre. Consultable depuis n'importe quel appareil
du réseau local : `http://<ip-du-mac>:8000/dashboard`.

## Architecture

```
iPhone (Health Auto Export, même wifi que le Mac)
   --POST JSON--> receiver.py (FastAPI, sur le réseau local uniquement)
   --stocke--> forme.db (SQLite)
   --lu par--> mcp_server.py --> Claude
```

Pas de tunnel public ici : le webhook n'est joignable que depuis ton réseau
wifi local. C'est le choix le plus simple côté vie privée — tes données de
santé ne transitent par aucun service tiers. La contrepartie : la sync ne se
fait que quand ton iPhone et ton Mac sont sur le même wifi (typiquement chez
toi le soir), et ton Mac doit être allumé avec `receiver.py` lancé à ce
moment-là. Largement suffisant pour un résumé hebdo et un calcul ACWR, qui
n'ont pas besoin de données en temps réel.

## 1. Installer les dépendances

```bash
cd apple-forme-mcp
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# édite .env : mets un WEBHOOK_TOKEN aléatoire
python -c "import secrets; print(secrets.token_hex(24))"
```

## 2. Lancer le webhook receiver

```bash
uvicorn receiver:app --host 0.0.0.0 --port 8000
```

`--host 0.0.0.0` fait écouter `receiver.py` sur toutes les interfaces réseau
du Mac, donc y compris le wifi — c'est ce qui permet à l'iPhone de le joindre.

## 3. Trouver l'IP locale de ton Mac

```bash
ipconfig getifaddr en0
```

Ça renvoie une adresse du type `192.168.1.42`. C'est l'IP à utiliser dans
l'automatisation Health Auto Export (voir étape 4). Elle peut changer si ta
box réattribue les IP — si l'automatisation arrête de fonctionner du jour au
lendemain, reviens vérifier cette commande.

Pense à laisser ton Mac allumé (pas en veille) et `receiver.py` lancé au
moment où tu veux que la sync se fasse — par exemple le soir en rentrant de
ta sortie.

## 4. Configurer Health Auto Export sur l'iPhone

Dans l'app > Automations > New Automation :

- **Automation Type** : REST API
- **URL** : `http://192.168.1.42:8000/health-auto-export/webhook` (remplace
  par l'IP trouvée à l'étape 3)
- **Header** : `Authorization: Bearer <ton WEBHOOK_TOKEN>`
- **Data Type** : Workouts (décoche "Routes"/"GPS" — inutile pour les 2 tools
  et c'est la donnée la plus sensible de l'export)
- **Format** : JSON
- **Export Version** : 2
- **Sync Behavior** : "Since Last Sync"
- **Fréquence** : ex. toutes les 6h, ou 1x/jour

⚠️ Limites Apple à connaître : les automatisations ne tournent que quand le
téléphone est déverrouillé, et iOS limite l'exécution en arrière-plan — donc
attends-toi à un léger délai, pas du vrai temps réel.

Fais un premier **Manual Export** dans l'app pour peupler direct ta base avec
ton historique existant, plutôt que d'attendre que ça s'accumule au fil de
l'eau. Les automatisations ne proposent que des plages relatives ; pour un
gros historique, utilise plutôt la section **Exportations** de l'app (plage
de dates libre → fichier JSON), transfère le fichier sur le Mac, puis :

```bash
python import_file.py ~/Downloads/HealthAutoExport-*.json
```

Les doublons sont gérés (upsert par identifiant de séance) : réimporter des
données déjà connues est sans effet.

## 5. Lancer le serveur MCP

```bash
python mcp_server.py
```

Puis ajoute-le dans `claude_desktop_config.json` :

```json
{
  "mcpServers": {
    "apple-forme": {
      "command": "/chemin/absolu/vers/venv/bin/python",
      "args": ["/chemin/absolu/vers/apple-forme-mcp/mcp_server.py"]
    }
  }
}
```

## Limites connues / à améliorer

- **Charge de session** : approximée via `durée × (FC moyenne / 60)` faute de
  RPE façon Strava. À affiner avec un vrai TRIMP (Banister) une fois que tu
  as FC repos/FC max calibrées dans le code (`training_load.py`).
- **Fallback ACWR** : en dessous de 21 jours d'historique, le tool renvoie une
  tendance semaine/semaine précédente plutôt qu'un ratio non fiable.
- **Format d'export** : le code gère "Workouts v2". Si tu configures
  l'automatisation en v1, dis-le moi pour que j'adapte `store.py`.