Aller au contenu
Riadh Mnasri
← Retour au blog
7 min de lecture

ecoledirecte-mcp et ffe-mcp : deux serveurs MCP faits maison, sans API officielle

ecoledirecte-mcp et ffe-mcp : deux serveurs MCP faits maison, sans API officielle

J'ai passé une soirée récente à comprendre pourquoi mon propre serveur MCP refusait de se connecter à EcoleDirecte avec des identifiants pourtant valides. Ce n'était pas un bug exotique, juste un protocole de login non documenté qu'il fallait reproduire à l'octet près. Cette session est l'occasion de revenir sur les deux serveurs MCP que j'ai construits pour mon usage personnel : ecoledirecte-mcp pour les notes et devoirs de mes enfants, ffe-mcp pour les tournois d'échecs homologués par la Fédération Française des Échecs.

Le problème que ça résout#

Aucun des deux sites n'expose d'API publique. EcoleDirecte a une appli et un site web, point final : pour savoir si mes enfants ont un devoir pour le lendemain, il faut ouvrir le site, se connecter, naviguer jusqu'au cahier de texte. Rien qui s'intègre dans une conversation avec Claude où je suis déjà en train de regarder mon planning de la semaine.

Pour les échecs, j'avais déjà un skill qui cherche des tournois via WebFetch directement sur le site de la FFE. Ça marchait, avec une limite connue et documentée dans le skill lui-même : la pagination ASP.NET et les filtres en postback JavaScript du site ne sont pas actionnables par un simple fetch, donc seul le premier lot de résultats par département était récupéré. Un serveur dédié, avec ses propres endpoints identifiés et ses propres parseurs, ferme cette limite proprement au lieu de la contourner à moitié à chaque appel.

Pourquoi un serveur MCP plutôt qu'un skill ou un script#

Un skill encode un comportement, un serveur MCP encode un accès à un système externe : je détaille cette distinction dans l'article sur MCP. Le sujet ici, c'est ce que ça donne concrètement quand on construit soi-même ce deuxième type de brique plutôt que de se contenter d'appeler une API publique bien documentée qui n'existe pas.

Ce que chaque serveur expose#

Cahier de textes EcoleDirecte avec nom d'élève, d'établissement et d'enseignant anonymisés

Capture réelle de l'interface, avec nom d'élève, d'établissement, de parent et d'enseignant remplacés par des valeurs fictives avant capture — c'est la page que consulter_devoirs lit à ma place.

ecoledirecte-mcp — nécessite les identifiants du compte (lus depuis un .env local, jamais transmis ailleurs) :

OutilDescription
lister_elevesListe les élèves rattachés au compte
consulter_notesNotes d'un élève par matière et par période
consulter_devoirsCahier de texte d'un élève
consulter_absencesAbsences, retards, sanctions d'un élève
consulter_messagesMessages reçus dans la messagerie du compte

ffe-mcp — données publiques, aucun identifiant requis :

OutilDescription
rechercher_joueurRecherche un joueur par nom, retourne numéro FFE et Elo
lister_tournoisTournois homologués d'un département
details_tournoiCadence, nombre de rondes, annonce d'un tournoi
classement_tournoiClassement général après la dernière ronde publiée
resultats_joueur_tournoiRésultats ronde par ronde d'un joueur dans un tournoi

Liste des tournois d'échecs homologués FFE dans les Hauts-de-Seine, sur echecs.asso.fr

Données publiques cette fois, aucune anonymisation nécessaire : la page que lister_tournois parse pour le département 92.

Comment ils sont construits#

Les deux projets partagent la même architecture, en trois couches :

  • src/domain/ : types métier et interfaces (ports), zéro dépendance à l'API ou au site source
  • src/infrastructure/ : l'adaptateur qui parle le format brut de la source (requêtes HTTP pour l'un, parsing HTML pour l'autre), avec un cache fichier qui sert de filet de sécurité
  • src/mcp/ : l'exposition des outils à Claude, qui orchestre fetch live et repli sur le cache

Cette isolation a un but précis : le jour où EcoleDirecte change son protocole de login ou où la FFE modifie la mise en page d'une page de résultats, un seul fichier doit changer. Les outils exposés à Claude, eux, ne bougent pas.

Note

Les deux tournent en local uniquement, via @modelcontextprotocol/sdk en transport stdio : pas de serveur HTTP exposé, pas de déploiement, pas de port réseau à sécuriser. Chaque famille qui veut l'utiliser clone le repo et le fait tourner chez elle, avec ses propres identifiants pour ecoledirecte-mcp, aucun identifiant du tout pour ffe-mcp.

Le vrai obstacle technique : deviner un protocole non documenté#

Le cas ecoledirecte-mcp est le plus instructif. login.awp rejetait mes identifiants avec un message générique, « identifiant et/ou mot de passe invalide », alors qu'ils fonctionnaient sans problème sur le site. Première piste, plausible mais fausse : la présence de scripts anti-bot (transparentedge.io, cookie TEDGEPT) observés en comparant une capture réseau d'un vrai login navigateur avec ce que mon client Node envoyait. Ça ressemblait à du fingerprinting bloqué côté serveur.

La vraie cause, trouvée en croisant la documentation communautaire du protocole EcoleDirecte (le format n'est pas officiel, mais largement rétro-documenté par plusieurs projets open source), était plus simple et strictement protocolaire : login.awp attend un GET préalable (?gtk=1) qui pose deux cookies, dont un GTK, à renvoyer sur le POST de login à la fois comme header X-Gtk et comme header Cookie classique. Mon client ne renvoyait ni l'un ni l'autre. Une fois les deux ajoutés, le login est passé du premier coup.

Attention

La leçon qui compte n'est pas le detail du header manquant, elle est plus générale : un message d'erreur produit par une API non documentée n'est pas une preuve de sa cause. J'ai perdu du temps sur une hypothèse anti-bot plausible avant de vérifier le protocole réellement attendu par une capture réseau comparée point par point. Le même principe que je décris dans l'article sur le débogage avec un agent : citer une preuve brute avant de conclure, jamais un récit plausible.

Côté ffe-mcp, la fragilité est différente : pas de protocole à reconstituer, mais des pages HTML publiques dont la structure peut changer sans préavis. La parade n'est pas la même non plus : les tests vitest tournent contre des fixtures HTML réellement capturées sur echecs.asso.fr, et le README documente explicitement quels champs sont vérifiés par capture réelle et lesquels restent à confirmer. Si la mise en page change, le test casse fort et vite plutôt que de renvoyer silencieusement un classement faux.

Comment les utiliser#

Pour ecoledirecte-mcp, un assistant en ligne de commande écrit le fichier de configuration à l'écart du projet, pour rester stable même installé via npx :

bash
npx ecoledirecte-mcp-init
claude mcp add ecoledirecte -- npx -y ecoledirecte-mcp

Pour ffe-mcp, pas d'identifiants à fournir puisque les données sont publiques :

bash
git clone https://github.com/riadh-mnasri/ffe-mcp.git
cd ffe-mcp && npm install && npm run build
claude mcp add ffe -- node /chemin/vers/ffe-mcp/dist/index.js

Les deux fonctionnent aussi avec Claude Desktop, en ajoutant l'équivalent dans claude_desktop_config.json.

Partager sans être un service#

Les deux projets sont sous licence MIT, sans compte à créer et sans base de données centrale : ce n'est pas un service auquel on se connecte, c'est un programme que chaque famille clone et fait tourner chez elle. Pour ecoledirecte-mcp en particulier, ce choix n'est pas qu'une préférence d'architecture, c'est ce qui évite d'avoir à porter la responsabilité du stockage des données scolaires d'autrui : il n'y a pas de « autrui », chacun héberge les siennes.

ClaudestdioServeur MCP localdomain / infrastructure / mcpSource (API / HTML)Cache localrepli si échec, flag "stale"

Ce que ça généralise#

Trois principes qui tiennent au-delà de ces deux projets, pour n'importe quel outil construit contre une source sans API officielle : partir d'une requête réellement capturée plutôt que d'une supposition sur le protocole, isoler l'adaptateur volatile du reste du code pour qu'une seule couche casse le jour où la source change, et préférer un repli sur un cache explicitement daté à un échec sec quand la source est hors de mon contrôle. Le code des deux serveurs est public : ecoledirecte-mcp et ffe-mcp.