french-politics-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@french-politics-mcpShow me passages on climate change from all parties"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Civis — french-politics-mcp
Serveur MCP qui donne accès aux programmes officiels de l'élection présidentielle française de 2022, pour cinq partis, avec une contrainte : ne jamais répondre sans source primaire.
Le serveur ne raisonne pas et ne rédige aucune synthèse. Il retrouve des passages, renvoie leur texte exact et leur référence complète, et dit explicitement quand le corpus ne documente pas un sujet. La synthèse revient au modèle client, à partir de citations vérifiables.
Se connecter
Le serveur est déployé, public et en lecture seule :
https://french-politics-mcp.mael-app.workers.dev/mcpAvec Claude Code :
claude mcp add --transport http civis https://french-politics-mcp.mael-app.workers.dev/mcpAvec l'inspecteur MCP, en transport Streamable HTTP :
npx @modelcontextprotocol/inspector --cli \
https://french-politics-mcp.mael-app.workers.dev/mcp \
--transport http --method tools/listPour un client qui ne parle que stdio, passer par le proxy mcp-remote. Aucune authentification n'est requise, le corpus est public.
Related MCP server: alexandria-mcp
Corpus
158 documents, 4 704 passages citables, 3,4 millions de caractères, pour ce seul scrutin. Dix thèmes comparables, tous couverts par les cinq partis.
Parti | Candidat | Documents | Passages |
LFI | Jean-Luc Mélenchon | Programme abrégé + 41 livrets thématiques + 13 plans | 2 358 |
RN | Marine Le Pen | Manifeste + 17 livrets « projet » | 791 |
Renaissance | Emmanuel Macron | Projet 24 p. + 41 fiches thématiques | 739 |
LR | Valérie Pécresse | Le courage de faire + 33 fiches de projet | 551 |
PS | Anne Hidalgo | Programme officiel 44 p. | 266 |
S'y ajoutent deux séries homogènes : la déclaration officielle de chaque candidat à la Commission nationale de contrôle de la campagne — le seul document que les cinq ont produit dans le même format — et les réponses écrites au questionnaire TDIE sur les transports, pour les quatre candidats qui y ont répondu (Emmanuel Macron ne l'a pas fait).
Ces séries sont retenues selon une règle uniforme : tous ceux qui ont produit le document, sans sélection destinée à combler tel ou tel parti.
Le choix de la présidentielle 2022 plutôt que des législatives 2024 est délibéré : en 2024, LFI et le PS partageaient le programme du Nouveau Front populaire, ce qui rendait la comparaison parti par parti sans objet.
Un corpus inégal, et pourquoi il le reste
Le PS est documenté 9 fois moins que LFI. Ce n'est pas un défaut de collecte : Anne Hidalgo n'a produit aucun livret thématique, là où LFI en a publié 54, et la candidature d'Emmanuel Macron, déposée cinq semaines avant le scrutin, n'a matériellement pas donné lieu à un appareil programmatique volumineux. Le déséquilibre reflète ce que les partis ont réellement publié.
Plutôt que de tronquer les uns pour égaliser, le serveur rend l'écart visible et l'empêche de fausser les résultats :
compare_partiesannonce l'écart et joint à chaque parti son volume de corpus. Unnot_founddoit se lire « le corpus documente peu ce parti », jamais « ce parti n'avait pas de position ». Le classement n'y est pas affecté : chaque parti est interrogé par une requête séparée.search_documentsplafonne la part d'un même parti à un tiers des résultats, faute de quoi le parti le plus volumineux monopoliserait les recherches non filtrées.
Sources et robots.txt
Deux hôtes interdisent le parcours automatisé, et cela a été respecté :
mlafrance.fr(Disallow: /) sert les livrets du RN. On passe parrassemblementnational.fr, qui les sert à l'identique enAllow: /. Ce qui reste exclusif à mlafrance.fr — dossiers de presse, discours, communiqués — n'est de toute façon pas programmatique.laec.frpublie le texte intégral de L'Avenir en commun, mais sonrobots.txtest une liste blanche de moteurs de recherche close parDisallow: /. Le texte du livre n'est donc pas dans le corpus. Ses livrets et plans, republiés par LFI surmelenchon2027.fr(hôte permissif), le sont — et représentent un volume bien supérieur.
Les sites de campagne d'Emmanuel Macron et d'Anne Hidalgo ayant disparu, leurs documents sont cités via l'archive Wayback, à un horodatage figé pour rester reproductibles ; l'URL d'origine est conservée dans les métadonnées. Chaque source porte son empreinte SHA-256.
Tools MCP
Tool | Rôle |
| Recherche des passages, filtrables par parti et par thème. Une liste vide est une réponse : le corpus ne documente pas le sujet. |
| Texte exact d'un passage et de ses voisins, pour vérifier qu'une citation n'est pas sortie de son contexte. |
| Sur un thème, les meilleurs passages de chaque parti avec un niveau de preuve. Aucune synthèse côté serveur. |
| Ce que le corpus contient par parti : volume, thèmes couverts. |
| Documents primaires, URL, type, empreinte SHA-256. |
Resources : party://{partyId}, election://presidentielle-2022, topics://catalog.
Prompts : compare-topic, summarize-party-position, find-direct-quote.
Niveaux de preuve
compare_parties qualifie chaque parti par un evidenceLevel, déduit du nombre de mots-clés du thème réellement présents dans le passage — un signal mesurable, jamais un jugement sur le fond.
direct_quote— le passage traite explicitement le thèmeclear_paraphrase— il l'aborde sans lui être consacréweak_inference— le lien n'est que lexical, à interpréter avec prudencenot_found— rien dans le corpus : ne prêter aucune position au parti
Architecture
TypeScript de bout en bout, sur Cloudflare Workers, avec le corpus dans D1 (SQLite managé).
src/
index.ts Worker : health check + createMcpHandler sur /mcp
server/ McpServer — tools, resources, prompts
domain/ types, partis, taxonomie des thèmes
search/ pipeline linguistique français + constructeur de requête FTS5
storage/ accès D1 : recherche, passages, agrégats
ingest/ pipeline local : fetch → extract → normalize → build-sql
data/corpus/ corpus.json — artefact normalisé, source du SQL
data/sql/ schema.sql (écrit à la main) + seed.sql (généré)
data/text/ texte extrait, versionné (preuve consultable)
data/raw/ PDF sources (non versionnés, checksums.json l'est)Le Worker est sans état et n'embarque aucune donnée : pas de Durable Object, transport Streamable HTTP uniquement (SSE est déprécié). Une instance McpServer neuve est créée à chaque requête — le SDK l'exige depuis la version 1.26, un serveur partagé pouvant faire fuiter la réponse d'un client vers un autre.
Pourquoi D1 plutôt qu'un index embarqué
La première version chargeait un index MiniSearch depuis le bundle. Ce n'était pas la taille qui posait problème (609 Ko gzippés sur les 3 Mo autorisés) mais le CPU au démarrage à froid, mesuré à ~8,8 ms sur un isolate neuf — dont 6,2 ms pour la seule réhydratation de l'index — face à la limite de 10 ms de CPU par requête du plan gratuit. La première requête servie par chaque isolate passait tout près du plafond.
D1 déplace ce travail vers de l'entrée-sortie, qui ne compte pas dans le budget CPU. Le bundle tombe à 386 Ko gzippés, et le coût par requête devient l'attente réseau plus quelques microsecondes de sérialisation. Le corpus peut par ailleurs grossir sans que la taille du Worker bouge.
Recherche
Recherche plein texte FTS5 avec classement bm25, le titre de section comptant double.
FTS5 n'embarque aucun analyseur français — son tokenizer se contente de retirer les diacritiques. Le contenu indexé est donc pré-stemmé à l'ingestion par src/search/french.ts, et la requête passe par exactement le même code côté Worker. Sans cela, « retraites » ne retrouverait pas « retraite ». Toute modification du stemmer impose de régénérer le seed.
Ce pipeline est écrit à la main : tokenisation sans accents, mots vides, et un stemmer léger dans l'esprit du French light stemmer de Savoy. Snowball aurait pesé 867 Ko pour un gain marginal. npm run stem:check vérifie la convergence des variantes sur le vocabulaire du corpus (21 groupes sur 22 ; le préfixe FTS5 rattrape le dernier).
Trois règles décident de ce qui est renvoyé et dans quel ordre :
Pénalité de navigation — les sommaires sont denses en mots-clés mais ne contiennent aucune position citable. Ils sont pénalisés au classement, jamais exclus : l'heuristique n'est pas assez sûre pour rendre du texte inatteignable.
Plancher relatif — les résultats sous 25 % du meilleur score sont coupés. « cryptomonnaies blockchain NFT » ne remonte rien plutôt que cinq passages sans rapport.
Plafond par parti — sur une recherche non filtrée, aucun parti ne peut occuper plus d'un tiers des résultats. Les partis n'ayant pas publié le même volume, LFI raflait sept des douze premiers résultats sur « augmenter le SMIC » : c'était la taille de son corpus qui parlait, pas la pertinence. Le classement par score est conservé, seuls les résultats excédentaires d'un parti déjà bien représenté sont écartés. Un filtre explicite sur un parti désactive la règle.
Couverture thématique — sur une comparaison, le score bm25 est majoré de 15 % par mot-clé distinct du thème présent dans le passage. bm25 seul récompense la rareté d'un terme, ce qui n'est pas la même chose que traiter le sujet ; la couverture seule échoue symétriquement, le vocabulaire d'un thème étant ambigu. Multiplier les deux laisse la pertinence lexicale départager à couverture comparable.
Ingestion
npm run ingest # fetch → extract → normalize → build-sql
npm run corpus:check # vérifie les invariants du corpusPrérequis : poppler (brew install poppler, ou apt install poppler-utils), pour pdftotext. Requis uniquement pour l'ingestion, exécutée en local ; le texte extrait est versionné et le Worker n'en dépend jamais.
Le manifeste (ingest/manifest.ts) accepte deux formats. Les PDF passent par poppler, avec un mode par source : le mode par défaut convient aux programmes mis en page, raw est réservé aux déclarations CNCCEP dont les colonnes s'entrelaceraient autrement. Les pages HTML passent par ingest/html.ts, qui isole le contenu éditorial du gabarit — sans quoi chaque page injecterait son menu et son pied de page dans le corpus, le pendant HTML des titres courants des PDF.
L'extraction passe par poppler plutôt que par une bibliothèque JS parce que ces programmes mélangent, parfois sur une même page, des paragraphes pleine largeur et des zones à deux colonnes. Les extracteurs qui suivent l'ordre du flux PDF recollent alors la ligne de gauche et celle de droite en une seule phrase — pour un serveur dont la promesse est la citation exacte, c'est disqualifiant : cela fabrique des phrases que le candidat n'a jamais écrites.
Le nettoyage traite ensuite les défauts propres à ces documents : titres courants soudés au texte (détectés par n-grammes répétés entre pages), césures, caractères de contrôle laissés à la place de puces, et mots disloqués par l'interlettrage des titres (« UNE RE TRAITE DIGNE » → « UNE RETRAITE DIGNE »).
corpus:check revérifie l'invariant central : chunk.text est exactement texteSource.slice(charStart, charEnd). C'est ce qui rend une citation vérifiable. Il contrôle aussi que 95 % au moins de chaque document se retrouve dans un passage citable — la couverture est actuellement de 99,7 % à 99,9 %.
Développement
npm install
npm run db:reset:local # applique schema.sql + seed.sql au SQLite local
npm run dev # wrangler dev sur http://localhost:8787
npm run typecheckLe développement local n'a besoin d'aucun compte Cloudflare : --local travaille sur un SQLite dans .wrangler/state, et le database_id de wrangler.jsonc peut rester un placeholder.
Tester le serveur avec l'inspecteur MCP, en transport Streamable HTTP sur http://localhost:8787/mcp :
npx @modelcontextprotocol/inspectorDéploiement
wrangler d1 create civis-corpus # coller le database_id dans wrangler.jsonc
npm run ingest:sql # regénère data/sql/seed.sql
npm run db:reset:remote # applique le schéma et le corpus
npm run deploy
claude mcp add --transport http civis https://french-politics-mcp.mael-app.workers.dev/mcpdb:reset:remote recrée les tables : le corpus est un artefact généré, jamais modifié en place.
Limites de la V1
Le corpus se limite à un scrutin : une position citée engage la campagne présidentielle de 2022, pas la ligne actuelle du parti. Il ne contient ni déclarations médiatiques, ni programmes législatifs. Pour LFI, seule la version abrégée de L'Avenir en commun est librement accessible ; l'édition intégrale est un ouvrage payant.
La recherche est purement lexicale, avec deux conséquences. Une question formulée sans les mots du programme peut ne rien remonter. Et le vocabulaire d'un thème est parfois ambigu : sur l'immigration, « étranger » désigne aussi bien les étrangers en France que les Français de l'étranger, ce qu'aucun réglage lexical ne distingue — c'est précisément ce que la recherche sémantique résoudrait.
FTS5 n'offre pas non plus de correspondance approximative : une coquille dans la requête ne remonte rien. L'extraction par poppler étant propre, le corpus lui-même n'en souffre pas.
Le texte intégral de L'Avenir en commun manque, son seul hébergement libre interdisant le parcours automatisé (voir plus haut). Ses 54 livrets et plans, eux, sont présents.
La recherche sémantique (Vectorize + embeddings multilingues via Workers AI, qui tiennent dans le palier gratuit à cette échelle), les autres scrutins et la détection de positions contradictoires relèvent d'une version ultérieure.
Contribuer
Les règles de contribution, la convention de commit et la marche à suivre pour ajouter une source au corpus sont dans CONTRIBUTING.md. Pour signaler une faille, voir SECURITY.md.
La CI, la configuration Dependabot et les réglages de protection de branche dont elle dépend sont décrits dans .github/AUTOMATION.md.
Licence
Le code est sous Apache-2.0 : src/, ingest/, le schéma de base de données, le manifeste des sources, la taxonomie des thèmes et les métadonnées des partis.
Le texte des programmes dans data/text/ n'est pas couvert par cette licence. Ce sont des œuvres protégées, dont les droits appartiennent aux partis, aux candidats et à leurs éditeurs. Le projet n'en revendique aucun droit et n'en concède aucun. Ce texte est reproduit à des fins documentaires et de citation : le serveur répond en citant mot pour mot, ce qui exige une copie fidèle et vérifiable de la source. Trois des sites de campagne de 2022 ayant déjà disparu, cette copie fait aussi office d'archive.
Chaque document porte son URL de provenance, son empreinte SHA-256 et son parti. La liste complète est dans ingest/manifest.ts, et npm run ingest reproduit data/text/ depuis ces URLs.
Le détail des attributions et la procédure de retrait sont dans NOTICE. Toute demande de retrait d'un ayant droit est honorée sans discussion : le corpus se reconstruit depuis ses sources, retirer un document ne coûte qu'une entrée de manifeste.
Le projet ne prend aucune position politique. Les partis sont traités selon une règle uniforme et le serveur est conçu pour citer, pas pour résumer.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mael-app/french-politics-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server