feat(mcp): tool search_organisations (résolution nom -> id)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Colin Maudry
2026-07-09 20:13:17 +02:00
parent 9303c5e206
commit e2d1082e92
2 changed files with 57 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
# src/mcp/queries.py
import re
from src.mcp.serialization import (
to_json_records, # noqa: F401 (utilisé aux tâches suivantes)
)
from src.utils.data import DF_ACHETEURS, DF_TITULAIRES
from src.utils.search import search_org
PAGE_SIZE = 50
TOP_N = 10
ORG_FRAMES = {"acheteur": DF_ACHETEURS, "titulaire": DF_TITULAIRES}
def _extract_plain_text(html_str: str) -> str:
"""Extract plain text from HTML link, e.g. '<a...>123</a>' -> '123'."""
match = re.search(r">([^<]+)<", html_str)
return match.group(1) if match else html_str
def search_organisations(
query: str, org_type: str = "acheteur", limite: int = 20
) -> list[dict]:
"""Recherche des organisations par nom, résout un nom -> id."""
if org_type not in ORG_FRAMES:
raise ValueError(
f"type invalide: {org_type!r} (attendu 'acheteur' ou 'titulaire')"
)
df = search_org(ORG_FRAMES[org_type], query, org_type, track=False).head(limite)
return [
{
"id": _extract_plain_text(r[f"{org_type}_id"]),
"nom": _extract_plain_text(r[f"{org_type}_nom"]),
"departement": r.get("Département"),
}
for r in df.to_dicts()
]
+20
View File
@@ -1,4 +1,7 @@
import pytest
import src.utils.search as search_mod
from src.mcp.queries import search_organisations
from src.utils.data import DF_ACHETEURS
from src.utils.search import search_org
@@ -19,3 +22,20 @@ def test_search_org_track_true_calls_track_search(monkeypatch):
search_org(DF_ACHETEURS, "ACHETEUR", "acheteur", track=True)
assert calls == [("ACHETEUR", "home_page_search")]
def test_search_organisations_finds_known_acheteur():
result = search_organisations("ACHETEUR", "acheteur")
assert any(r["id"] == "123" for r in result)
first = next(r for r in result if r["id"] == "123")
assert set(first.keys()) == {"id", "nom", "departement"}
def test_search_organisations_invalid_type_raises():
with pytest.raises(ValueError):
search_organisations("x", "autre")
def test_search_organisations_respects_limite():
result = search_organisations("ACHETEUR", "acheteur", limite=1)
assert len(result) <= 1