feat(mcp): expose les 4 fonctions métier via @mcp_enabled

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Colin Maudry
2026-07-09 20:35:24 +02:00
parent ee98aa8186
commit 5a6bd59297
2 changed files with 119 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
from dash.mcp import mcp_enabled
from src.mcp import queries
from src.utils.tracking import track_mcp_tool
@mcp_enabled(name="rechercher_organisations", expose_docstring=True)
def rechercher_organisations(
query: str,
type: str = "acheteur",
limite: int = 20, # noqa: A002
) -> list[dict]:
"""Recherche des acheteurs ou titulaires publics par nom.
Utiliser en premier pour résoudre un nom d'organisation vers son
identifiant, à passer ensuite à stats_acheteur / stats_titulaire.
query: texte libre (nom d'organisation).
type: "acheteur" ou "titulaire".
Retourne une liste de {id, nom, departement}.
"""
track_mcp_tool("rechercher_organisations", query=query)
return queries.search_organisations(query, type, limite)
@mcp_enabled(name="stats_acheteur", expose_docstring=True)
def stats_acheteur(acheteur_id: str) -> dict:
"""Statistiques agrégées d'un acheteur public (par identifiant).
Retourne nombre de marchés, montant total, répartition annuelle,
principaux titulaires et principaux codes CPV.
"""
track_mcp_tool("stats_acheteur")
return queries.compute_org_stats("acheteur", acheteur_id)
@mcp_enabled(name="stats_titulaire", expose_docstring=True)
def stats_titulaire(titulaire_id: str) -> dict:
"""Statistiques agrégées d'un titulaire (entreprise) par identifiant.
Retourne nombre de marchés remportés, montant total, répartition
annuelle, principaux acheteurs et principaux codes CPV.
"""
track_mcp_tool("stats_titulaire")
return queries.compute_org_stats("titulaire", titulaire_id)
@mcp_enabled(name="rechercher_marches", expose_docstring=True)
def rechercher_marches(
acheteur_id: str | None = None,
titulaire_id: str | None = None,
cpv: str | None = None,
objet_contient: str | None = None,
montant_min: float | None = None,
montant_max: float | None = None,
date_min: str | None = None,
date_max: str | None = None,
departement: str | None = None,
page: int = 1,
filtres_avances: dict | None = None,
) -> dict:
"""Recherche paginée de marchés publics (DECP).
Filtres nommés : acheteur_id, titulaire_id, cpv (code CPV, correspondance
partielle), objet_contient (texte de l'objet), montant_min, montant_max,
date_min / date_max (format YYYY-MM-DD, sur dateNotification),
departement (code département de l'acheteur).
filtres_avances : dict optionnel {"colonne__operateur": valeur} pour les
besoins pointus (mêmes colonnes/opérateurs que l'API REST colibre).
page : numéro de page (50 résultats par page).
Retourne {meta: {page, page_size, total}, marches: [...]}.
"""
track_mcp_tool("rechercher_marches", query=objet_contient)
return queries.search_marches(
acheteur_id=acheteur_id,
titulaire_id=titulaire_id,
cpv=cpv,
objet_contient=objet_contient,
montant_min=montant_min,
montant_max=montant_max,
date_min=date_min,
date_max=date_max,
departement=departement,
page=page,
filtres_avances=filtres_avances,
)
+33
View File
@@ -0,0 +1,33 @@
from src.mcp import tools
def test_all_four_tools_are_callable():
for name in (
"rechercher_organisations",
"stats_acheteur",
"stats_titulaire",
"rechercher_marches",
):
assert callable(getattr(tools, name))
def test_rechercher_organisations_returns_list():
result = tools.rechercher_organisations("ACHETEUR", "acheteur")
assert isinstance(result, list)
assert any(r["id"] == "123" for r in result)
def test_rechercher_marches_returns_meta():
result = tools.rechercher_marches(acheteur_id="123")
assert result["meta"]["total"] >= 1
def test_stats_acheteur_returns_stats():
result = tools.stats_acheteur("123")
assert result["nb_marches"] >= 1
assert result["identite"]["id"] == "123"
def test_stats_titulaire_returns_stats():
result = tools.stats_titulaire("345")
assert result["nb_marches"] >= 1