Borrowing it
Nothing to install: this file belongs to cturkieh/france-data-mcp. Take a copy, put it at the same path in your own repository, and replace the rules that are about this project with yours.
curl -O https://raw.githubusercontent.com/cturkieh/france-data-mcp/main/.claude/skills/mcp-conventions/SKILL.mdgit clone --depth 1 https://github.com/cturkieh/france-data-mcpWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/cturkieh/france-data-mcp/mcp-conventions)<a href="https://agentmods.dev/skills/cturkieh/france-data-mcp/mcp-conventions"><img src="https://agentmods.dev/badge/skills/cturkieh/france-data-mcp/mcp-conventions/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/cturkieh/france-data-mcp/mcp-conventions"><img src="https://agentmods.dev/badge/skills/cturkieh/france-data-mcp/mcp-conventions.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00098 | $0.03241 |
| Opus 5 | $0.00049 | $0.01621 |
| Sonnet 5 | $0.00020 | $0.00648 |
| Haiku 4.5 | $0.00010 | $0.00324 |
Grade B, and why
mcp-conventions scanned grade B with 2 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 5d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Sends data to an external URLmediumData exfiltration
A POST to an outside endpoint may be telemetry or may be exfiltration; either way the mod talks to somewhere, and you should know where.
- **JSON malformé caller → `-32700 Parse error` classé AU SITE de l'accès `req.body`, JAMAIS par CLASSE d'exception dans le catch root** (fix `FRANCE-DATA-MCP-1`, prouvé prod 2026-07-25 — **SUPERSEDE la règle V0.12.2 `er Makes network callslowCapability
Not a fault in itself. Listed so you know the mod talks to something, and to what.
- **JSON malformé caller → `-32700 Parse error` classé AU SITE de l'accès `req.body`, JAMAIS par CLASSE d'exception dans le catch root** (fix `FRANCE-DATA-MCP-1`, prouvé prod 2026-07-25 — **SUPERSEDE la règle V0.12.2 `er How it starts
The opening of the file, as written. The whole thing — 72 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Conventions de code (lib, endpoint, boundary)
Déplacé verbatim depuis
CLAUDE.mdle 2026-09-06 (budget). Source de vérité pour ce périmètre ;CLAUDE.mdne garde que les règles de tête.
Lib (src/) — OSS publiable, pas de Sentry direct.
- Catch jamais silencieux :
console.errorouconsole.warnavec préfixe[france-data-mcp]. RangeErrorpour input invalide au boundary public (mappe JSON-RPC-32602).LookupResult<T>discriminé pour distinguer "pas trouvé" vs "erreur API".- Tests
_resetXForTesting()pour tout module avec état partagé. - Lookup PK qui peut retourner ≤ 1 row →
expectSingleRow(rpc, rows, identifier, hint)(db-helpers.ts). Source unique du pattern « warne LOUD si N > 1, ne throw pas, picke la première » utilisé parfiness_by_num_finess+centres_sante_by_finess. Lehintvoyage dans le warn pour préserver les patterns grep ops (PAS reformuler les call-sites). - Clé de déduplication d'identité = attributs de PERSONNE uniquement, jamais d'attribut de SITE (
raison_sociale, adresse). Un PS multi-sites partage une identité ; mettre un attribut de site dans la clé le scinde en faux doublons (régression P1). L'attribut de site voyage dansadresse/sites[]. - Primitives génériques (texte, maths) →
core/, jamaissante/.sante/importe déjàterritoire/: une primitive danssante/consommée parterritoire/crée une inversion de couche / cycle. Ré-export depuis l'ancien emplacement pour ne pas casser les consommateurs. - Résolution point→commune :
reverseGeocode(adresse) ≠communeContainingPoint(frontières) (V0.26.2,territoire/communes.ts).reverseGeocodecherche l'ADRESSE la plus proche →nullsur un site sans adresse à proximité (industriel isolé / littoral, ex. Orano La Hague) ALORS que le point est DANS une commune. Tout dérivé d'une commune issu dereverseGeocode(permis Sit@del dedynamique_immobiliere, dept definess_sirene_coverage_in_radius) DOIT fallback surcommuneContainingPoint(lat,lon)(point-dans-polygonegeo.api.gouv.fr/communes?lat&lon, frontières IGN AdminExpress). Garde-fou load-bearinglength === 1: sur coords hors-bornes (lat>90…) l'API ignore SILENCIEUSEMENT le filtre géo et renvoie TOUTE la liste alphabétique (34 969 communes,[0]="01001"Ain — faux positif, prouvé prod) → n'exploiter QUElength === 1(un point ∈ 1 commune ;0=mer/hors-France,>1=filtre ignoré →null), JAMAISdata[0]. Fail-safe par contrat (catch→null+warn, jamais throw — n'est appelé que sur un chemin déjà dégradé) ; le throw dereverseGeocode(panne IGN réelle) continue de remonter. Seul un point réellement en mer reste sans commune → dégradation propre conservée. Doctrine smoke/test corollaire : gater sur le STATUS de section (couverture.permis === "ok"), JAMAIS sur une donnée métier volatile (logements_autorises_recent > 0) —runSectionexposeokdès absence de throw, uncountpeut valoir 0 légitimement (Fleury-devant-Douaumont :permis="ok"+ 0 logement) ; le compte voyage en INFO.scripts/smoke-deploy.mjsencode ces 2 doctrines (gate-sur-status + params boundary{lat,lon,radius_km,naf}jamais{center,radiusKm}= signature lib interne →-32602). - Resolver SIRET — le
best_matchprivilégie l'établissement ACTIF co-localisé, JAMAIS le score d'adresse seul (V0.16, fix succession M&A —siret-resolver.ts).disambiguateFallbackCandidatesapplique une étape « actif prime » AVANT le name filter : si ≥ 1 candidat actif est co-localisé avec le FINESS, lebest_matchest arbitré parmi les actifs ; les SIRET fermés du site restent danscandidates[](timeline) mais ne sont plus best_match-éligibles. Co-localisation = distance haversine (core/geo-distance.ts) ≤COLOCATION_RADIUS_M100 m (V0.16.1, recalibré prod 2026-05-29 — était 50 m), JAMAIS le Dice d'adresse (qui ne discrimine pas le numéro de voie — un voisin au n°48 d'une avenue score 0,90 vs le n°85 du FINESS, prouvé prod). Pourquoi 100 et plus 50 : le géocodage DREES (Lambert93, grossier) décale le point FINESS de plusieurs dizaines de mètres du point BAN de l'adresse — décalage PARTAGÉ par tous les SIRET de cette adresse. Deux repreneurs M&A réels (Cerballiance Aulnay 52,1 m, EYLAU Courbevoie 96,6 m) ressortaient à la distance IDENTIQUE de leur ancien exploitant fermé (même adresse) mais juste au-dessus de 50 m → faux négatifferme. 100 m couvre ces décalages, sous le voisin-piège testé ~110 m. Garde-fou faux positif inverse au rayon élargi = bande RELATIVECOLOCATION_SAME_SITE_TOLERANCE_M(30 m) : parmi les co-localisés, seuls ceux à≤ min(distance) + 30 m(« même bâtiment ») sont best_match-éligibles ; un voisin actif d'une AUTRE adresse, plus loin qu'un prédécesseur fermé co-localisé, ne bascule pas le verdict enactif(test garde-fou voisin 80 m / prédécesseur 30 m). NE PAS reverter à 50 m sans relire la preuve prod (les 2 repreneurs redeviendraient invisibles ; le site EYLAU légitime à 46,6 m reste co-localisé dans les deux calibrations). Le fallback géo est aussi armé quand lebest_matchRPPS est FERMÉ (L1 — sinon le repreneur d'un autre SIREN reste invisible). Champsuccessionexposé (fait brut — le tool ne dit jamais « rachat »). Garde-fous :cross-source.test.ts(Méca A chemin RPPS / Méca B fallback géo / faux positif inverse) +geo-distance.test.ts. Cadrage durable :docs/plans/verifier-site-actif-succession-fix.md.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 5d ago First seen · 72 lines · 98 tokens per session scan B 51319935d71d
mcp-conventions is a skill published in the GitHub repository cturkieh/france-data-mcp (3 stars, last pushed 4d ago), licensed MIT. It adds 98 tokens to every session and 3,241 once invoked, about $0.0005 per session on Opus 5. A static security scan graded it B with 2 findings (sends data to an external url, makes network calls). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-06.
Other skills, from other repositories
event-store-design
Design and implement event stores for event-sourced systems. Use when building event sourcing infrastructure, choosing event store technologies, or implementing event persistence patterns.
convex-explain-app
Explain an existing Convex app — data model + relationships, public vs internal functions, auth/ownership model, components, a request→data flow — read from the schema and function surface. Read-only.
platform-custom-field-generate
Use this skill when users need to create, generate, or validate Salesforce Custom Field metadata. Trigger when users mention custom fields, field types, Roll-up Summary fields, Master-Detail relationships, Lookup relationships, formula fields, picklists, dependent (controlling) picklists, referencing a value set from…
field-service-sobject-create-configure
Headless 360 REST API deployment step for creating sObject records. Handles describe-based field discovery, required-field derivation, entity-relationship ordering, and composite graph transactions. Use this skill when a designer skill (or a user directly) needs to create sObject records after design confirmation…
durable-objects
Build, debug, or review Cloudflare Durable Objects code for persistent state and coordination.
nornicdb-grpc
Drive NornicDB over gRPC — the Qdrant-compatible surface (Collections, Points, Snapshots) plus the additive NornicSearch service. Use when ingesting via Qdrant SDKs, migrating from Qdrant, or running hybrid text+vector search from a non-Bolt client. Covers connection, RPC catalog, collection→database mapping…