- Endpoints découverts: menu (menus-service) + détails batch (recipes/recipes) - get_menu en 2 temps: menu (ids) -> batch détails (ingrédients/allergènes) - Fix faux positifs: exclusion sur ingrédients/allergènes/nom, plus sur les tags (HelloFresh pose un tag interne 'coconut' sur ~la moitié des recettes) - Token mis en cache (pas de navigateur si frais) - endpoints.json versionné (sans secret), semaine optionnelle (défaut = courante) - Testé: 4 recettes coco/85 détectées, shortlist classée, tous les outils MCP OK - set_selection (écriture) reste à découvrir sur un compte avec box active
103 lines
4.3 KiB
Markdown
103 lines
4.3 KiB
Markdown
# AntiCoco 🥥🚫
|
|
|
|
Serveur **MCP** qui donne accès à ton compte **HelloFresh** (France, `hellofresh.fr`) pour :
|
|
lire le menu de la semaine, **exclure des ingrédients** (la **noix de coco** en priorité),
|
|
**proposer une shortlist** de recettes, puis **enregistrer ta sélection** après confirmation.
|
|
|
|
Client MCP visé : **Hermes** (Nous Research), qui tourne sur le même homelab.
|
|
|
|
> ⚠️ HelloFresh n'a pas d'API publique. AntiCoco s'appuie sur l'API interne `gw/` du site
|
|
> (non documentée, susceptible de changer) — **usage strictement personnel**.
|
|
|
|
## État (testé en local, 2026-06)
|
|
|
|
✅ **Lecture validée sur le menu réel** : login Playwright + token, menu de la semaine
|
|
(`menus-service/menus`) → détails en 1 appel batch (`recipes/recipes?ids=…`), filtrage coco
|
|
correct (4 recettes coco détectées sur 85, faux positifs des tags internes neutralisés),
|
|
scoring par préférences, gestion de la liste d'exclusion. Serveur MCP fonctionnel (handshake OK).
|
|
|
|
⏳ **Écriture (`hf_confirm_selection`) à finaliser** : l'endpoint d'enregistrement de la
|
|
sélection (`set_selection`) n'a pas pu être capturé (compte de test sans abonnement actif).
|
|
À découvrir via `discover_api.py` sur un compte avec une box modifiable (changer une recette
|
|
pour observer l'appel `PUT`/`POST`), puis renseigner `config/endpoints.json`.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Hermes ──HTTP──▶ server.py (FastMCP, :9200/mcp)
|
|
├─ hellofresh/auth.py login Playwright + capture du bearer token
|
|
├─ hellofresh/api.py appels httpx vers le gateway HelloFresh
|
|
├─ hellofresh/filter.py exclusion (coco !) + scoring préférences
|
|
└─ config/ excludes.json · prefs.json · endpoints.json
|
|
```
|
|
|
|
## Mise en route
|
|
|
|
### 1. Installer
|
|
```bash
|
|
pip install -r requirements.txt
|
|
playwright install chromium
|
|
cp .env.example .env # remplir HF_EMAIL / HF_PASSWORD (optionnels, fallback re-login)
|
|
```
|
|
|
|
### 2. Découvrir les endpoints (étape 0, en local, fenêtre visible)
|
|
```bash
|
|
ANTICOCO_HEADLESS=0 python tools/discover_api.py
|
|
```
|
|
Connecte-toi, ouvre le menu de la semaine, change une recette pour capturer l'écriture, puis
|
|
Entrée. Vérifie/complète ensuite `config/endpoints.json` (généré depuis le trafic capturé,
|
|
voir aussi `.session/discovery_log.json`).
|
|
|
|
### 3. Tester en local
|
|
```bash
|
|
ANTICOCO_HEADLESS=0 python server.py # 1er run : login dans la fenêtre si besoin
|
|
```
|
|
Le login crée `.session/profile` (profil Playwright persistant) — réutilisé ensuite headless.
|
|
|
|
## Déploiement homelab (Docker)
|
|
|
|
`.session/` et `.env` ne sont **jamais** versionnés. Workflow :
|
|
|
|
```bash
|
|
# 1. Sur le Mac : générer une session connectée (fenêtre visible)
|
|
ANTICOCO_HEADLESS=0 python server.py # se connecter, puis Ctrl-C
|
|
|
|
# 2. Pousser le code
|
|
git add -A && git commit -m "..." && git push
|
|
|
|
# 3. Synchroniser la session vers le homelab (NON versionnée ; endpoints.json est dans git)
|
|
scp -r .session jerem@192.168.0.43:<path>/AntiCoco/
|
|
|
|
# 4. Sur le homelab : déployer
|
|
ssh homelab
|
|
cd <path>/AntiCoco && git pull && docker compose up -d --build
|
|
```
|
|
|
|
Vérifier : `curl -s http://127.0.0.1:9200/mcp` (le serveur répond au handshake MCP).
|
|
|
|
## Intégration Hermes
|
|
|
|
Enregistrer AntiCoco dans la config MCP de Hermes (côté homelab), URL
|
|
`http://127.0.0.1:9200/mcp` (transport streamable-http).
|
|
|
|
> Si Hermes n'accepte que le **stdio**, changer la dernière ligne de `server.py`
|
|
> (`mcp.run(transport="stdio")`) et lancer le serveur en sous-processus — le reste est identique.
|
|
|
|
## Outils MCP exposés
|
|
|
|
| Outil | Rôle |
|
|
|-------|------|
|
|
| `hf_auth_status()` | état de connexion |
|
|
| `hf_login()` | (re)connexion + capture token |
|
|
| `hf_list_weeks()` | semaines modifiables |
|
|
| `hf_get_menu(week)` | toutes les recettes, avec flag `contains_excluded` |
|
|
| `hf_propose(week, count=0)` | shortlist **sans coco**, classée par préférences |
|
|
| `hf_confirm_selection(week, recipe_ids)` | **écrit** la sélection (refuse la coco) |
|
|
| `hf_get_excludes()` / `hf_add_exclude(term)` / `hf_remove_exclude(term)` | gérer la liste d'exclusion |
|
|
|
|
## Configuration
|
|
|
|
- `config/excludes.json` — ingrédients bannis (matching insensible casse/accents). Coco déjà listée.
|
|
- `config/prefs.json` — mots-clés `liked`/`disliked` pour classer les propositions.
|
|
- `config/endpoints.json` — URLs gateway réelles (généré par `discover_api.py`, non versionné).
|