shopping-radar

shopping-radar

Enables Claude to search and analyze product listings from multiple French marketplaces, evaluating price, delivery, and distance to a reference point to find the best value.

Category
访问服务器

README

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

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 <gold> mesure le rappel scam (la vraie cible) séparément du risky, avec IC95% Wilson (honnête sur petit N), + faux positifs sur les ok. Protocole de labellisation figé dans eval/LABELING.md (verdict ok/risky/scam, labellisation à l'aveugle).

Workflow gold réel :

  1. python eval/make_batch.py → eval/to_label.jsonl (batch réel, aveugle, stratifié-pour-faire-mal : imports/bundles/refurb/prix bas/phrases FR ambiguës).
  2. Labelliser à la main (verdict + reason) selon eval/LABELING.md.
  3. python eval/score.py eval/to_label.jsonl → vrais précision/rappel.

eval/gold.jsonl (25 lignes synthétiques) reste comme détecteur de régression (il a chiffré puis verrouillé le fix « prix négociable »). C'est un détecteur de modes d'échec, pas un go/no-go statistique au pourcent.

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_months où null ≠ 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é

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选