FFBB-MCP-Server
AGENTS.md4 starsChanged 50 days agoApache-2.0View on GitHub
⚠️ Fichier auto-généré par tools/update_agents_md.py — ne pas modifier manuellement. Dernière mise à jour : FFBB MCP server | server.py: 434 lignes | services.py: 13020 lignes
- Reads credentials
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository4 other files it gives its agents.
- .github/copilot-instructions.mdCopilot instructions
- website/llms-full.txtllms.txt
- website/llms.txtllms.txt
- release-gateSkill
The file
We split this AGENTS.md into the rules it gives an agent
1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 167
Test manuel du service : status='ok'
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
FFBB MCP Server
⚠️ Fichier auto-généré par
tools/update_agents_md.py— ne pas modifier manuellement. Dernière mise à jour : FFBB MCP server | server.py: 434 lignes | services.py: 13020 lignes
Langue
Tous les documents de travail (walkthrough.md, implementation_plan.md) DOIVENT être en français.
Persona
Expert en basketball français. Accès au serveur MCP FFBB (ffbb.desimone.fr) connecté aux données officielles FFBB.
Workflow FFBB (Outils MCP)
Ressources MCP
ffbb://saisons→ Liste des saisons FFBB au format JSONffbb://competition/{competition_id}→ Détails d'une compétition au format JSONffbb://poule/{poule_id}→ Détails d'une poule au format JSONffbb://organisme/{organisme_id}→ Détails d'un organisme/club au format JSONffbb://rencontre/{rencontre_id}→ Détails d'une rencontre au format JSONffbb://salle/{salle_id}→ Détails d'une salle au format JSONffbb://officiel/{officiel_id}→ Détails d'un officiel/arbitre au format JSONffbb://entraineur/{entraineur_id}→ Détails d'un entraîneur/coach au format JSON
Règles de comportement
- Appelle TOUJOURS un outil MCP avant de répondre
- OBLIGATION ABSOLUE : Utiliser TOUJOURS le préfixe 'rtk' pour TOUTES les commandes shell exécutées dans le terminal (ex: 'rtk uv run ...', 'rtk git ...')
- Si plusieurs résultats, liste et demande confirmation
- Réponds toujours en français
- Si API ne répond pas, dis-le clairement
- Scores live : précise "données en temps réel, mises à jour toutes les 15s"
- Réutilise les
organisme_idrésolus dans la conversation (ne pas re-rechercher)
Règles strictes (outils FFBB)
- INTERDIT :
ffbb_get(type='poule')pour chercher un score ou match - INTERDIT : Déduire un score depuis le classement
- INTERDIT : Déclarer qu'un score "n'est pas disponible" sans avoir vérifié
- OBLIGATOIRE : Présenter un résultat de match AVEC le classement complet (paniers_marqués, paniers_encaissés)
- OBLIGATOIRE : Dans le classement, mettre TOUJOURS l'équipe cible en gras avec 🎯 (
is_target: true) - SINGULIER vs PLURIEL : "prochain match" →
ffbb_next_match· "prochains matchs" →ffbb_club(action='calendrier') - Catégorie ambiguë : Appeler
ffbb_resolve_teamAVANTffbb_next_match/ffbb_last_resultsi pas de numéro d'équipe - Question combinant résultats/prochain match et classement :
- Appeler
ffbb_team_summary. - Si la réponse ne contient pas le tableau complet, appeler
ffbb_club(action="classement", poule_id=<phase_courante.poule_id>, organisme_id=<resource_ids.organisme_id>)dans le même tour, sans le signaler à l'utilisateur comme une limite. - Ne jamais écrire "je n'ai pas le détail" sans avoir tenté l'appel de classement.
- Appeler
Karpathy Guidelines (Règles de développement)
Ces directives inspirées d'Andrej Karpathy visent à éliminer les erreurs de codage courantes en privilégiant la simplicité et la rigueur :
1. Penser avant de coder (Think Before Coding)
- Ne pas assumer, ne pas cacher la confusion, expliciter les compromis.
- Avant d'implémenter :
- Déclarez vos hypothèses de manière explicite. En cas d'incertitude, demandez.
- S'il existe plusieurs interprétations, présentez-les — ne choisissez pas en silence.
- Si une approche plus simple existe, proposez-la. Argumentez contre la complexité inutile si nécessaire.
- Si quelque chose n'est pas clair, arrêtez-vous. Nommez ce qui vous perturbe et demandez confirmation.
2. La simplicité d'abord (Simplicity First)
- Le minimum de code nécessaire pour résoudre le problème. Rien de spéculatif.
- Pas de fonctionnalités au-delà de ce qui est explicitement demandé.
- Pas d'abstractions pour du code à usage unique.
- Pas de "flexibilité" ou de "configurabilité" non requise.
- Pas de gestion d'erreurs pour des scénarios impossibles.
- Si vous écrivez 200 lignes alors que 50 suffiraient, réécrivez-le.
- Posez-vous toujours la question : "Est-ce qu'un développeur senior validerait cette implémentation comme simple et directe ?"
Phases éliminatoires vs poules
Détection automatique
Si le champ competition contient (insensible à la casse) l'un de ces
termes : finale, 1/2, demi-finale, demi-fin, quart, play-off, playoff, coupe, barrage, promotion
→ Phase éliminatoire 🏆
Sinon (Phase 1, Phase 2, Phase 3…) → Phase de poule 📊
Règles de formulation
- Phase éliminatoire : toujours mentionner explicitement le contexte (ex : "ce match est une demi-finale départementale")
- Ne JAMAIS rattacher un match éliminatoire au bilan de phase de poule
État d'une phase (terminée vs en cours)
phase_courante dans ffbb_bilan = dernière phase connue, pas
nécessairement une phase active.
Règle de temps verbal :
- Si aucun match futur détectable dans la poule → utiliser le passé ("ont terminé", "ont fini", "se sont classés")
- Si des matchs restent à jouer → utiliser le présent ("sont", "occupent", "se trouvent")
⚠️ INTERDIT : écrire "sont actuellement Xe" si la phase est terminée.
Format enrichi pour tout match affiché
- 📍 Domicile / Extérieur
- 🏆 Phase éliminatoire OU 📊 Phase de poule (numéro)
- ⚠️ Si
salleouvillevides → écrire "Salle non encore renseignée" - 📍 Format d'adresse standardisé :
[Nom de la Salle] - [Adresse Postale], [Ville](gérer proprement les valeurs manquantes sans séparateurs orphelins)
Alignement Strict FFBB Data Client & MCP
- Machine à états stricte (Zéro résolution d'équipe ambiguë silencieuse) : Ne JAMAIS renvoyer
status="resolved"si plusieurs engagements actifs correspondent au club + catégorie (ex: Championnat [PLAT] vs Coupe [COUPE]). Renvoyer obligatoirementstatus="ambiguous", la liste exhaustivecandidates, et unclarification_promptprêt pour le LLM. Propager systématiquement les filtrescompetition_id,competition_type,poule_id,season_id,force_refreshsur tous les outils d'équipe et surffbb_club(action='calendrier'). - Contrat de pagination
_meta& enveloppe uniforme : Respect strict de1 <= limit <= 100etoffset >= 0surffbb_search. Tout outil retournant une collection paginée (ffbb_search,ffbb_club(action='calendrier')) doit renvoyer un objet{"items": list, "_meta": dict}avectotal,returned,has_moreetsort. Ne jamais insérer un objet sentinelle_metaen tête de liste. - Vérification d'identifiants numériques : Toujours vérifier
id is None or id == ""(ne jamais utiliserif not idqui élimine silencieusementid: 0). - Résolution H2H & Fallback de poule : Si l'adversaire B n'est pas directement résolu par recherche globale d'organismes, inspecter la poule partagée de l'équipe A pour construire une résolution synthétique avec
fallback_warning. - Dispatching dynamique des mocks inter-services : Dans l'architecture modulaire
services/, utiliser systématiquement le pattern de résolution dynamique (getter = getattr(svc, 'func_name', func_local)) pour garantir l'herméticité et la compatibilité totale avec les mocks de tests unitaires. - Calcul objectif des statuts de saison : Évaluer
enCoursetwithin_date_rangepar comparaison temporelle stricte (debut <= today <= fin) pour pallier les états non mis à jour par l'amont Directus. - Parité des index Meilisearch : Le serveur MCP interroge exclusivement les 6 index Meilisearch réels et actifs (
organismes,competitions,rencontres,salles,terrains,tournois). - Élévation de niveau / Fallback : Si Directus renvoie
classements: [](avant 1ère journée), le MCP reconstruit la liste des équipes engagées depuis lesrencontres(status: non_commence). - Allègement des payloads : Préférer
get_organisme_for_search_async()pour la résolution de club afin de minimiser le transfert réseau. - Polymorphisme des paramètres : Toujours supporter
numero_equipeetforce_refreshsur les outils d'équipe (ffbb_bilan,ffbb_team_summary,ffbb_next_match,ffbb_last_result).
Développement MCP (FastMCP)
- Cycle de vie :
mcp.run()oumcp.run_streamable_http_async()— pas de montage manuel viaapp.mount() - Chemin personnalisé : configurer
mcp.settings.streamable_http_pathavantmcp.run() - Routes HTTP : définies dans
routes.pyviaregister_routes(mcp) - Tools MCP : définis dans
server.pyvia@mcp.tool()
Architecture
src/ffbb_mcp/
├── __init__.py # Version du package
├── __main__.py # Point d'entrée CLI
├── _state.py # State global (caches, inflight)
├── aliases.py # Alias clubs + cache acronymes persistant
├── app_factory.py # Starlette app + middlewares
├── benchmark.py # Benchmark performance
├── cache_strategy.py # TTL dynamique selon fenêtres de match
├── client.py # FFBBDataClient factory + token refresh
├── dashboard.py # Dashboard HTML
├── metrics.py # Prometheus metrics + health snapshot
├── prompts.py # Prompts MCP réutilisables
├── resources.py # Resources MCP (ffbb://saisons, etc.)
├── routes.py # Routes HTTP (health, metrics, dashboard, docs, etc.)
├── server.py # Tools MCP + main() (≈434 lignes)
├── services/ # Logique métier modularisée (≈13020 lignes)
│ ├── __init__.py # Point d'entrée et factory de services
│ ├── bilan.py # Module de service
│ ├── calendar.py # Module de service
│ ├── club.py # Service de gestion des clubs
│ ├── common.py # Helpers et base services partagés
│ ├── division.py # Module de service
│ ├── http_api.py # Module de service
│ ├── poule.py # Service de gestion des poules
│ ├── poule_lives.py # Module de service
│ ├── poule_opponent.py # Module de service
│ ├── regulations.py # Module de service
│ ├── salle.py # Service de gestion des salles
│ ├── search.py # Service de recherche multicritère
│ ├── team_resolver.py # Module de service
│ └── warmup.py # Service de préchauffage du cache
└── utils.py # serialize_model, parse_categorie, normalize_queryConventions de code
- Services :
ffbb_<nom>_service(dans services/) - Tools MCP :
ffbb_<nom>(dans server.py,@mcp.tool()) - Pas de suffixe
_compact_ou_impl_exposé - Modifier une fonction à la fois, seulement si test/usage échoue
- Nouvelle fonction → test manuel validé avant exposition MCP
- Modularisation : Le package
services/(total ≈13020 lignes) remplace l'ancien fichier unique de 2915 lignes pour une meilleure cohésion.
Commandes
- Démarrer le serveur MCP (stdio) :
rtk uv run python -m ffbb_mcp(recommandé pour Claude Desktop) - Démarrer le serveur MCP (HTTP/SSE) :
MCP_MODE=streamable-http rtk uv run python -m ffbb_mcp(port9123par défaut) - Inspecter/Tester localement :
rtk npx -y @modelcontextprotocol/inspector uv run python -m ffbb_mcp - Tests unitaires :
.venv/bin/python -m pytest -q(paspytestseul) - Pre-merge :
- pytest -q → 0 failed
- Test manuel du service : status='ok'
grep "compact\|fantôme" src/ffbb_mcp/*.py→ 0 résultat
Codebase Knowledge Graph (codebase-memory-mcp)
Ce projet utilise codebase-memory-mcp pour maintenir un graphe de connaissances AST/Cypher précis de la codebase.
Outils disponibles : search_graph, trace_path, get_code_snippet, query_graph, get_architecture.
Push / Tag / Release Gate
⚠️ OBLIGATION STRICTE : Toutes ces commandes DOIVENT être préfixées par 'rtk' dans le terminal (ex: 'rtk uv run pytest'). Ne jamais exécuter de commande nue sans 'rtk'. Avant push/tag/release :
rtk uv run python tools/check_version_alignment.pyrtk uv run ruff format --check .rtk uv run ruff check .rtk uv run mypy srcrtk uv run pyright srcrtk uv run pytest- Si version files modifiés :
rtk uv run tools/sync_version.py+ vérifier diff docs/website - Vérifier cache (
src/ffbb_mcp/acronyms_cache.json) — revert impératif de toute modification non liée à votre tâche - Après push : inspecter les GitHub Actions
Variables d'environnement
| Variable | Défaut | Usage |
XDG_CACHE_HOME | `` | Dossier racine pour stocker les fichiers de cache persistants (ex: acronymes, benchmark) |
FFBB_DATA_DIR | /app/data | Répertoire racine contenant les données statiques (ex: regulations, cache) |
MCP_MODE | stdio | Mode de transport (stdio / streamable-http) |
MCP_STATELESS_HTTP | true | Activer le mode stateless HTTP MCP spec 2026-07-28 sans session (défaut : true) |
ENABLE_DNS_PROTECTION | `` | Activer/désactiver explicitement la protection contre le DNS rebinding |
TRUSTED_PROXY_HOSTS | 127.0.0.1 | Proxies de confiance |
FFBB_LIVES_REFRESH_INTERVAL | 60 | Intervalle de rafraîchissement proactif des lives en secondes, mode HTTP (défaut : 10) |
FFBB_ENABLE_DIRECTUS | 0 | Forcer l'activation des appels Directus (défaut : 0, Directus désactivé en faveur de Meilisearch) |
FFBB_DISABLE_DIRECTUS | 1 | Désactiver les appels réseau Directus vers bo/api.ffbb.com bloqués par BunnyCDN (défaut : 1) |
API_FFBB_APP_BEARER_TOKEN | `` | Jeton d'authentification Bearer pour l'API Directus FFBB |
MEILISEARCH_BEARER_TOKEN | `` | Jeton d'authentification Bearer pour le cluster Meilisearch FFBB |
FFBB_CACHE_BACKEND | sqlite | Choix du backend de cache HTTP (sqlite ou redis) |
API_FFBB_BASE_URL | https://api.ffbb.com/ | URL de base de l'API FFBB (défaut : https://api.ffbb.com/) |
FFBB_SERVICE_CACHE_PERSIST | 1 | Activer la persistance des caches service sur disque (SQLite) entre redémarrages |
FFBB_KNOWN_CLUB_IDS | `` | Override JSON de la liste d'organisme_id connus pour les prompts MCP (fallback : _DEFAULT_KNOWN_CLUB_IDS) |
FFBB_REGULATIONS_MANIFEST | `` | Chemin explicite vers le fichier manifest.yaml des règlements sportifs |
FFBB_WARMUP_API_KEY | `` | Clé d'API secrète requise pour déclencher le warmup via l'endpoint HTTP /warmup |
FFBB_WARMUP_MAX_ORGANISMES | 50 | Nombre maximum d'organismes à charger lors d'un cycle de warmup |
PUBLIC_URL | https://ffbb.desimone.fr | URL publique pour liens/sitemap |
ALLOWED_HOSTS | * | Hosts autorisés (DNS rebinding protection) |
ALLOWED_ORIGINS | * | Origins CORS |
FFBB_LOG_LEVEL | INFO | Niveau de log |
HOST | 0.0.0.0 | Interface d'écoute |
PORT | 9123 | Port d'écoute HTTP |
FFBB_SWR_ENABLED | 1 | Activer le Stale-While-Revalidate : servir le cache et rafraîchir en arrière-plan (défaut : 1) |
FFBB_SWR_STALE_FRACTION | 0.75 | Fraction du TTL au-delà de laquelle une entrée est rafraîchie en arrière-plan (défaut : 0.75) |
FFBB_API_TIMEOUT_SECONDS | 3.0 | Timeout en secondes pour les requêtes vers l'API FFBB / Meilisearch |
MAX_CONCURRENT_FFBB | 4 | Concurrence max appels API FFBB |
FFBB_MAX_CALENDAR_MATCHES | 300 | Max rencontres retournées |
FFBB_SWR_MAX_TASKS | 32 | Nombre max de tâches SWR concurrentes (défaut : 32) |
FFBB_WARMUP_ORGANISMES | `` | Liste d'organisme_id séparés par des virgules à préchauffer au démarrage |
FFBB_WARMUP_CONCURRENCY | 5 | Concurrence maximale lors du préchauffage du cache |
GIT_SHA | `` | Commit SHA Git déployé exposé dans ffbb_version et /health |
BUILD_SHA | `` | Build SHA de l'image conteneurisée |
COMMIT_SHA | `` | Alias de commit SHA pour les déploiements CI/CD |
BUILD_DATE | `` | Date de compilation/build de l'image ou du package exposé dans ffbb_version |
DEPLOY_DATE | `` | Date de déploiement en production (alternative à BUILD_DATE) |
FFBB_ENABLE_BENCHMARK | — | Activer endpoint /benchmark/run (sécurité) |
FFBB_POULE_FETCH_CONCURRENCY | — | Concurrence max fetch poules |
FFBB_CACHE_TTL_* | — | TTL par type de cache (voir cache_strategy.py) |
FFBB_REDIS_URL | — | URL de connexion à l'instance Redis si backend=redis |
FFBB_CACHE_EXPIRE_AFTER | — | TTL en secondes pour le cache HTTP court de session (défaut : 30) |
Notes workflow / outils
PR Comments pour Jules (Google)
- NE PAS utiliser
gh pr review --comment— Jules ne le détecte pas - Utiliser
gh pr comment <number> --body "..."ou commenter via l'UI GitHub - Jules écoute les
issue_commentevents, pas lespull_request_reviewevents
Journal Bolt (.jules/bolt.md)
- OBLIGATION : chaque nouvelle entrée ajoutée à
.jules/bolt.mdDOIT être datée de la date du jour (format## YYYY-MM-DD - Titre) - INTERDIT : copier une date existante (d'une entrée précédente, d'une autre branche, d'un commit ou d'une issue) — les dates antérieures au jour d'écriture signalent une entrée non datée
- Vérifier la date courante avant d'écrire, ex :
date +%F
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

