# 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 (validé de bout en bout, 2026-06) ✅ **Boucle complète testée sur le vrai compte** : lecture du menu (`menus-service/menus` → détails batch `recipes/recipes?ids=…`), filtrage coco (4/85 détectées, faux positifs des tags internes neutralisés), proposition classée, et **écriture réelle réussie** (`PUT /v1/carts/{week}`, HTTP 200) — sélection par index de course, ids de compte dérivés dynamiquement. ✅ **Auth autonome (pur HTTP)** : le token (30 min) est rafraîchi par un simple `POST /gw/refresh` (le endpoint que la SPA appelle), **sans navigateur**. Le refresh_token roule par fenêtres de 60 j, remises à zéro à chaque refresh → un homelab allumé reste authentifié **indéfiniment**, sans intervention ni re-sync. Le navigateur headless ne sert plus que de filet de secours. > ⚠️ La connexion **directe** automatisée (Playwright/Chromium qui remplit le formulaire) est > bloquée par l'anti-bot HelloFresh. La session se crée donc via **attache CDP à ton vrai Chrome** > (`tools/attach_capture.py`), où le login marche normalement. ## Architecture ``` Hermes ──HTTP──▶ server.py (FastMCP, :9200/mcp) ├─ hellofresh/auth.py session storage_state + refresh HTTP /gw/refresh ├─ hellofresh/api.py httpx : menu, détails, deliveries, PUT cart ├─ 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 ``` ### 2. Créer la session (login via TON Chrome, anti-bot contourné) Lance ton Chrome avec un port de debug + profil dédié (ta fenêtre Chrome habituelle peut rester ouverte), connecte-toi à HelloFresh (email + mot de passe), puis attache la capture : ```bash "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \ --remote-debugging-port=9222 --user-data-dir="$HOME/.hf-chrome-debug" \ https://www.hellofresh.fr/my-account/deliveries/menu python tools/attach_capture.py # capture trafic + exporte .session/storage_state.json ``` `storage_state.json` (cookies, ~60 j) est la session réutilisable. `config/endpoints.json` est déjà rempli ; rejoue `attach_capture` si l'API change (cf. `config/endpoints_discovered.json`). ### 3. Tester en local (headless, comme le homelab) ```bash python server.py # auth via storage_state, refresh token automatique ``` ## Déploiement homelab (Docker) `.session/` et `.env` ne sont **jamais** versionnés. Workflow : ```bash # 1. Sur le Mac : générer la session (cf. « Mise en route » §2 → .session/storage_state.json) # 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) # storage_state.json suffit (le homelab tourne headless et rafraîchit le token tout seul). scp .session/storage_state.json jerem@192.168.0.43:/AntiCoco/.session/ # 4. Sur le homelab : déployer ssh homelab cd /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é).