heurix-mcp-server 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
REFERENCEMENT-ANNUAIRES.md
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: heurix-mcp-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Serveur MCP pour Heurix — recherche et classement de catalogues produits techniques en langage naturel
|
|
5
|
+
Project-URL: Homepage, https://heurix.fr
|
|
6
|
+
Project-URL: Documentation, https://heurix.fr/docs.html#ep-mcp
|
|
7
|
+
Project-URL: Repository, https://github.com/flahaut-alexis/heurix-mcp-server
|
|
8
|
+
Author-email: Alexis Flahaut <contact@heurix.fr>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: catalog,ecommerce,mcp,model-context-protocol,product-search,search
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: httpx>=0.27
|
|
18
|
+
Requires-Dist: mcp>=1.2.0
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Serveur MCP Heurix
|
|
22
|
+
|
|
23
|
+
Permet à un agent IA (Claude Desktop, Cursor, ou tout autre client MCP)
|
|
24
|
+
d'interroger directement un catalogue Heurix — recherche, parcours par
|
|
25
|
+
catégorie, statistiques — sans que l'agent ait à connaître l'API REST.
|
|
26
|
+
Chantier 6.1 de la roadmap, 24 juillet 2026.
|
|
27
|
+
|
|
28
|
+
Trois tools exposés :
|
|
29
|
+
- **`heurix_search`** — recherche par mot-clé, tolérante aux fautes de frappe
|
|
30
|
+
- **`heurix_browse`** — liste les produits d'une catégorie, avec tri (stock, prix, popularité...)
|
|
31
|
+
- **`heurix_catalog_stats`** — liste les catalogues et leurs catégories disponibles
|
|
32
|
+
|
|
33
|
+
Une fine couche au-dessus de l'API REST Heurix existante — aucune nouvelle
|
|
34
|
+
logique métier, juste une nouvelle façade que les agents IA savent parler
|
|
35
|
+
nativement.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install -r requirements.txt
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Testable en local avant de le brancher à un client :
|
|
44
|
+
```bash
|
|
45
|
+
HEURIX_API_KEY=hx_votre_cle python3 server.py
|
|
46
|
+
```
|
|
47
|
+
(Le serveur attend alors une connexion MCP sur stdin/stdout — `Ctrl+C` pour arrêter. C'est normal qu'il ne "fasse rien" visuellement : un client MCP doit s'y connecter pour que quoi que ce soit se passe.)
|
|
48
|
+
|
|
49
|
+
## Configuration dans Claude Desktop
|
|
50
|
+
|
|
51
|
+
1. Ouvrez Claude Desktop → **Réglages → Développeur → Modifier la configuration** (ça crée le fichier s'il n'existe pas encore)
|
|
52
|
+
2. Le fichier se trouve à :
|
|
53
|
+
- macOS : `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
54
|
+
- Windows : `%APPDATA%\Claude\claude_desktop_config.json`
|
|
55
|
+
3. Ajoutez (ou complétez s'il existe déjà d'autres serveurs) :
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"mcpServers": {
|
|
60
|
+
"heurix": {
|
|
61
|
+
"command": "/usr/bin/python3",
|
|
62
|
+
"args": ["/chemin/complet/vers/heurix-mcp-server/server.py"],
|
|
63
|
+
"env": {
|
|
64
|
+
"HEURIX_API_KEY": "hx_votre_cle_api",
|
|
65
|
+
"HEURIX_API_BASE": "https://api.heurix.fr"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Important** : utilisez le **chemin complet** vers `python3` (`which python3` dans un terminal pour le trouver), pas juste `python3` — Claude Desktop lance la configuration avec un PATH minimal, une commande courte qui fonctionne dans votre terminal peut échouer silencieusement ici. Même chose pour le chemin vers `server.py` : complet, pas relatif.
|
|
73
|
+
|
|
74
|
+
4. Redémarrez Claude Desktop entièrement (pas juste fermer la fenêtre)
|
|
75
|
+
5. Un nouvel outil (icône 🔌 ou menu MCP selon la version) doit lister `heurix_search`, `heurix_browse`, `heurix_catalog_stats`
|
|
76
|
+
|
|
77
|
+
## Configuration dans Cursor
|
|
78
|
+
|
|
79
|
+
Même structure de fichier, deux emplacements possibles :
|
|
80
|
+
- `.cursor/mcp.json` à la racine d'un projet (pour un serveur propre à ce projet)
|
|
81
|
+
- `~/.cursor/mcp.json` (global, disponible dans tous les projets)
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"mcpServers": {
|
|
86
|
+
"heurix": {
|
|
87
|
+
"command": "/usr/bin/python3",
|
|
88
|
+
"args": ["/chemin/complet/vers/heurix-mcp-server/server.py"],
|
|
89
|
+
"env": {
|
|
90
|
+
"HEURIX_API_KEY": "hx_votre_cle_api",
|
|
91
|
+
"HEURIX_API_BASE": "https://api.heurix.fr"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Ensuite : **Réglages Cursor → Tools & MCP**, vérifiez que "Enable MCP Servers" est coché, et que `heurix` apparaît avec un point vert (connecté). Si rien n'apparaît après un redémarrage, le panneau **Output → MCP** affiche les logs bruts du serveur — souvent plus parlant que l'interface elle-même pour diagnostiquer.
|
|
99
|
+
|
|
100
|
+
## Exemple concret
|
|
101
|
+
|
|
102
|
+
**Ce qu'un utilisateur tape dans Claude Desktop**, sans rien connaître de l'API Heurix :
|
|
103
|
+
|
|
104
|
+
> J'ai un catalogue Heurix qui s'appelle quincaillerie-demo. Est-ce que j'ai des vis M8 en stock, et à quel prix ?
|
|
105
|
+
|
|
106
|
+
**Ce qui se passe côté agent** (invisible pour l'utilisateur, montré ici pour comprendre) :
|
|
107
|
+
1. Claude appelle `heurix_search(catalog="quincaillerie-demo", query="vis M8")`
|
|
108
|
+
2. Le serveur MCP relaie vers `POST https://api.heurix.fr/v1/index/quincaillerie-demo/search`
|
|
109
|
+
3. La réponse JSON (hits, scores, stock, prix) revient à Claude
|
|
110
|
+
|
|
111
|
+
**Réponse type de Claude Desktop à l'utilisateur** :
|
|
112
|
+
|
|
113
|
+
> Oui, vous avez deux références de vis M8 en stock dans quincaillerie-demo :
|
|
114
|
+
>
|
|
115
|
+
> - **Vis M8 x 20 - Inox A2** — 120 en stock, 5,90 €
|
|
116
|
+
> - **Vis M8 x 30 - Inox A2** — 45 en stock, 7,90 €
|
|
117
|
+
>
|
|
118
|
+
> Voulez-vous que je regarde aussi si l'une d'elles a un stock faible, ou que je compare avec une autre référence ?
|
|
119
|
+
|
|
120
|
+
Aucune ligne de code, aucun appel curl — l'utilisateur pose une question en
|
|
121
|
+
langage naturel, l'agent fait le pont vers l'API.
|
|
122
|
+
|
|
123
|
+
## Sécurité
|
|
124
|
+
|
|
125
|
+
`HEURIX_API_KEY` vit uniquement dans la configuration du client MCP (fichier
|
|
126
|
+
local sur la machine de l'utilisateur), jamais en argument de ligne de
|
|
127
|
+
commande, jamais transmise en clair dans un appel de tool — le serveur la
|
|
128
|
+
lit une fois au démarrage depuis l'environnement et l'utilise pour chaque
|
|
129
|
+
appel à l'API Heurix.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Serveur MCP Heurix
|
|
2
|
+
|
|
3
|
+
Permet à un agent IA (Claude Desktop, Cursor, ou tout autre client MCP)
|
|
4
|
+
d'interroger directement un catalogue Heurix — recherche, parcours par
|
|
5
|
+
catégorie, statistiques — sans que l'agent ait à connaître l'API REST.
|
|
6
|
+
Chantier 6.1 de la roadmap, 24 juillet 2026.
|
|
7
|
+
|
|
8
|
+
Trois tools exposés :
|
|
9
|
+
- **`heurix_search`** — recherche par mot-clé, tolérante aux fautes de frappe
|
|
10
|
+
- **`heurix_browse`** — liste les produits d'une catégorie, avec tri (stock, prix, popularité...)
|
|
11
|
+
- **`heurix_catalog_stats`** — liste les catalogues et leurs catégories disponibles
|
|
12
|
+
|
|
13
|
+
Une fine couche au-dessus de l'API REST Heurix existante — aucune nouvelle
|
|
14
|
+
logique métier, juste une nouvelle façade que les agents IA savent parler
|
|
15
|
+
nativement.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install -r requirements.txt
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Testable en local avant de le brancher à un client :
|
|
24
|
+
```bash
|
|
25
|
+
HEURIX_API_KEY=hx_votre_cle python3 server.py
|
|
26
|
+
```
|
|
27
|
+
(Le serveur attend alors une connexion MCP sur stdin/stdout — `Ctrl+C` pour arrêter. C'est normal qu'il ne "fasse rien" visuellement : un client MCP doit s'y connecter pour que quoi que ce soit se passe.)
|
|
28
|
+
|
|
29
|
+
## Configuration dans Claude Desktop
|
|
30
|
+
|
|
31
|
+
1. Ouvrez Claude Desktop → **Réglages → Développeur → Modifier la configuration** (ça crée le fichier s'il n'existe pas encore)
|
|
32
|
+
2. Le fichier se trouve à :
|
|
33
|
+
- macOS : `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
34
|
+
- Windows : `%APPDATA%\Claude\claude_desktop_config.json`
|
|
35
|
+
3. Ajoutez (ou complétez s'il existe déjà d'autres serveurs) :
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"heurix": {
|
|
41
|
+
"command": "/usr/bin/python3",
|
|
42
|
+
"args": ["/chemin/complet/vers/heurix-mcp-server/server.py"],
|
|
43
|
+
"env": {
|
|
44
|
+
"HEURIX_API_KEY": "hx_votre_cle_api",
|
|
45
|
+
"HEURIX_API_BASE": "https://api.heurix.fr"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Important** : utilisez le **chemin complet** vers `python3` (`which python3` dans un terminal pour le trouver), pas juste `python3` — Claude Desktop lance la configuration avec un PATH minimal, une commande courte qui fonctionne dans votre terminal peut échouer silencieusement ici. Même chose pour le chemin vers `server.py` : complet, pas relatif.
|
|
53
|
+
|
|
54
|
+
4. Redémarrez Claude Desktop entièrement (pas juste fermer la fenêtre)
|
|
55
|
+
5. Un nouvel outil (icône 🔌 ou menu MCP selon la version) doit lister `heurix_search`, `heurix_browse`, `heurix_catalog_stats`
|
|
56
|
+
|
|
57
|
+
## Configuration dans Cursor
|
|
58
|
+
|
|
59
|
+
Même structure de fichier, deux emplacements possibles :
|
|
60
|
+
- `.cursor/mcp.json` à la racine d'un projet (pour un serveur propre à ce projet)
|
|
61
|
+
- `~/.cursor/mcp.json` (global, disponible dans tous les projets)
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"heurix": {
|
|
67
|
+
"command": "/usr/bin/python3",
|
|
68
|
+
"args": ["/chemin/complet/vers/heurix-mcp-server/server.py"],
|
|
69
|
+
"env": {
|
|
70
|
+
"HEURIX_API_KEY": "hx_votre_cle_api",
|
|
71
|
+
"HEURIX_API_BASE": "https://api.heurix.fr"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Ensuite : **Réglages Cursor → Tools & MCP**, vérifiez que "Enable MCP Servers" est coché, et que `heurix` apparaît avec un point vert (connecté). Si rien n'apparaît après un redémarrage, le panneau **Output → MCP** affiche les logs bruts du serveur — souvent plus parlant que l'interface elle-même pour diagnostiquer.
|
|
79
|
+
|
|
80
|
+
## Exemple concret
|
|
81
|
+
|
|
82
|
+
**Ce qu'un utilisateur tape dans Claude Desktop**, sans rien connaître de l'API Heurix :
|
|
83
|
+
|
|
84
|
+
> J'ai un catalogue Heurix qui s'appelle quincaillerie-demo. Est-ce que j'ai des vis M8 en stock, et à quel prix ?
|
|
85
|
+
|
|
86
|
+
**Ce qui se passe côté agent** (invisible pour l'utilisateur, montré ici pour comprendre) :
|
|
87
|
+
1. Claude appelle `heurix_search(catalog="quincaillerie-demo", query="vis M8")`
|
|
88
|
+
2. Le serveur MCP relaie vers `POST https://api.heurix.fr/v1/index/quincaillerie-demo/search`
|
|
89
|
+
3. La réponse JSON (hits, scores, stock, prix) revient à Claude
|
|
90
|
+
|
|
91
|
+
**Réponse type de Claude Desktop à l'utilisateur** :
|
|
92
|
+
|
|
93
|
+
> Oui, vous avez deux références de vis M8 en stock dans quincaillerie-demo :
|
|
94
|
+
>
|
|
95
|
+
> - **Vis M8 x 20 - Inox A2** — 120 en stock, 5,90 €
|
|
96
|
+
> - **Vis M8 x 30 - Inox A2** — 45 en stock, 7,90 €
|
|
97
|
+
>
|
|
98
|
+
> Voulez-vous que je regarde aussi si l'une d'elles a un stock faible, ou que je compare avec une autre référence ?
|
|
99
|
+
|
|
100
|
+
Aucune ligne de code, aucun appel curl — l'utilisateur pose une question en
|
|
101
|
+
langage naturel, l'agent fait le pont vers l'API.
|
|
102
|
+
|
|
103
|
+
## Sécurité
|
|
104
|
+
|
|
105
|
+
`HEURIX_API_KEY` vit uniquement dans la configuration du client MCP (fichier
|
|
106
|
+
local sur la machine de l'utilisateur), jamais en argument de ligne de
|
|
107
|
+
commande, jamais transmise en clair dans un appel de tool — le serveur la
|
|
108
|
+
lit une fois au démarrage depuis l'environnement et l'utilise pour chaque
|
|
109
|
+
appel à l'API Heurix.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Paquet installable du serveur MCP Heurix.
|
|
2
|
+
#
|
|
3
|
+
# POURQUOI CE FICHIER : les annuaires MCP (mcp.so, Smithery, Glama) verifient
|
|
4
|
+
# un serveur en INTROSPECTANT un processus qu'ils lancent. Un zip telecharge
|
|
5
|
+
# depuis un site ne leur suffit pas -- il leur faut une commande executable.
|
|
6
|
+
# Publie sur PyPI, le serveur devient lancable par `uvx heurix-mcp-server`,
|
|
7
|
+
# ce que tout crawler d'annuaire sait faire.
|
|
8
|
+
[build-system]
|
|
9
|
+
requires = ["hatchling"]
|
|
10
|
+
build-backend = "hatchling.build"
|
|
11
|
+
|
|
12
|
+
[project]
|
|
13
|
+
name = "heurix-mcp-server"
|
|
14
|
+
version = "0.1.0"
|
|
15
|
+
description = "Serveur MCP pour Heurix — recherche et classement de catalogues produits techniques en langage naturel"
|
|
16
|
+
readme = "README.md"
|
|
17
|
+
requires-python = ">=3.10"
|
|
18
|
+
license = { text = "MIT" }
|
|
19
|
+
authors = [{ name = "Alexis Flahaut", email = "contact@heurix.fr" }]
|
|
20
|
+
keywords = ["mcp", "model-context-protocol", "search", "ecommerce", "catalog", "product-search"]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 4 - Beta",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Topic :: Internet :: WWW/HTTP :: Indexing/Search",
|
|
27
|
+
]
|
|
28
|
+
dependencies = ["mcp>=1.2.0", "httpx>=0.27"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://heurix.fr"
|
|
32
|
+
Documentation = "https://heurix.fr/docs.html#ep-mcp"
|
|
33
|
+
Repository = "https://github.com/flahaut-alexis/heurix-mcp-server"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
heurix-mcp-server = "server:main"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
include = ["server.py"]
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Serveur MCP pour Heurix — chantier 6.1 de la roadmap (24 juillet 2026).
|
|
3
|
+
|
|
4
|
+
Enveloppe l'API REST Heurix existante en "tools" qu'un agent IA (Claude
|
|
5
|
+
Desktop, Cursor, un agent interne via le SDK MCP) peut découvrir et
|
|
6
|
+
appeler directement. Pas de nouvelle logique métier ici : une nouvelle
|
|
7
|
+
façade sur ce qui existe déjà (recherche, browse, stats catalogue).
|
|
8
|
+
|
|
9
|
+
Configuration — deux variables d'environnement, jamais codées en dur ni
|
|
10
|
+
passées en clair dans un appel de tool :
|
|
11
|
+
HEURIX_API_KEY votre clé API Heurix (hx_...)
|
|
12
|
+
HEURIX_API_BASE URL de base de l'API (défaut : https://api.heurix.fr)
|
|
13
|
+
|
|
14
|
+
Lancement local (test manuel) :
|
|
15
|
+
HEURIX_API_KEY=hx_... python3 server.py
|
|
16
|
+
|
|
17
|
+
Voir README.md pour la configuration dans Claude Desktop et Cursor.
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
import httpx
|
|
25
|
+
from mcp.server.fastmcp import FastMCP
|
|
26
|
+
|
|
27
|
+
HEURIX_API_KEY = os.environ.get("HEURIX_API_KEY", "").strip()
|
|
28
|
+
HEURIX_API_BASE = os.environ.get("HEURIX_API_BASE", "https://api.heurix.fr").rstrip("/")
|
|
29
|
+
|
|
30
|
+
if not HEURIX_API_KEY:
|
|
31
|
+
print(
|
|
32
|
+
"HEURIX_API_KEY manquante — définissez-la dans la configuration MCP de "
|
|
33
|
+
"votre client (Claude Desktop, Cursor...), jamais en argument de ligne "
|
|
34
|
+
"de commande ni codée en dur dans ce fichier.",
|
|
35
|
+
file=sys.stderr,
|
|
36
|
+
)
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
mcp = FastMCP(
|
|
40
|
+
"heurix",
|
|
41
|
+
instructions=(
|
|
42
|
+
"Outils pour interroger un catalogue produit indexé sur Heurix — un "
|
|
43
|
+
"moteur de recherche et de classement pour catalogues techniques "
|
|
44
|
+
"(regex sur références produit, facettes, tri par catégorie). "
|
|
45
|
+
"Commencez par heurix_catalog_stats si vous ne connaissez pas encore "
|
|
46
|
+
"les catalogues, catégories ou attributs disponibles sur ce compte : "
|
|
47
|
+
"les noms de catalogue et de catégorie sont sensibles à la casse et "
|
|
48
|
+
"doivent être exacts, pas devinés."
|
|
49
|
+
),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _auth_headers() -> dict:
|
|
54
|
+
return {"Authorization": f"Bearer {HEURIX_API_KEY}"}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _handle_response(r: httpx.Response) -> dict:
|
|
58
|
+
"""Ne masque jamais une erreur API derrière un plantage générique — un
|
|
59
|
+
agent doit pouvoir comprendre, et au besoin expliquer à l'utilisateur,
|
|
60
|
+
ce qui s'est mal passé (catalogue introuvable, quota dépassé, accès
|
|
61
|
+
Browse non inclus dans le plan...) plutôt que recevoir une exception
|
|
62
|
+
opaque."""
|
|
63
|
+
if r.status_code >= 400:
|
|
64
|
+
try:
|
|
65
|
+
detail = r.json().get("detail", r.text)
|
|
66
|
+
except Exception: # noqa: BLE001 — reponse non-JSON, on renvoie le texte brut
|
|
67
|
+
detail = r.text
|
|
68
|
+
return {"error": True, "status_code": r.status_code, "detail": detail}
|
|
69
|
+
return r.json()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def _get(path: str, params: dict | None = None) -> dict:
|
|
73
|
+
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
74
|
+
r = await client.get(f"{HEURIX_API_BASE}{path}", headers=_auth_headers(), params=params or {})
|
|
75
|
+
return _handle_response(r)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def _post(path: str, json_body: dict) -> dict:
|
|
79
|
+
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
80
|
+
r = await client.post(f"{HEURIX_API_BASE}{path}", headers=_auth_headers(), json=json_body)
|
|
81
|
+
return _handle_response(r)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@mcp.tool()
|
|
85
|
+
async def heurix_search(catalog: str, query: str, filters: list[str] | None = None, limit: int = 10) -> dict:
|
|
86
|
+
"""Recherche des produits dans un catalogue Heurix par mot-clé, avec
|
|
87
|
+
tolérance aux fautes de frappe et reconnaissance des références
|
|
88
|
+
techniques (diamètres, longueurs, matières, ISBN...). Utilisez
|
|
89
|
+
heurix_catalog_stats d'abord si le nom exact du catalogue n'est pas
|
|
90
|
+
déjà connu.
|
|
91
|
+
|
|
92
|
+
La réponse peut inclure `suggested_category` si un mot de la requête
|
|
93
|
+
recoupe une catégorie Browse connue — utile pour proposer "cherchiez-
|
|
94
|
+
vous plutôt dans telle catégorie ?", ne change jamais les résultats
|
|
95
|
+
eux-mêmes.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
catalog: Nom exact du catalogue à interroger.
|
|
99
|
+
query: Texte de recherche, tel qu'un utilisateur le taperait —
|
|
100
|
+
les fautes de frappe et formats différents sont tolérés par
|
|
101
|
+
le moteur, pas la peine de les corriger avant d'appeler.
|
|
102
|
+
filters: Liste optionnelle de filtres exacts sur des annotations
|
|
103
|
+
connues (ex. ["DIAM_M8"]). Laisser vide si incertain plutôt
|
|
104
|
+
que de deviner une valeur.
|
|
105
|
+
limit: Nombre maximal de résultats, entre 1 et 100 (défaut 10).
|
|
106
|
+
"""
|
|
107
|
+
return await _post(
|
|
108
|
+
f"/v1/index/{catalog}/search",
|
|
109
|
+
{"q": query, "filters": filters or [], "limit": max(1, min(limit, 100))},
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@mcp.tool()
|
|
114
|
+
async def heurix_browse(catalog: str, category: str, sort: str = "stock", limit: int = 20) -> dict:
|
|
115
|
+
"""Liste les produits d'une catégorie sans recherche textuelle — pour
|
|
116
|
+
une demande du type "montre-moi tous les produits de telle
|
|
117
|
+
catégorie", pas une recherche par mot-clé (utilisez heurix_search
|
|
118
|
+
pour ça). Utilisez heurix_catalog_stats pour découvrir les
|
|
119
|
+
catégories réellement disponibles si elles ne sont pas déjà connues
|
|
120
|
+
— inventer un nom de catégorie renverra une liste vide, pas une erreur.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
catalog: Nom exact du catalogue.
|
|
124
|
+
category: Valeur de catégorie exacte, sensible à la casse.
|
|
125
|
+
sort: Stratégie de tri — "stock" (défaut, en stock d'abord),
|
|
126
|
+
"recent", "alphabetical", "price_asc", "price_desc",
|
|
127
|
+
"margin", ou "popular" (popularité réelle, clics et achats).
|
|
128
|
+
limit: Nombre maximal de résultats, entre 1 et 100 (défaut 20).
|
|
129
|
+
"""
|
|
130
|
+
return await _get(
|
|
131
|
+
f"/v1/browse/{catalog}/{category}",
|
|
132
|
+
{"sort": sort, "limit": max(1, min(limit, 100))},
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@mcp.tool()
|
|
137
|
+
async def heurix_catalog_stats(catalog: str | None = None) -> dict:
|
|
138
|
+
"""Liste tous les catalogues accessibles avec cette clé API et leurs
|
|
139
|
+
statistiques de base (nombre de produits, pack de règles actif). Si
|
|
140
|
+
`catalog` est précisé, renvoie en plus les catégories Browse
|
|
141
|
+
disponibles pour ce catalogue. À appeler en premier pour découvrir
|
|
142
|
+
ce qui existe, avant une recherche ou un parcours par catégorie.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
catalog: Nom d'un catalogue précis (optionnel). Sans ce
|
|
146
|
+
paramètre, liste tous les catalogues du compte.
|
|
147
|
+
"""
|
|
148
|
+
if catalog:
|
|
149
|
+
stats = await _get(f"/v1/index/{catalog}/stats")
|
|
150
|
+
if stats.get("error"):
|
|
151
|
+
return stats
|
|
152
|
+
categories = await _get(f"/v1/index/{catalog}/browse-categories")
|
|
153
|
+
# Browse peut ne pas être inclus dans le plan de cette clé — pas une
|
|
154
|
+
# raison de faire échouer tout l'appel, juste une liste vide.
|
|
155
|
+
stats["browse_categories"] = categories.get("categories", []) if not categories.get("error") else []
|
|
156
|
+
return stats
|
|
157
|
+
return await _get("/v1/index/catalogs")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def main() -> None:
|
|
161
|
+
"""Point d'entree de la commande `heurix-mcp-server`.
|
|
162
|
+
|
|
163
|
+
Declaree dans pyproject.toml sous [project.scripts] : sans cette
|
|
164
|
+
fonction, la commande installee depuis PyPI echouerait a l'import.
|
|
165
|
+
C'est aussi elle que les annuaires MCP lancent pour introspecter le
|
|
166
|
+
serveur et verifier les outils qu'il expose.
|
|
167
|
+
"""
|
|
168
|
+
mcp.run(transport="stdio")
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
if __name__ == "__main__":
|
|
172
|
+
mcp.run(transport="stdio")
|