Skip to main content
Glama
rbenhaga
by rbenhaga

shopping-radar 🛒🔎

Serveur MCP qui permet à Claude de récupérer les annonces d'un produit sur plusieurs places de marché françaises et de les analyser rigoureusement : prix, date, livraison, et distance au point de référence (Montpellier) quand l'article n'est pas livrable.

Pensé pour trouver le meilleur rapport qualité-prix (ex. un cadeau), en comparant l'occasion au prix du neuf.

Sources (8)

Source

Type

Clé requise

État

Leboncoin (direct)

occasion

— (intermittent, DataDome)

✅ actif

Leboncoin (Apify)

occasion fiable

APIFY_TOKEN (~1 $/1000 résultats)

✅ testé, opt-in

Vinted

occasion

✅ actif

Dealabs

deals neuf / erreurs de prix

✅ actif

eBay

occasion + reconditionné

EBAY_APP_ID + EBAY_CERT_ID (gratuit)

🔌 sur clé

Google Shopping

neuf (multi-marchands)

SERPAPI_KEY (gratuit limité)

🔌 sur clé

Idealo

comparateur neuf

APIFY_TOKEN (crédit gratuit)

🔌 sur clé

Keepa

Amazon neuf + historique

KEEPA_API_KEY (payant)

🔌 sur clé

Back Market

reconditionné garanti

APIFY_TOKEN + BACKMARKET_APIFY_ACTOR

🔌 sur clé

Les 3 premières fonctionnent sans aucune clé. Les autres s'activent en ajoutant la clé correspondante dans .env. Aucune dépendance Python supplémentaire n'est nécessaire pour les activer (sauf Keepa) — tout passe par httpx.

Couverture par usage

  • Occasion : Leboncoin, Vinted, eBay

  • Reconditionné : Back Market, eBay

  • Neuf / prix de référence : Google Shopping (Amazon, Fnac, Darty, Boulanger…), Idealo, Keepa, Dealabs

Related MCP server: MCP Shop Server

Pipeline d'analyse & qualité des données

analyze enchaîne : recherche multi-sources → déduplication → filtre logistique (Montpellier) → filtre de pertinence → enrichissement qualité → tri par score composite. Chaque offre gardée est enrichie de :

  • condition_label — état normalisé sur une échelle standard (neuf, comme neuf, très bon, bon, correct, reconditionné, pour pièces).

  • is_bundle — détecte les lots/packs (« + 2 batteries », « pack complet »).

  • risk_level (ok/faible/moyen/eleve) + risk_flags : prix_tres_bas (sous médiane − 30 %), marque_incoherente (marque ≠ produit recherché), import_hors_fr (titre en langue étrangère → transfrontalier), vendeur_inconnu.

  • deal_score — note composite 0-100 où le risque PRIME sur le prix : la valeur-prix est plafonnée sous le seuil « trop beau pour être vrai » (pas de bonus pour les prix d'arnaque) et un malus de risque (jusqu'à −45) écrase le bonus prix. Pondération : prix vs neuf (50) + état (20) + proximité (15) + confiance vendeur (10) − risque.

  • Segmentation par variante : les stats (médiane, seuil « trop bas ») sont calculées par segment (sous-modèle × premium/standard), pas sur un pool qui mélangerait X4 nue / Adventure / Bike… Le seuil bas est auto-calibré par z-score robuste (médiane − k·MAD intra-segment), au lieu d'un ratio fixe.

  • Détection de mislabel : une variante premium (« Adventure », « Bike »…) affichée sous le prix d'une version de base → flag mislabel_suspect (résolu sans référence externe, par comparaison inter-segments).

  • Seuils configurables : RISK_LOW_PRICE_RATIO, RISK_MAD_K, IMPORT_MARKERS, PREMIUM_KEYWORDS.

Limites encore ouvertes (assumées) : (1) la validation du modèle de risque repose sur des tests unitaires (change-detectors), pas sur un jeu labellisé précision/rappel ; (2) les stats vendeur (note, ancienneté, dernière connexion) et la fraîcheur/statut vendu des annonces ne sont pas encore exploitées — ce sont les signaux anti-fraude les plus forts ; (3) le score n'intègre pas encore garantie FR / retour / complétude accessoires.

  • also_on — autres sources où l'article a été repéré (déduplication inter-sources).

stats remonte aussi duplicates_removed, suspicious_count, new_reference_price.

Tests : python tests/test_core.py (tests déterministes, sans réseau).

Validation (au-delà des tests unitaires) : python eval/score.py eval/gold.jsonl mesure précision/rappel sur un jeu labellisé (suspect vs légit) + segmentation

  • faux positifs de flag — ce que les tests unitaires (change-detectors) ne voient pas. C'est ce harness qui a chiffré puis validé la correction du faux positif « prix négociable ». Gold set actuel = jouet (24 lignes) ; cible avant tout SaaS : 40-60 annonces réelles labellisées.

Vers un produit (SaaS) : voir docs/AUDIT.md (audit du code), docs/ARCHITECTURE.md (passage stateless→stateful : Postgres

  • file de jobs + précalcul) et db/schema.sql. Le moteur actuel devient la couche worker, on ne le réécrit pas.

Sécurité free tier (quotas)

Un garde-fou (core/quota.py) compte les appels par provider et bloque proprement avant de dépasser la limite gratuite (pas de facturation surprise). Usage persisté dans .cache/usage.json. Limites par défaut (juin 2026, surchargeables dans .env) :

Provider

Limite gratuite

Fenêtre

SerpAPI

250 recherches

mois

Apify (runs)

50 runs (vrai plafond = 5 $ de crédit)

mois

eBay Browse

5 000 appels

jour

Base Adresse Nationale

2 000 (poli)

jour

  • Sources coûteuses opt-in : Idealo, Back Market (runs Apify) et Keepa consomment du crédit → exclues des recherches par défaut. Pour les utiliser, les nommer : analyze(query, sources=["vinted","idealo"]). Google Shopping (SerpAPI, gratuit) fournit déjà le prix neuf de référence par défaut.

  • État des quotas visible via l'outil list_sources.

Fiabilité Leboncoin & proxy

Important : la lib lbc fait déjà le plus dur — impersonation TLS via curl_cffi (JA3 d'un vrai navigateur), amorçage du cookie DataDome (GET homepage), et utilisation de l'API mobile avec un User-Agent d'app. La couche TLS n'est donc PAS le problème. Les 503 intermittents viennent de la réputation de l'IP (ton IP perso flaggée après quelques requêtes). Le seul vrai levier = une IP propre.

Du gratuit au plus fiable :

  1. Retries + rotation de fingerprint (gratuit, activé) : LEBONCOIN_RETRIES=3.

  2. Proxy résidentiel FR : LEBONCOIN_PROXY=... ou un pool LEBONCOIN_PROXIES=p1,p2,... (rotation aléatoire). Options : LEBONCOIN_IMPERSONATE, LEBONCOIN_DATADOME_COOKIE.

  3. ✅ Source leboncoin_apify (la plus fiable, recommandée) : acteur Apify fatihtahta/leboncoin-fr-scraper (proxy résidentiel inclus ~1 $/1000 résultats). Testée, données riches (GPS, code postal, vendeur pro/particulier). Opt-in : analyze(query, sources=["leboncoin_apify","vinted","google_shopping"]).

⚠️ Pas de proxy gratuit fiable contre DataDome (les gratuits = IP datacenter, filtrées). Voie fiable « sans CB » : la source leboncoin_apify (crédit Apify).

Générique — fonctionne pour n'importe quel article

Rien n'est codé en dur pour un produit donné : la requête est un paramètre, le point de référence est dans .env (HOME_LAT/LNG), et les heuristiques sont génériques. Pour un domaine précis, on ajoute des mots-clés via .env : ACCESSORY_KEYWORDS=perche,objectif,trepied (photo) ou …=pompe,antivol (vélo), et BUNDLE_KEYWORDS=.... Le filtre de pertinence (is_relevant) s'adapte seul au modèle recherché (tokens chiffrés type « x4 », « 13 »).

Règle livraison / distance (mise à jour)

Une annonce est rejetée uniquement si elle est explicitement non livrable ET trop loin. Si la livraison est inconnue (cas fréquent Leboncoin), l'annonce est gardée avec un drapeau « (!) livraison à vérifier » plutôt que jetée — on ne perd pas une bonne affaire potentiellement livrable.

Géolocalisation

Si une annonce n'a pas de coordonnées GPS (fréquent sur Leboncoin), le code postal/ville est géocodé via l'API officielle Base Adresse Nationale (gratuite, sans clé) pour calculer la distance à Montpellier. Cache dans .cache/geocode.json.

Installation

python -m venv .venv
.venv\Scripts\activate          # Windows
pip install -r requirements.txt
copy .env.example .env          # puis éditer si besoin

Outils exposés à Claude (MCP)

  • list_sources() — sources disponibles + point de référence.

  • search_all(query, max_price?, sources?, limit_per_source?) — récupère les offres normalisées de toutes les sources actives (en parallèle).

  • analyze(query, max_price?, max_distance_km?, reference_price?, ...) — recherche + filtrage logistique (livrable OU à ≤ X km de Montpellier) + tri par prix et score de valeur vs prix neuf.

  • build_candidates(query, budget?, priorities?, top_k?, ...) — produit le « fichier de candidats » pour un agent décideur : normalise chaque offre (schéma stable, total_cost_normalized, warranty_monthsnull ≠ 0), met en quarantaine le risque élevé/mislabel (jamais transmis), et stratifie en top-K par (modèle × état). Renvoie aussi un brief de décision. Le déterministe ne tranche rien de subjectif — c'est le job de l'agent.

Brancher sur Claude Code / Claude Desktop

Ajouter dans la config MCP (ex. claude_desktop_config.json) :

{
  "mcpServers": {
    "shopping-radar": {
      "command": "python",
      "args": ["C:/Users/rayan/Desktop/Dev/Leboncoin/server.py"]
    }
  }
}

Puis, dans Claude : « Analyse les Insta360 X4 d'occasion sous 320 €, livrables ou à moins de 50 km de Montpellier. »

Règle métier « livraison / distance »

Une offre est gardée si :

  • elle est livrable, OU

  • sa distance au point de référence ≤ MAX_DISTANCE_KM (défaut 60 km).

Si livraison et distance sont inconnues, l'offre est gardée mais marquée « à vérifier » (on ne jette jamais une offre faute d'information).

Avertissements

  • Les clients Leboncoin/Vinted reposent sur des API non-officielles qui peuvent casser sans préavis et dont l'usage peut contrevenir aux CGU des sites. Réservé à un usage personnel et raisonnable.

  • L'analyse finale (recommandation) est faite par Claude ; ce serveur fournit la donnée normalisée et un pré-tri déterministe.

Architecture

server.py            # serveur MCP (outils list_sources / search_all / analyze)
core/
  models.py          # Offer normalisée + parsing prix/date
  geo.py             # distance Montpellier (haversine) + géocodage des CP manquants
  geocode.py         # géocodage Base Adresse Nationale (gratuit) + cache disque
  score.py           # filtre logistique/accessoires + scoring qualité-prix
sources/
  base.py            # interface Source
  leboncoin.py vinted.py dealabs.py           # gratuit
  leboncoin_apify.py                          # Leboncoin fiable (Apify, opt-in)
  ebay.py google_shopping.py idealo.py        # sur clé
  keepa.py backmarket.py                      # sur clé
F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rbenhaga/shopping-radar'

If you have feedback or need assistance with the MCP directory API, please join our Discord server