# OpenLegi - Documentation complète > Serveur MCP pour l'accès aux sources juridiques françaises officielles ## Présentation OpenLegi est un serveur MCP (Model Context Protocol) qui permet aux LLMs d'accéder directement aux bases de données juridiques françaises : Légifrance, RNE (Registre National des Entreprises) et EUR-Lex. ## Configuration rapide ### Claude Desktop ```json { "mcpServers": { "Legifrance": { "type": "streamable-http", "url": "https://mcp.openlegi.fr/legifrance/mcp", "headers": { "Authorization": "Bearer VOTRE_TOKEN" } } } } ``` ## Liens - Documentation web : https://auth.openlegi.fr/documentation/ - Dashboard (obtenir token) : https://auth.openlegi.fr/users/dashboard/ - Contact : https://auth.openlegi.fr/contact/ - Endpoint MCP : https://mcp.openlegi.fr/legifrance/mcp --- ## Démarrage rapide Configurer OpenLegi MCP en quelques minutes ### FAQ — Questions fréquentes ## Pour commencer ### Ai-je besoin de savoir programmer pour utiliser OpenLegi ? Non. Dans l'usage courant, vous branchez OpenLegi à votre assistant IA (Claude, ChatGPT, Mistral) une seule fois, puis vous posez vos questions en français, normalement. Par exemple : « Quels sont les derniers arrêts du Conseil d'État sur les marchés publics ? » La configuration initiale se résume à coller une adresse et à vous connecter. Les pages de documentation qui contiennent du code Python s'adressent aux équipes qui veulent intégrer OpenLegi dans leur propre logiciel — vous pouvez les ignorer. ### Est-ce gratuit ? Oui pour l'usage courant. La création de compte et l'accès aux sources officielles sont gratuits, avec des clés d'accès partagées entre les utilisateurs et donc une limite de débit. Si vous atteignez cette limite, vous pouvez déclarer vos propres identifiants PISTE (le portail officiel de l'État) dans votre tableau de bord : vos requêtes ne sont alors plus décomptées sauf limite anti-abus. La démarche est gratuite mais l'approbation par PISTE peut prendre quelques jours. **Ce qui restera gratuit.** L'accès aux sources publiques telles que l'État les diffuse — Légifrance via PISTE, le Journal officiel, les codes, la jurisprudence. C'est de la donnée publique : la rendre interrogeable depuis un assistant IA n'a pas vocation à être facturé. **Ce qui sera payant.** Ce qu'OpenLegi ajoute par-dessus, et qui suppose un travail d'indexation et d'infrastructure : - les **bases enrichies**, avec recherche lexicale et sémantique, qui vont au-delà de ce que permet l'interrogation directe des API officielles ; - les **autres modes d'accès**, à commencer par l'API REST destinée aux intégrations qui ne passent pas par le protocole MCP. Quatre sources (législation européenne, jurisprudence administrative et judiciaire et accords d'entreprises ) sont d'ores et déjà réservées aux abonnements. Enfin, certaines plateformes d'IA exigent leur propre abonnement payant pour utiliser les connecteurs : c'est le cas de Claude et de ChatGPT, indépendamment d'OpenLegi. ### Avec quels assistants IA cela fonctionne-t-il ? Avec ceux qui gèrent le protocole MCP : Claude (web et bureau), ChatGPT, Mistral, Microsoft Copilot Studio, ainsi que les environnements de développement VS Code et Cursor. Perplexity fonctionne partiellement, sur son application de bureau uniquement. Le tableau détaillé, avec le mode de connexion et l'abonnement requis pour chaque plateforme, est sur la page « Liste des services compatibles ». --- ## Fiabilité et usage professionnel ### Les résultats sont-ils à jour ? **Ils le sont exactement autant que Légifrance, ni plus ni moins.** Sauf dans le cas de l'offre sur abonnement, OpenLegi n'héberge aucune copie des données de l'opendata juridique. Chaque requête part vers l'API officielle et vous renvoie ce que Légifrance expose à cet instant. Nous ne pouvons donc pas être plus à jour que la source : **nous héritons intégralement de son rythme de mise à jour**, y compris de ses délais. Trois décalages peuvent s'additionner : 1. **Le rythme de Légifrance lui-même.** Un texte paru au Journal officiel n'apparaît pas instantanément dans les bases, et sa **consolidation** — l'intégration de ses modifications dans les textes qu'il modifie — intervient plus tard encore. Un article peut donc être affiché dans une version que la loi la plus récente a déjà modifiée. 2. **La publication la plus récente**, qui peut accuser quelques heures de retard. 3. **Notre mise en cache**, qui ajoute un délai court destiné à ménager l'API officielle. Les deux derniers se comptent en heures. Le premier échappe à OpenLegi comme à quiconque interroge Légifrance : c'est le fonctionnement du service public de diffusion du droit. ### Comment vérifier qu'un texte est bien à jour ? **En ouvrant le lien.** Chaque résultat est accompagné d'un lien vers la source officielle, et **seul le texte consulté sur Légifrance fait foi**. Prenez ce réflexe systématiquement, et pas seulement en cas de doute : une réponse d'assistant IA peut être parfaitement bien formée, citer un numéro d'article plausible et afficher un lien d'apparence correcte, tout en restituant un texte périmé, tronqué ou reformulé. Rien dans la réponse ne vous signalera l'écart — seule la consultation de la source le révèle. La règle vaut pour tout usage professionnel, juridique ou décisionnel. Voir aussi la page « Limitations connues ». ### Puis-je citer un résultat dans une écriture ou un acte ? **Pas directement, et c'est important.** OpenLegi est une interface d'accès à Légifrance, pas un substitut à Légifrance. Ce que vous lisez dans une réponse — surtout reformulée par un assistant IA — est une représentation intermédiaire du texte officiel, pas le texte officiel lui-même. Chaque résultat contient un lien vers la source officielle. **Pour tout usage professionnel, vérifiez le texte sur Légifrance via ce lien avant de le citer, de le commenter ou de l'appliquer.** Ne vous fiez jamais à la seule réponse d'un chatbot, même lorsqu'elle affiche un identifiant ou un lien Légifrance d'apparence correcte. La page « Limitations connues » détaille les cas où l'écart entre la réponse et le texte officiel a été observé : renumérotation d'articles, références internes orphelines, troncature, reformulation par le modèle. ### Mes recherches sont-elles confidentielles ? OpenLegi journalise les appels pour des raisons techniques : horodatage, outil appelé, service concerné, code de statut et temps de réponse. **Le contenu de vos recherches — vos mots-clés, vos questions — n'est pas enregistré dans ces journaux.** Ils sont purgés automatiquement au bout de 90 jours. Attention en revanche : votre conversation elle-même est traitée par l'éditeur de votre assistant IA (Anthropic, OpenAI, Mistral…) selon **ses** propres conditions, sur lesquelles OpenLegi n'a pas la main. Pour des informations ou des documents confidentiels, c'est ce point-là qu'il faut examiner. Voir la [politique de confidentialité](/documentation/legal/politique-de-confidentialite/). --- ## Utilisation ### Combien de requêtes puis-je faire ? Avec les clés partagées, l'usage est limité pour garantir la disponibilité du service à tous. En déclarant vos propres identifiants PISTE dans le tableau de bord, vos requêtes ne sont plus décomptées (sauf limite anti-abus) Vous pouvez suivre votre consommation en temps réel depuis votre tableau de bord. ### Ma recherche ne retourne rien, pourquoi ? Trois causes, par ordre de fréquence : 1. **Trop de mots-clés.** Par défaut, la recherche exige que *tous* les mots soient présents dans le même champ. Retirez les mots accessoires et gardez les termes juridiques. 2. **Orthographe et accents.** Les accents comptent dans les index Légifrance. 3. **Mauvaise base.** Un texte non codifié ne se trouve pas dans les codes : voir la question suivante. Si le problème persiste, demandez simplement à votre assistant d'élargir la recherche — il sait ajuster les paramètres. ### Quelle est la différence entre les codes et les textes consolidés (LODA) ? - **Codes** : les 73 codes juridiques organisés — Code civil, Code du travail, Code pénal… - **LODA** : tous les autres textes consolidés, c'est-à-dire ceux qui ne sont pas codifiés — lois non codifiées, ordonnances, décrets, arrêtés. En pratique : si vous cherchez un article numéroté d'un code, c'est « codes ». Si vous cherchez une loi par son numéro et son année (par exemple la loi 78-17), c'est « LODA ». ### À quoi sert le mode « panorama » ? Il ne renvoie que les métadonnées et les résumés, sans le texte intégral. C'est utile pour balayer un grand nombre de résultats et repérer ceux qui méritent d'être ouverts, sans saturer la fenêtre de contexte de votre assistant. Vous demandez ensuite le texte complet des seules décisions retenues. --- ## Connexion ### Faut-il utiliser OAuth ou un token dans l'URL ? **OAuth quand votre client le permet** (claude.ai, ChatGPT, Mistral) : vous vous connectez une fois, aucun secret à copier, et l'accès se renouvelle puis expire tout seul. **Le token dans l'URL** reste nécessaire pour les clients qui ne gèrent pas OAuth — Claude Desktop en configuration locale, VS Code, Cursor. Le token est alors un secret permanent : ne le partagez pas, et préférez, quand c'est possible, le passer dans l'en-tête `Authorization: Bearer` plutôt que dans l'URL. Les deux modes coexistent et resteront disponibles. Voir « Les deux modes de connexion ». ### Dois-je saisir un « Client ID » ? **Cela dépend de votre client, et dans beaucoup de cas : non.** Pour se connecter en OAuth, le client MCP doit d'abord s'identifier auprès d'OpenLegi. Deux méthodes coexistent, et c'est le client qui choisit : **Identification automatique (CIMD).** Le client présente l'adresse de son propre document de métadonnées en guise d'identifiant. OpenLegi va le chercher, le valide et enregistre le client tout seul. **Vous n'avez rien à saisir** : vous collez l'URL du serveur MCP, vous vous connectez, c'est terminé. **Identifiant pré-enregistré.** Si votre client vous demande explicitement un « Client ID », c'est qu'il ne gère pas l'identification automatique. Collez alors l'identifiant public correspondant à votre plateforme, listé sur la page « Problème connexion spécifique à Claude ». Dans les deux cas, **le champ « Client Secret » doit rester vide** : OpenLegi utilise des clients publics sécurisés par PKCE, sans secret partagé. ### Claude me demande un « Client ID », est-ce une erreur ? Non. Selon la façon dont le connecteur est ajouté, Claude s'identifie automatiquement ou vous réclame un Client ID — les deux parcours sont valides et mènent au même résultat. Ce qui a changé : jusqu'à l'été 2026, OpenLegi ne connaissait que le token dans l'URL et la fenêtre OAuth de Claude menait à une impasse. OpenLegi étant désormais serveur d'autorisation OAuth 2.0 / OpenID Connect, cette demande fait partie du parcours normal. Si Claude vous demande un Client ID, collez l'identifiant public indiqué sur la page « Problème connexion spécifique à Claude », et laissez « Client Secret » vide. --- ## Et ensuite ### Une API REST est-elle prévue ? Oui. Une API REST couvrant l'ensemble du périmètre Légifrance, et au-delà (EUR-Lex notamment), est en préparation pour les équipes qui souhaitent intégrer ces sources dans leur propre logiciel, sans passer par le protocole MCP. Ce sera une **offre commerciale** : contrairement à l'accès MCP aux sources publiques, elle suppose une infrastructure dédiée et des garanties de service. Les modalités seront précisées à l'ouverture — vous pouvez demander à en être prévenu. ### Les bases enrichies, c'est quoi ? Les API officielles répondent bien quand vous savez ce que vous cherchez : un article, un numéro de texte, des mots-clés exacts. Elles montrent leurs limites dès que la question est formulée en langage naturel, ou qu'un même concept se dit de plusieurs façons selon les textes. Les bases enrichies ajoutent une couche d'indexation propre à OpenLegi, combinant recherche lexicale et recherche sémantique, pour retrouver des textes pertinents même sans les termes exacts. C'est ce travail d'indexation qui distingue l'offre payante de l'accès gratuit aux sources brutes. ### Comment signaler une erreur ou demander une source ? Par le [formulaire de contact](/contact/), ou depuis l'espace support si vous avez un compte. Les signalements d'écart entre une réponse et le texte officiel sont particulièrement utiles : ils alimentent notamment la page « Limitations connues ». ### Clés API personnelles Par défaut, OpenLegi utilise des **clés API partagées** avec des limites de débit. Pour un usage intensif ou professionnel, vous pouvez configurer vos propres credentials PISTE. Vous pouvez vous aider d'un [tutoriel complet](http://www.christopheqa.fr/claude/openlegi-piste-claude.md) à copier/coller directement dans Claude. ### Avantages des clés personnelles Pour le moment, les clés personnelles offrent les avantages suivants: - **Aucune limite de débit** — Pas de quota partagé avec d'autres utilisateurs - **Mode illimité** — Vos requêtes ne sont plus comptabilisées sauf abus (burst) - **Stockage sécurisé** — Vos credentials sont chiffrés ### Obtenir vos credentials PISTE 1. Rendez-vous sur [https://piste.gouv.fr](https://piste.gouv.fr) (portail PISTE) 2. Créez un compte ou connectez-vous 3. Créez une **application** et souscrivez à l'**API Legifrance** 4. Attendez l'**approbation** de votre application (peut prendre quelques jours) 5. Une fois approuvée, accédez à votre application en environnement **Production** 6. Récupérez votre **identifiant OAuth (pas API Keys)** (= Client ID) et votre **Consumer Secret** (= Client Secret) ### Configurer dans OpenLegi 1. Connectez-vous sur [auth.openlegi.fr](https://auth.openlegi.fr) 2. Accédez à votre [Dashboard](https://auth.openlegi.fr/users/dashboard/) 3. Onglet **Clés OAuth** → cliquez sur **Ajouter une clé** 4. Renseignez un nom, votre Client ID et Client Secret 5. La validation automatique teste vos credentials (jusqu'à 30 secondes) 6. Si la validation réussit, votre clé passe en statut **Active** ### Statuts possibles | Statut | Signification | Action | |--------|--------------|--------| | **Active** | Credentials valides, prêts à l'emploi | Rien à faire | | **En attente** | La validation n'a pas pu aboutir (timeout) | Cliquez sur **Tester** pour relancer | | **Invalide** | Credentials rejetés par l'API PISTE | Vérifiez vos credentials (voir erreurs courantes) | ### Erreurs courantes **"Client ID ou Client Secret invalide"** (erreur invalid_client) - Vérifiez que vous utilisez les credentials de l'environnement **Production** (pas Sandbox) - Vérifiez que votre application PISTE est bien **approuvée** (statut "Approved") - Attention aux **espaces invisibles** lors du copier-coller - Le Consumer Key et le Consumer Secret sont différents du login/mot de passe PISTE **"Timeout de connexion"** - Le serveur de validation n'a pas répondu à temps - Cela peut indiquer des credentials invalides (le serveur retente plusieurs fois avant d'échouer) - Vérifiez d'abord vos credentials, puis cliquez sur **Tester** **"Accès interdit"** (erreur 403) - Votre application PISTE n'a probablement pas souscrit à l'API Legifrance - Connectez-vous sur le portail PISTE et vérifiez vos souscriptions ### Gestion des clés - **Une seule clé active par provider** — Supprimez l'ancienne avant d'en créer une nouvelle - **Bouton Tester** — Relance la validation à tout moment - **Bouton Supprimer** — Supprime la clé et repasse automatiquement en clés partagées - **Toggle "Clés personnelles"** — Active/désactive l'utilisation de vos clés (nécessite une clé active) ### Les deux modes de connexion : OAuth et token dans l'url ou le header Pour connecter un client MCP (Claude, Mistral, etc.) à OpenLegi, deux modes d'authentification sont disponibles. **Ils coexistent** : choisissez celui qui convient à votre client. | | **OAuth 2.0** | **Token** | |---|---|---| | Principe | Vous vous connectez à OpenLegi, le client obtient un jeton temporaire | Un token personnel est intégré à l'URL du serveur MCP | | Mise en place | URL de base + identification du client (Client ID ou CIMD), puis connexion | Copier-coller l'URL déjà pré-remplie avec votre token ou dans le header (Bearer) en POST | | Sécurité | Élevée : jeton signé, à durée de vie limitée, renouvelé automatiquement | Le token est un secret permanent à ne pas divulguer | | Recommandé pour | **claude.ai**, **ChatGPT**, **Mistral Vibe** | **Claude Desktop** (config locale), VS Code / Cursor, autres clients | | Client ID à saisir | Selon la méthode : oui (pré-enregistré) ou non (CIMD, automatique) | Non | ## Mode 1 — OAuth 2.0 (recommandé pour claude.ai, ChatGPT, Mistral) OpenLegi est un serveur d'autorisation **OAuth 2.0 / OpenID Connect**. Le client MCP ne manipule jamais votre token permanent : il obtient un jeton d'accès temporaire (JWT), signé par OpenLegi et à durée de vie limitée. Vous vous authentifiez une fois via Microsoft ou votre email / mot de passe, et l'accès se renouvelle automatiquement. Le déroulé est le même quel que soit le client : 1. Ajoutez un **connecteur MCP** avec l'URL de base, **sans token** : ``` https://mcp.openlegi.fr/legifrance/mcp ``` 2. Le connecteur s'identifie auprès d'OpenLegi — **deux méthodes possibles** (voir ci-dessous). 3. Connectez-vous à **OpenLegi** et **autorisez** l'accès aux sources demandées. ### Méthode A — Client ID pré-enregistré (disponible aujourd'hui) Dans le champ **Client ID** du connecteur, collez l'identifiant public correspondant à votre client, en laissant le **Client Secret vide** (client public sécurisé par PKCE) : | Client | Client ID OpenLegi à saisir | |---|---| | Claude (claude.ai) | `nqyiazmWHxa3qCVSyhktSwvqClpiuBYTPGEQlFsE` | | ChatGPT | `yPmrEkKZHW5C5hGuI523JmgsK3HHwjR2A0qn8L6s` | | Mistral Vibe | `hZ7TfVcWnRDywnChOs8VuXHpvI94L3WiO9juPB4L` | | Perplexity | `eHHQX1c64F9ont9o4Zq5pR5BSUpISXnZunpTWFdy ` | ### Méthode B — Identification automatique / CIMD Les clients les plus récents savent s'identifier **tout seuls**, sans aucun Client ID à copier : ils présentent leur propre identifiant sous la forme d'une **URL de métadonnées** (spécification *Client ID Metadata Document*, CIMD). OpenLegi récupère cette URL et reconnaît le client automatiquement. Avec un client compatible : vous ajoutez l'URL du serveur, vous cliquez sur **« Se connecter avec OpenLegi »**, et c'est tout — **aucun Client ID à saisir**. > Cette méthode est expérimentale et n'est pas acceptée par tous les services. Tant qu'elle n'est pas disponible pour votre client, utilisez la **méthode A** (Client ID pré-enregistré). ### Périmètre d'accès (scopes) Lors de l'autorisation, le client peut demander l'accès à une ou plusieurs sources. OpenLegi n'accorde que celles auxquelles votre compte a droit : - `legifrance` — JORF, Codes, Jurisprudence, LODA ``` https://mcp.openlegi.fr/legifrance/mcp ``` - `rne` — Registre National des Entreprises ``` https://mcp.openlegi.fr/rne/mcp ``` - `bofip` — Doctrine fiscale (BOFiP) ``` https://mcp.openlegi.fr/bofip/mcp ``` - `bodacc` — Annonces civiles et commerciales (BODACC) ``` https://mcp.openlegi.fr/bodacc/mcp ``` - `eurlex` — Législation européenne ``` https://mcp.openlegi.fr/eurlex/mcp ``` Un retrait d'accès côté OpenLegi prend effet au renouvellement suivant (moins d'une heure). ## Mode 2 — Token dans l'URL Historique et toujours pris en charge. Votre token personnel est intégré à l'URL du serveur MCP. C'est le mode le plus simple pour **Claude Desktop configuré localement** et les clients qui ne gèrent pas l'OAuth. ### Étapes 1. Ouvrez votre [tableau de bord](https://auth.openlegi.fr/users/dashboard/) et copiez l'URL du service voulu (elle contient déjà votre token) : ``` https://mcp.openlegi.fr/legifrance/mcp?token=VOTRE_TOKEN ``` 2. Collez cette URL dans la configuration de votre client MCP. Exemple pour **Claude Desktop** (`claude_desktop_config.json`) : ```json { "mcpServers": { "legifrance": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-fetch"], "env": { "FETCH_URL": "https://mcp.openlegi.fr/legifrance/mcp?token=VOTRE_TOKEN" } } } } ``` > **Gardez ce token secret.** Il donne accès à vos outils MCP. En cas de fuite, régénérez-le depuis le tableau de bord (l'ancien cesse alors immédiatement de fonctionner). ## Quel mode choisir ? - **Sur claude.ai, ChatGPT ou Mistral Le Chat** : privilégiez l'**OAuth**. Plus sûr, rien (ou presque) à copier, connexion renouvelée automatiquement. Voir aussi [Claude demande un « Client ID »](/documentation/demarrage-rapide/probleme-de-connexion-claude/). - **Sur Claude Desktop en local, VS Code / Cursor, ou un client sans OAuth** : utilisez le **token dans l'URL ou dans le header**. Dans les deux cas, l'accès réel aux sources et vos limites d'usage sont identiques : seul le mécanisme d'authentification change. ### Liste des services compatibles OpenLegi expose ses sources via le protocole **MCP** (Model Context Protocol). La plupart des assistants IA qui gèrent les connecteurs MCP peuvent donc s'y brancher. Le tableau ci-dessous précise, pour chaque plateforme, le **mode d'authentification** à utiliser (voir [Les deux modes de connexion](/documentation/demarrage-rapide/deux-modes-connexion/)) et l'**abonnement** requis côté plateforme. Ce tableau est amené à évoluer très rapidement. Il est plus fiable de se renseigner directement sur le site du service concerné pour se tenir au courant des mises à jour. | Plateforme | Compatibilité MCP | Mode d'authentification OpenLegi | Abonnement de la plateforme | Notes | |---|---|---|---|---| | **Claude — web & bureau (claude.ai)** | Native (connecteurs personnalisés) | **OAuth** (recommandé) ou token dans l'URL | Payant — plan Pro / Max / Team / Enterprise | Mode recommandé. Voir [Client ID demandé](/documentation/demarrage-rapide/deux-modes-connexion/) | | **Claude Desktop (config locale)** | Native (`claude_desktop_config.json`) | Token dans l'URL | Gratuit | Via `mcp-remote` / `server-fetch` | | **ChatGPT** | Native (mode Développeur / connecteurs) | **OAuth** | Payant — Plus / Pro / Business / Enterprise | Auparavant non compatible ; désormais pris en charge via OAuth | | **Mistral Vibe (Nouveau)** | Native (« Connecteurs ») | **OAuth** ou token | Selon l'offre Mistral | Section Connecteurs / Intelligence | | **Microsoft Copilot Studio** | Native (config serveur MCP) |**OAuth** ou token | Entreprise | Contexte entreprise | | **VS Code / Cursor** | Extensions MCP (Continue, Cline…) | Token | Gratuit (hors licence de l'IDE) | Environnements de développement | | **Perplexity** | Partielle | Token dans l'URL | Selon l'offre de l'éditeur | Application de bureau uniquement | | **JetBrains (IntelliJ, PyCharm…)** | Partielle (plugins tiers) | Token | Selon l'offre de l'éditeur | En cours de maturation | | **Google Gemini** | Non (pas de MCP natif dans l'app) | — | — | Le connecteur MCP grand public n'est pas disponible | ## Légende - **OAuth** : vous vous connectez à OpenLegi ; le client obtient un jeton temporaire. Le plus sûr. Selon le client, soit vous collez le **Client ID public OpenLegi** de votre plateforme, soit l'identification est automatique (**CIMD**, en cours d'activation). Détail : [Les deux modes de connexion](/documentation/demarrage-rapide/deux-modes-connexion/). - **Token** : votre token personnel est intégré à l'URL du serveur MCP, copiée depuis le [tableau de bord](https://auth.openlegi.fr/users/dashboard/). - **Abonnement de la plateforme** : les connecteurs MCP distants sont, chez plusieurs éditeurs, réservés aux offres payantes de **leur** plateforme. Cela ne concerne pas OpenLegi (voir ci-dessous). Ces conditions évoluent : vérifiez l'offre en vigueur chez chaque éditeur. ### Configuration Claude Desktop Cette page concerne **Claude Desktop en configuration locale**, c'est-à-dire l'édition manuelle du fichier `claude_desktop_config.json`. Si vous utilisez **claude.ai** (web ou application de bureau) avec les connecteurs, ne suivez pas cette page : passez par OAuth, c'est plus simple et plus sûr. Voir « Les deux modes de connexion » et « Problème connexion spécifique à Claude ». ## Avant de commencer Récupérez votre token sur le [tableau de bord](https://auth.openlegi.fr/users/dashboard/). C'est un secret permanent : traitez-le comme un mot de passe. ## Configuration recommandée Elle transmet le token dans l'**en-tête HTTP**, où il n'apparaît ni dans les journaux d'URL ni dans votre historique de commandes. ```json { "mcpServers": { "OpenLegi": { "type": "streamable-http", "url": "https://mcp.openlegi.fr/legifrance/mcp", "headers": { "Authorization": "Bearer VOTRE_TOKEN" } } } } ``` ## Repli pour les versions plus anciennes Si votre version de Claude Desktop ne gère pas `streamable-http`, passez par `mcp-remote`, qui fait le pont : ```json { "mcpServers": { "OpenLegi": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://mcp.openlegi.fr/legifrance/mcp", "--header", "Authorization: Bearer VOTRE_TOKEN" ] } } } ``` Vous rencontrerez parfois une variante qui place le token directement dans l'URL (`...?token=VOTRE_TOKEN`). Elle fonctionne, mais **évitez-la si vous le pouvez** : le secret circule alors dans l'URL, susceptible d'être enregistré par des intermédiaires. Cette configuration nécessite [Node.js](https://nodejs.org) installé sur votre machine. ## Où se trouve le fichier | Système | Chemin | |---|---| | macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` | | Windows | `%APPDATA%\Claude\claude_desktop_config.json` | | Linux | `~/.config/Claude/claude_desktop_config.json` | Si le fichier n'existe pas, créez-le avec le contenu ci-dessus. S'il existe déjà et contient d'autres serveurs, ajoutez seulement l'entrée `"OpenLegi"` à l'intérieur de l'objet `mcpServers` existant — n'écrasez pas le fichier. **Redémarrez complètement Claude Desktop** après modification : fermer la fenêtre ne suffit pas, quittez l'application. ## Ajouter les autres services Chaque service a son propre point d'accès. Ajoutez une entrée par service souhaité : | Service | URL | |---|---| | Légifrance | `https://mcp.openlegi.fr/legifrance/mcp` | | RNE (entreprises) | `https://mcp.openlegi.fr/rne/mcp` | | EUR-Lex (droit européen) | `https://mcp.openlegi.fr/eurlex/mcp` | RNE et EUR-Lex sont accessibles sur abonnement — voir la page d'accueil pour en demander l'activation. ## Vérifier que ça marche Posez une question qui ne peut aboutir que par un appel d'outil, par exemple : > « Donne-moi l'article 1240 du Code civil. » Claude doit indiquer qu'il utilise un outil OpenLegi et vous répondre avec un lien vers Légifrance. Si rien ne se passe, vérifiez dans l'ordre : 1. L'application a bien été **quittée puis relancée**. 2. Le JSON est **valide** — une virgule en trop suffit à faire ignorer tout le fichier. 3. Le token est correct : testez-le avec `curl https://mcp.openlegi.fr/health` (ce point d'accès ne demande pas d'authentification et confirme que le service répond). La page « Dépannage — codes d'erreur » détaille les erreurs 400, 401 et 403. ### Problème connexion spécifique à Claude # Claude demande un « Client ID » : c'est désormais normal Cette page concerne le connecteur OpenLegi ajouté dans Claude (claude.ai, sur le web comme sur l'application de bureau). Si, lors de l'ajout du connecteur ou d'une reconnexion, Claude affiche une demande de « Client ID », **ce n'est plus une erreur** : c'est le nouveau mode de connexion sécurisé d'OpenLegi. Voici quoi saisir. > **Ce qui a changé.** Jusqu'à l'été 2026, OpenLegi s'authentifiait uniquement par un token intégré à l'URL, et la fenêtre OAuth de Claude menait à une impasse. **OpenLegi est désormais un serveur d'autorisation OAuth 2.0 / OpenID Connect** : la demande de « Client ID » fait maintenant partie du parcours de connexion normal. Les deux modes coexistent — voir [Les deux modes de connexion](/documentation/demarrage-rapide/deux-modes-connexion/). ## Connecter OpenLegi en OAuth (claude.ai) 1. Dans Claude, ouvrez **Paramètres → Connecteurs → Ajouter un connecteur personnalisé**. 2. Renseignez l'**URL du serveur MCP**, sans token : ``` https://mcp.openlegi.fr/legifrance/mcp ``` 3. Lorsque Claude demande un **Client ID**, collez le Client ID public OpenLegi pour Claude : ``` nqyiazmWHxa3qCVSyhktSwvqClpiuBYTPGEQlFsE ``` Laissez le champ **Client Secret vide** (OpenLegi utilise un client public sécurisé par PKCE, sans secret). 4. Validez : Claude vous redirige vers **OpenLegi**. Connectez-vous (Microsoft ou email / mot de passe), puis **autorisez l'accès** aux sources demandées. 5. C'est terminé. Aucun token à copier : la connexion se renouvelle automatiquement et expire d'elle-même, ce qui est plus sûr. Vous pouvez répéter l'opération pour les autres services en changeant le chemin de l'URL : `/rne/mcp`, `/bofip/mcp`, `/bodacc/mcp`, `/eurlex/mcp`. > **Bientôt : connexion sans Client ID.** OpenLegi met en place l'identification automatique des clients (*Client ID Metadata Document*) : avec un client compatible, vous n'aurez plus aucun Client ID à saisir — un simple « Se connecter avec OpenLegi » suffira. En attendant, utilisez le Client ID ci-dessus. Détails sur [Les deux modes de connexion](/documentation/demarrage-rapide/deux-modes-connexion/). ## Vous préférez l'ancien mode (token dans l'URL) ? Il reste **entièrement pris en charge**, notamment pour Claude Desktop configuré localement, Mistral Le Chat ou tout autre client MCP. Dans ce cas, vous n'avez pas de Client ID à saisir : vous collez directement l'URL contenant votre token, disponible sur votre [tableau de bord](https://auth.openlegi.fr/users/dashboard/). Le détail des deux approches est décrit sur la page [Les deux modes de connexion](/documentation/demarrage-rapide/deux-modes-connexion/). ## Si la connexion OAuth échoue - **« invalid_client » ou Client ID refusé** : vérifiez que vous avez collé le Client ID public OpenLegi ci-dessus, sans espace avant/après, et que le champ Client Secret est bien **vide**. - **Vous restez bloqué sur l'écran de connexion OpenLegi** : ouvrez d'abord [votre tableau de bord](https://auth.openlegi.fr/users/dashboard/) dans le même navigateur pour vérifier que votre compte est actif, puis réessayez. - **Aucun outil ne répond après connexion** : supprimez le connecteur dans Claude puis ré-ajoutez-le en suivant les étapes ci-dessus. ## Solution de repli : Claude Desktop en local L'application Claude Desktop configurée localement fonctionne indépendamment de l'OAuth, avec le token dans l'URL : ```json { "mcpServers": { "legifrance": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-fetch"], "env": { "FETCH_URL": "https://mcp.openlegi.fr/legifrance/mcp?token=VOTRE_TOKEN" } } } } ``` Si le problème persiste, ouvrez un ticket depuis votre [espace support](https://auth.openlegi.fr/support/) en précisant la date et l'heure de votre dernière tentative : cela nous permet de croiser votre signalement avec les journaux de notre passerelle. ### Limitations connues > ## ⚠️ Avertissement important — nature des résultats > > **OpenLegi est une interface d'accès à la base Légifrance, pas un substitut à Légifrance.** > > Les résultats transitent par une API qui opère un filtre, une mise en forme et une mise en cache sur les données brutes de Légifrance. Ce que vous lisez dans une réponse d'outil — ou dans la réponse d'un assistant IA — est une **représentation intermédiaire** du texte officiel, pas le texte officiel lui-même. > > **Règle absolue : pour tout usage professionnel, juridique ou décisionnel, toujours vérifier le texte sur [Légifrance](https://www.legifrance.gouv.fr) via le lien `article_lc` fourni dans les métadonnées.** Ce lien pointe vers la source officielle faisant foi. > > Ne jamais citer, commenter ou appliquer un texte de loi sur la seule foi d'une réponse d'un chatbot ou d'un outil IA, même lorsque celui-ci affiche un lien ou un identifiant Légifrance. --- > ⚠️ **Limite de cette documentation.** Les observations ci-dessous sont issues d'un échantillon limité de **12 cas tests** conduits sur quelques codes et lois. Elles documentent des comportements observés, non des comportements générals de fonctionnement. Tout comportement non testé doit être considéré comme inconnu jusqu'à vérification. Cette documentation s'intéresse principalement au fonds LEGI et ne documente pas les limitations connues sur les autres. Par exemple, JUDILIBRE présente des doublons (régression de pseudonymisation) sur les décisions des tribunaux de commerce. Ces limitations feront l'objet d'une documentation séparée lors de la publication de ce fonds. --- ## Périmètre de couverture | Source juridique | Statut observé | Exemple | |---|---|---| | Codes français consolidés (L., R., D.) | Accessible | [Art. L1132-1 C. trav.](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006900787) — [Art. R625-1 C. com.](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006269542) | | Lois autonomes hors code (LODA) | Accessible | [Art. 6 Loi n° 78-17](https://www.legifrance.gouv.fr/loda/article_lc/LEGIARTI000006528068) | | Versions historiques / droit transitoire | ❌ Non accessible | [Art. L3121-1 C. trav.](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006902440) — versions antérieures à 2016 inaccessibles | | Règlements européens directement applicables | ❌ Hors périmètre | Art. 83 RGPD (Rgt UE 2016/679) → `SEARCH_NO_RESULTS` | --- ## Risques identifiés > Les risques ci-dessous combinent les limites propres à OpenLegi et celles introduites par l'utilisation dans un workflow IA (LLM → restitution). Ils ont été observés sur l'échantillon de tests et d'autres risques non encore documentés peuvent exister. ### 1 — Numéro réaffecté après renumérotation législative Certaines réformes réaffectent d'anciens numéros à de nouveaux articles. OpenLegi retourne l'article en vigueur portant ce numéro — qui peut être radicalement différent du texte historiquement attendu. **Exemple documenté.** Demander `Art. 1382 C. civ.` retourne un article sur les présomptions judiciaires ([lien](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006438819)), et non l'ancien article sur la responsabilité délictuelle, devenu [Art. 1240](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006437044) depuis l'ordonnance n° 2016-131. **Mitigation.** Toujours croiser le numéro retourné avec la section parente et les premiers mots du texte. Codes particulièrement concernés : Code civil (2016), Code du travail (2008), Code de commerce (ordonnances successives). --- ### 2 — Références internes orphelines Un article `VIGUEUR` peut contenir des renvois vers des articles abrogés. OpenLegi retourne le texte brut sans valider la cohérence des renvois internes. **Exemple documenté.** [Art. R625-1 C. com.](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006269542) (v1.0, inchangé depuis 2007) cite `L. 143-11-4 C. trav.`, abrogé en 2008 et remplacé par [Art. L3253-15](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006902640). **Mitigation.** Signal d'alerte : article avec numéro de version faible (v1.0 ou v2.0) et date de vigueur ancienne (avant 2010), surtout en partie réglementaire (R. ou D.). Vérifier les renvois directement sur Légifrance. --- ### 3 — Troncature des textes longs L'API peut retourner des textes tronqués, signalés par `...`. Un LLM peut restituer ce texte incomplet sans signaler la coupure, voire compléter la fin de mémoire. **Signaux d'alerte.** | Signal | Exemple | |---|---| | Texte se terminant par `…` ou `...` | [Art. L1132-1 C. trav.](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006900787) — 25 critères de discrimination | | Alinéas numérotés (I., II., 1°, 2°…) dont certains semblent manquants | [Art. 222-33 C. pén.](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006417706) — 3 parties + peines aggravées | | Article version ≥ 5.0 ou loi de transposition | [Art. L1132-1](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006900787) v11.0 — [Art. 6 Loi 78-17](https://www.legifrance.gouv.fr/loda/article_lc/LEGIARTI000006528068) | **Mitigation.** Ouvrir le lien Légifrance pour vérifier le texte intégral. Ne jamais citer un article dont la complétude n'a pas été vérifiée à la source. --- ### 4 — Hallucination et paraphrase par le LLM Un LLM dispose de millions de textes juridiques en mémoire. Il peut compléter silencieusement un texte tronqué, substituer une version ancienne à la version en vigueur, ou reformuler une disposition en en modifiant la portée — sans le signaler. **Exemple.** [Art. 226-1 C. pén.](https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006417928) : *"à titre privé **ou** confidentiel"* reformulé en *"en privé"* efface une condition alternative et modifie le champ de l'infraction. **Cas à risque élevé :** articles renumérotés, réformes récentes (loi SREN 2024, ord. 2023-1142…), textes tronqués. **Mitigation.** Exiger du LLM la reproduction exacte du texte retourné par l'outil, sans reformulation. Instruction système recommandée : *"Ne jamais paraphraser ni compléter un texte juridique. Reproduire uniquement le contenu exact retourné par l'outil, en signalant toute troncature (`...`) sans la corriger."* --- ### 5 — Faux positif du statut VIGUEUR Le statut `VIGUEUR` confirme uniquement que l'article existe dans la base consolidée. Il ne garantit pas que le texte est complet, que ses renvois internes sont valides, ni que le numéro correspond au texte recherché (voir risques 1 et 2). **Mitigation.** `VIGUEUR` est une condition nécessaire, non suffisante. Croiser systématiquement avec la section parente, le numéro de version, la date de vigueur, et l'absence de troncature. --- ### 6 — Décalage de cache Les données peuvent être servies depuis un cache intermédiaire dont la durée de rafraîchissement n'est pas fiable. En cas de modification législative très récente, le texte retourné peut ne pas encore refléter la dernière version en vigueur. **Mitigation.** Pour tout article susceptible d'avoir été modifié récemment, consulter directement Légifrance. --- ## Checklist de validation avant citation - [ ] Le texte ne se termine pas par `...` et tous les alinéas attendus sont présents - [ ] La section parente correspond à la matière recherchée - [ ] Le numéro de version et la date sont cohérents avec la réforme attendue - [ ] Les renvois internes ont été vérifiés (si article ancien, v1.0) - [ ] **Le lien Légifrance a été ouvert et le texte officiel lu** - [ ] Le texte cité est la reproduction exacte du texte officiel, sans paraphrase --- ## Hors périmètre — alternatives recommandées | Besoin | Alternative | |---|---| | Règlements et directives européens (RGPD, DMA, DSA, AI Act…) | [EUR-Lex](https://eur-lex.europa.eu) | | Versions historiques / droit transitoire | [Légifrance](https://www.legifrance.gouv.fr) — onglet "Versions" sur la fiche article | | Jurisprudence judiciaire et administrative | Outils `rechercher_jurisprudence_judiciaire` / `rechercher_jurisprudence_administrative` | --- *Documentation établie sur un échantillon de 12 cas tests — Code civil, Code du travail, Code pénal, Code de commerce, Loi n° 78-17. Les comportements observés ne valent pas garantie générale. Dernière mise à jour : 30 mars 2026.* ## Plugins et Skills ### Construire un Skill Claude qui utilise openlegi Ce guide explique comment créer un Skill au format Agent Skills pour exploiter openlegi. Un Skill est l'unité élémentaire d'extension de Claude : un dossier contenant un fichier `SKILL.md` et, en option, des scripts, des références et des assets. Là où un plugin regroupe plusieurs capacités cohérentes pour une équipe, un Skill encapsule une compétence atomique distribuable indépendamment. ## Skill ou plugin : quand choisir quoi Un plugin Claude bundle plusieurs skills, des agents planifiés, des hooks et une configuration MCP partagée via un fichier `CLAUDE.md`. Un Skill au format Agent Skills est plus léger : un dossier autonome qui se charge dynamiquement quand sa description correspond au contexte. ([Anthropic Engineering](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)) Trois critères de choix. **Granularité** : un Skill couvre une compétence (vérifier une citation d'article, formater une note de jurisprudence). Un plugin couvre une pratique (droit du travail, des affaires, contentieux spécifiques, etc). **Portabilité** : depuis octobre 2025, Agent Skills est un standard ouvert publié sur agentskills.io. Il a été adopté par Claude Code, OpenAI Codex CLI, Gemini CLI, Cursor et GitHub Copilot. ([agentskills.io](https://agentskills.io/home)) Un Skill bien construit fonctionne sur plusieurs assistants. Un plugin reste spécifique à l'écosystème Claude (Cowork et Claude Code). **Surface de distribution** : un Skill peut être uploadé sur claude.ai dans les settings, via l'API Claude, ou ajouté dans Claude Code via le système de fichiers. ([Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)) Les trois surfaces ne synchronisent pas entre elles. > **À noter.** Pour publier sur claude.ai uniquement, un Skill suffit. Pour packager une suite complète (veille hebdo + recherche + rédaction de notes) avec un profil de pratique partagé, un plugin est plus adapté. ## Le mécanisme de progressive disclosure L'architecture Skills repose sur un chargement en trois niveaux qui contrôle l'usage de contexte. ([Anthropic Engineering](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)) | Niveau | Contenu | Quand chargé | | --- | --- | --- | | 1. Metadata | `name` + `description` de la frontmatter YAML | Toujours, dans le system prompt | | 2. Corps du SKILL.md | Procédure en markdown | Quand le skill se déclenche | | 3. Ressources bundlées | `scripts/`, `references/`, `assets/` | À la demande | Au démarrage, Claude pré-charge uniquement les métadonnées de tous les skills installés. Il décide ensuite de consulter ou non un skill en se basant sur sa description. Si le skill est déclenché, son corps est injecté dans le contexte. Les fichiers bundlés ne sont lus que si la procédure les référence explicitement. ([Anthropic Engineering](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)) Cette mécanique a une conséquence pratique : la qualité de la `description` détermine la qualité du déclenchement. Anthropic recommande de garder ce champ informatif et explicite, en mentionnant à la fois ce que fait le skill et dans quels contextes il doit s'activer. ([Anthropic Skills repo](https://github.com/anthropics/skills)) ## Raccourci recommandé : faire générer le skill par le skill-creator Avant de rédiger un skill manuellement, la voie la plus efficace est de déléguer le travail au **skill-creator**, un méta-skill publié par Anthropic dont la fonction est précisément de créer d'autres skills. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) L'astuce qui rend cette approche particulièrement adaptée à openlegi : quand le skill-creator s'exécute dans une session Claude où le connecteur MCP openlegi est branché, il découvre automatiquement la liste des outils disponibles (`rechercher_code`, `rechercher_jurisprudence_judiciaire`, `recherche_journal_officiel`, etc.) ainsi que leurs descriptions détaillées et leurs paramètres. Il s'appuie sur ces métadonnées pour construire la procédure du skill sans qu'on ait à les lui réécrire. Les descriptions d'outils MCP openlegi sont riches et autoportantes, ce qui rend la génération du skill quasi-immédiate. ### Installation du skill-creator ```bash /plugin marketplace add anthropic-agent-skills@https://github.com/anthropics/skills /plugin install example-skills@anthropic-agent-skills ``` Le skill-creator est inclus dans le bundle `example-skills`. ([anthropics/skills](https://github.com/anthropics/skills)) ### Prompt type à copier-coller Lancez une conversation Claude (Cowork, Code ou claude.ai si le skill y est installé) et envoyez : ``` Crée un skill openlegi pour [décris ta tâche en une phrase]. Contexte technique : - Les outils MCP openlegi sont déjà disponibles dans cette session. Inspecte-les via tool_search ou liste-les pour t'imprégner de leurs descriptions et de leurs paramètres avant de drafter le skill. - Documentation openlegi optimisée pour LLM : https://www.openlegi.fr/llms-full.txt - Garde-fous obligatoires : citation systématique du lien article_lc, pas de paraphrase de texte légal, signalement explicite des troncatures. Procède selon ta méthode habituelle : cold-start interview, draft du SKILL.md, propositions de prompts de test, puis itération. ``` Trois éléments font la différence dans ce prompt. **La référence à `tool_search`** force le skill-creator à interroger l'environnement avant d'écrire le skill, plutôt que d'inventer des appels d'outils qui n'existent pas. Les descriptions retournées contiennent les paramètres exacts (`code_name`, `champ`, `panorama`, etc.) qu'il reproduira fidèlement. **Le lien vers `llms-full.txt`** donne au skill-creator une vue exhaustive de la doc openlegi formatée pour LLM. ([openlegi, accueil](https://www.openlegi.fr/documentation/)) Il y trouve les conventions de nommage, les limitations connues et les exemples d'usage. **La mention explicite des garde-fous juridiques** garantit que le skill généré intègre les règles openlegi sur la vérification, la non-paraphrase et la troncature, plutôt qu'un boilerplate générique. ### Ce qui sort de la procédure Le skill-creator suit une boucle structurée : capture d'intention via questions à l'utilisateur, rédaction du SKILL.md, génération de prompts de test, exécution des tests (en parallèle via subagents si disponibles, en série sinon), évaluation qualitative, itération. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) Le livrable final est un dossier complet (`SKILL.md` + éventuels `scripts/`, `references/`, `assets/`) que le skill-creator peut packager en fichier `.skill` prêt à uploader. ([anthropics/skills](https://github.com/anthropics/skills)) ### Limites à connaître Cette approche fonctionne mieux pour les skills à output objectivement vérifiable (recherche, extraction, vérification de citation). Pour les skills à output subjectif (style rédactionnel, formatage de note), le skill-creator recommande lui-même de privilégier l'évaluation qualitative manuelle. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) Une revue humaine du SKILL.md généré reste indispensable avant publication. Le skill-creator peut sous-estimer certaines spécificités du droit français (renumérotations, droits transitoires, droit européen directement applicable) si l'utilisateur ne les a pas mentionnées pendant l'interview. Les sections suivantes de ce guide servent alors de checklist de revue. > **Astuce avancée.** Le skill-creator inclut une boucle d'optimisation automatique de la description (voir `scripts/run_loop.py` dans le repo). Elle exécute les prompts de test plusieurs fois sur des variantes de description pour mesurer le taux de déclenchement et sélectionner la meilleure. C'est l'étape qui transforme un skill fonctionnel en skill robuste. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) La suite de ce guide documente la création manuelle, soit comme alternative pour les utilisateurs qui préfèrent garder le contrôle, soit comme référence pour réviser un skill produit par le skill-creator. ## Prérequis | Élément | Comment l'obtenir | | --- | --- | | Compte openlegi avec token actif | [auth.openlegi.fr](https://auth.openlegi.fr/users/dashboard/) | | Surface Claude (claude.ai, API ou Claude Code) | Selon le mode de distribution visé | | Connecteur MCP openlegi déjà configuré sur la surface | Voir doc openlegi de configuration | Un Skill ne déclare pas lui-même de connecteurs MCP. Il suppose que le serveur openlegi est déjà branché sur l'environnement Claude où il s'exécute. ## Anatomie d'un Skill Structure minimale : ``` mon-skill/ ├── SKILL.md # obligatoire ├── scripts/ # optionnel ├── references/ # optionnel └── assets/ # optionnel ``` Le seul fichier requis est `SKILL.md`. Tout le reste est optionnel et n'est chargé qu'à la demande. ([anthropics/skills](https://github.com/anthropics/skills)) ## Étape 1 : la frontmatter YAML Tout skill commence par un bloc YAML entre deux lignes `---`. Deux champs sont requis : `name` et `description`. ([Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)) ```yaml --- name: verification-article-fr description: Vérifie qu'une citation d'article de code juridique français est exacte en comparant le texte cité au texte officiel récupéré via openlegi. Utiliser ce skill chaque fois que l'utilisateur cite un article du Code civil, Code du travail, Code de commerce, Code pénal ou tout autre code français, ou quand l'utilisateur demande de vérifier une référence légale, contrôler un numéro d'article, valider une citation juridique ou détecter des hallucinations sur du droit français. --- ``` Quelques règles tirées de la pratique d'Anthropic. Le nom du skill doit correspondre au nom du dossier qui le contient. ([anthropics/skills](https://github.com/anthropics/skills)) La description doit dire à la fois ce que fait le skill ET dans quels contextes le déclencher. Anthropic note que Claude a tendance à sous-déclencher les skills, ce qui justifie de rendre la description légèrement "pushy" en multipliant les formulations de déclenchement possibles. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) La description doit rester sous 1024 caractères, car elle est chargée en permanence dans le contexte de Claude. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) ## Étape 2 : le corps du skill Après la frontmatter, le markdown libre contient la procédure que Claude suivra quand le skill se déclenchera. La forme impérative est recommandée. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) Exemple complet pour `verification-article-fr` : ````markdown --- name: verification-article-fr description: [...comme ci-dessus...] --- # Vérification de citation d'article (droit français) Quand un utilisateur cite un article d'un code juridique français, ce skill récupère le texte officiel via openlegi et compare avec ce qui a été cité, en signalant explicitement toute divergence. ## Procédure 1. **Identifier la référence à vérifier** : - Code source (Code civil, Code du travail, etc.) - Numéro d'article (L1234-5, R625-1, etc.) - Texte cité (verbatim ou paraphrase) 2. **Appeler openlegi** via l'outil `rechercher_code` : ```json { "search": "", "code_name": "", "champ": "NUM_ARTICLE", "max_results": 1 } ``` 3. **Comparer la version officielle avec la citation** : - Reproduire le texte officiel retourné, sans paraphrase - Diffuser le texte cité par l'utilisateur - Identifier les divergences mot à mot 4. **Produire une note de vérification** : Si la citation est exacte : > ✅ Citation conforme au texte officiel. > Source : [lien article_lc Légifrance] Si la citation diverge : > ⚠️ Divergences détectées entre la citation et le texte officiel. > > **Texte cité** : "[citation utilisateur]" > **Texte officiel** : "[texte openlegi]" > **Divergences** : [liste précise] > > Source : [lien article_lc Légifrance] ## Cas particuliers ### Article potentiellement renuméroté Si la citation porte sur le Code civil pré-2016, le Code du travail pré-2008 ou le Code de commerce, vérifier que le numéro retourné par openlegi correspond bien au texte attendu, et non à un nouvel article ayant pris le même numéro après réforme. Voir `references/renumerotations.md` pour la liste des codes concernés. ### Texte tronqué Si la réponse openlegi se termine par `...` ou `…`, signaler la troncature sans tenter de compléter. Inviter l'utilisateur à ouvrir le lien Légifrance pour le texte intégral. ### Article non trouvé Si openlegi retourne `SEARCH_NO_RESULTS`, ne pas inventer le texte. Indiquer que l'article n'a pas été trouvé dans la base consolidée et proposer des alternatives (article voisin, ancienne numérotation). ## Garde-fous absolus - Ne jamais paraphraser le texte officiel : reproduire à l'identique. - Toujours afficher le lien `article_lc` Légifrance retourné par openlegi. - Si l'utilisateur conteste la version openlegi, l'inviter à vérifier directement sur legifrance.gouv.fr. openlegi est une interface, pas la source officielle. ```` Anthropic recommande de garder le corps du SKILL.md sous 500 lignes. Au-delà, il est préférable de découper en fichiers de référence dans `references/` que Claude lira à la demande. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) ## Étape 3 : ajouter des scripts déterministes Pour les opérations répétitives qui ne nécessitent pas de raisonnement (parsing, diff, génération de fichier), un script vaut mieux qu'une instruction en langage naturel. Le code est plus rapide et plus reproductible. ([Anthropic Engineering](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)) Exemple : `scripts/diff_citation.py` ```python #!/usr/bin/env python3 """ Compare un texte cité avec le texte officiel openlegi. Retourne une liste de divergences mot à mot. Usage: python diff_citation.py --cite "texte cité" --official "texte officiel" """ import argparse import difflib import json import sys def diff_texts(cite: str, official: str) -> dict: """Produit un diff structuré entre deux textes.""" cite_words = cite.split() official_words = official.split() matcher = difflib.SequenceMatcher(None, cite_words, official_words) divergences = [] for tag, i1, i2, j1, j2 in matcher.get_opcodes(): if tag == "equal": continue divergences.append({ "type": tag, "cited": " ".join(cite_words[i1:i2]) or None, "official": " ".join(official_words[j1:j2]) or None, }) return { "match_ratio": matcher.ratio(), "is_exact_match": matcher.ratio() == 1.0, "divergences": divergences, } def main(): parser = argparse.ArgumentParser() parser.add_argument("--cite", required=True) parser.add_argument("--official", required=True) args = parser.parse_args() result = diff_texts(args.cite, args.official) json.dump(result, sys.stdout, ensure_ascii=False, indent=2) if __name__ == "__main__": main() ``` Dans le corps du skill, on référence le script : ```markdown 4. Si le texte cité dépasse 50 mots, utiliser le script `scripts/diff_citation.py` pour produire un diff structuré plutôt que de comparer mot à mot manuellement. ``` Le script est exécuté par Claude via le tool bash (ou équivalent), sans être chargé en contexte. C'est ce qu'Anthropic appelle l'usage du code comme outil exécutable plutôt que comme documentation. ([Anthropic Engineering](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)) ## Étape 4 : ajouter des références Le dossier `references/` contient des fichiers markdown qui ne sont pas chargés par défaut mais référencés par le corps du SKILL.md. C'est utile pour les contenus volumineux (listes, taxonomies, jurisprudence de référence). ([anthropics/skills](https://github.com/anthropics/skills)) Exemple : `references/renumerotations.md` ```markdown # Codes français renumérotés Liste des réformes connues qui ont réaffecté d'anciens numéros d'articles à de nouveaux articles. À consulter quand une citation porte sur un de ces codes et précède la date de réforme. ## Code civil **Ordonnance n° 2016-131 du 10 février 2016** : refonte du droit des contrats et des obligations. Exemples de réaffectations : - Ancien Art. 1382 (responsabilité délictuelle) devenu Art. 1240. - Le numéro 1382 est aujourd'hui occupé par un article sur les présomptions judiciaires. ## Code du travail **Recodification 2008** : changement complet de la numérotation. - Articles L1132-1 et suivants, R625-1 et suivants : nouveaux numéros depuis 2008. Les anciens numéros (L122-45 etc.) ne sont plus en vigueur. ## Code de commerce Plusieurs ordonnances successives ont modifié la numérotation. Vérifier systématiquement la date de la citation et la date de version retournée par openlegi. ``` Pour les références volumineuses (>300 lignes), Anthropic recommande d'inclure une table des matières au début du fichier pour permettre à Claude de naviguer efficacement. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) ## Étape 5 : ajouter des assets Le dossier `assets/` contient les fichiers utilisés dans la sortie produite par le skill : templates, polices, icônes, modèles de documents. Contrairement aux références, ils ne sont pas lus pour informer Claude mais utilisés directement dans le résultat final. ([anthropics/skills](https://github.com/anthropics/skills)) Pour le skill `verification-article-fr`, on pourrait fournir un template de note de vérification : ``` assets/ └── template-note-verification.md ``` ```markdown # Note de vérification **Référence vérifiée** : {{reference}} **Date de vérification** : {{date}} **Source consultée** : openlegi (interface Légifrance) **Lien officiel** : {{article_lc}} ## Résultat {{resultat_verification}} ## Texte officiel {{texte_officiel}} ## Texte cité {{texte_cite}} ## Divergences détectées {{divergences}} --- *Cette note est un brouillon à valider. Pour tout usage professionnel, ouvrir le lien officiel et vérifier le texte directement sur Légifrance.* ``` ## Étape 6 : optimiser la description La description est le seul élément du skill qui détermine son déclenchement. Anthropic fournit dans son skill-creator un outil d'optimisation automatique de la description, qui exécute une boucle d'évaluation sur des prompts de test pour mesurer le taux de déclenchement et proposer des variantes. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) À défaut d'outillage, quelques règles empiriques. Inclure les termes que l'utilisateur emploie réellement. Pour un skill juridique français, "article", "code", "vérifier", "citation", "référence", "hallucination" sont des signaux forts. Énumérer plusieurs formulations équivalentes. "Vérifier une référence", "contrôler un numéro d'article", "valider une citation" sont trois formulations qui doivent toutes déclencher le skill. Mentionner les types de documents source si pertinent. "Code civil, Code du travail, Code de commerce" donne plus de signaux qu'une formule générique comme "code juridique". Éviter les descriptions vagues du type "ce skill aide à vérifier des trucs". Le signal de déclenchement doit être concret. ## Étape 7 : tester le skill Anthropic recommande de définir 2 à 3 prompts de test représentatifs avant publication. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) Pour `verification-article-fr` : ``` Test 1 : "L'article L1132-1 du Code du travail dispose que toute discrimination est interdite. Peux-tu vérifier cette citation ?" Attendu : déclenchement du skill, appel openlegi, restitution du texte officiel avec liste des 25 critères de discrimination effectivement listés dans l'article (non tronqués). Test 2 : "Selon l'article 1382 du Code civil, tout fait quelconque de l'homme qui cause à autrui un dommage oblige celui par la faute duquel il est arrivé à le réparer." Attendu : déclenchement, détection de la renumérotation (devenu Art. 1240), signalement explicite. Test 3 : "Quelle est la différence entre droit civil et droit pénal ?" Attendu : pas de déclenchement (la question ne cite aucun article). ``` L'objectif des tests négatifs (test 3) est de vérifier que le skill ne sur-déclenche pas sur des questions tangentielles. ## Étape 8 : packager le skill Le format de distribution est un fichier `.skill` qui est essentiellement le dossier compressé. Le repo `anthropics/skills` fournit un script `package_skill.py` pour cela. ([anthropics/skills](https://github.com/anthropics/skills)) Manuellement, l'opération équivaut à : ```bash cd parent-folder/ zip -r verification-article-fr.skill verification-article-fr/ ``` Le fichier `.skill` peut alors être uploadé sur claude.ai (Settings > Capabilities > Skills), poussé via l'API Claude, ou placé dans le répertoire `.claude/skills/` d'un projet Claude Code. ## Étape 9 : distribuer sur les trois surfaces Les Skills ne synchronisent pas automatiquement entre claude.ai, l'API et Claude Code. Il faut publier sur chaque surface séparément. ([Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)) **claude.ai** : upload du fichier `.skill` via les settings. Disponible immédiatement dans toutes les conversations de l'utilisateur. **API Claude** : upload via l'endpoint Skills API. Le skill devient utilisable dans toute requête API qui le référence. Pour les déploiements multi-utilisateurs (chatbot, intégration interne), c'est le mode privilégié. **Claude Code** : déposer le dossier dans `.claude/skills/` du projet. Le skill devient disponible dans la session Claude Code de ce projet. > **Conséquence pratique.** Un Skill destiné à être utilisé largement (par exemple, le skill de vérification d'article décrit ici) doit être publié au moins sur claude.ai et l'API pour couvrir la majorité des cas d'usage en cabinet. ## Adoption hors Claude Le standard Agent Skills est ouvert. Au moment de la publication de ce guide, il est implémenté par Claude Code, OpenAI Codex CLI, Gemini CLI, GitHub Copilot et Cursor. ([agentskills.io](https://agentskills.io/home)) Un skill openlegi rédigé selon le format de base (frontmatter standard, markdown, scripts optionnels) fonctionne sans modification sur la plupart de ces outils. Les fonctionnalités avancées propres à Claude (context forking, par exemple) ne sont pas portables. ([Agensi](https://www.agensi.io/learn/agent-skills-open-standard)) Cette portabilité a une implication stratégique pour openlegi : un skill bien conçu autour des outils MCP openlegi devient utilisable depuis n'importe quel assistant compatible MCP plus Agent Skills, ce qui élargit l'usage au-delà de l'écosystème Claude. ## Garde-fous spécifiques aux skills juridiques Anthropic insiste sur le fait que les skills sont des capacités exécutables qui peuvent invoquer des outils et exécuter du code. Un skill malveillant peut détourner ces capacités. ([Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)) Pour les skills juridiques, deux points de vigilance. **Auditer les scripts bundlés**. Avant d'installer un skill provenant d'un tiers, lire le contenu des fichiers dans `scripts/`. Un skill qui télécharge des données externes sans rapport avec sa fonction déclarée doit être considéré comme suspect. ([Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)) **Préserver le caractère d'aide à la décision**. Tout skill qui produit du contenu juridique doit explicitement positionner sa sortie comme un brouillon à valider, jamais comme un avis. Cette règle reprend la position d'Anthropic sur `claude-for-legal` : chaque output est un brouillon pour revue d'avocat, pas un avis juridique, pas une conclusion légale. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) > **Avertissement openlegi.** openlegi est une interface d'accès à Légifrance, pas un substitut. Tout skill construit sur openlegi doit prévoir un mécanisme de renvoi vers le texte officiel Légifrance via le lien `article_lc`. Cette règle est documentée dans les limitations connues d'openlegi. ([openlegi, Limitations connues](https://www.openlegi.fr/documentation/demarrage-rapide/limitations-connues/)) ## Exemple complet : repo de référence Un squelette minimal d'un skill openlegi a la structure suivante : ``` verification-article-fr/ ├── SKILL.md ├── scripts/ │ └── diff_citation.py ├── references/ │ └── renumerotations.md └── assets/ └── template-note-verification.md ``` Pour des exemples grandeur réelle, le repo `anthropics/skills` contient les skills de production qui alimentent Claude (docx, pdf, pptx, xlsx) ainsi qu'un skill-creator complet, sous licence Apache 2.0 pour les exemples communautaires et source-available pour les skills documents. ([anthropics/skills](https://github.com/anthropics/skills)) ## Limites et points de vigilance Le contenu des Skills n'est pas couvert par les arrangements Zero Data Retention. Les définitions de skills et les données d'exécution sont conservées selon la politique de rétention standard d'Anthropic. ([Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)) Pour les cabinets soumis à des contraintes strictes de confidentialité, ce point doit être vérifié avant déploiement. Les Skills ne se synchronisent pas entre claude.ai, l'API et Claude Code. Il faut maintenir la publication sur chaque surface. ([Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)) Claude tend à sous-déclencher les skills sur les tâches simples qu'il peut accomplir directement avec ses outils de base. ([anthropics/skills, skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md)) Un skill construit pour une opération triviale (lire un fichier, par exemple) ne se déclenchera pas, même si sa description matche. Les skills sont conçus pour des tâches multi-étapes ou spécialisées. ## Aller plus loin | Sujet | Ressource | | --- | --- | | **Skill-creator (raccourci recommandé)** | [anthropics/skills/skill-creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md) | | Spécification Agent Skills | [agentskills.io](https://agentskills.io/home) | | Repo officiel Anthropic | [anthropics/skills](https://github.com/anthropics/skills) | | Documentation API Skills | [Claude Platform Docs](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) | | Article fondateur d'Anthropic | [Equipping agents for the real world](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills) | | Doc openlegi optimisée pour LLM | [llms-full.txt](https://www.openlegi.fr/llms-full.txt) | | Outils openlegi exhaustifs | [openlegi, Liste des outils](https://www.openlegi.fr/documentation/outils/liste-des-outils/) | | Construire un plugin (variante) | Guide précédent dans cette documentation | ### Construire un plugin Claude qui utilise openlegi Ce guide explique comment packager les outils MCP openlegi dans un plugin Claude réutilisable. Un plugin permet de distribuer à plusieurs utilisateurs (équipe, cabinet, direction juridique) un ensemble cohérent de skills, d'agents planifiés et de connecteurs MCP, configurés une seule fois et personnalisés via un profil de pratique. ## Pourquoi un plugin plutôt qu'un simple `.mcp.json` Un fichier `.mcp.json` configure un serveur MCP pour une seule instance Claude. Un plugin Claude apporte trois éléments supplémentaires : un profil de pratique (`CLAUDE.md`) que tous les skills lisent en amont, des skills explicitement déclenchables via des slash commands (`/:`), et des agents planifiés qui s'exécutent en arrière-plan selon une cadence cron. ([Anthropic, Customize Claude Code with plugins](https://www.anthropic.com/news/claude-code-plugins)) Le format de référence est celui utilisé par Anthropic pour le repo `claude-for-legal`, publié sous licence Apache 2.0. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) Aucune compilation n'est requise : tout est en markdown et JSON. > **À noter.** Les plugins fonctionnent sur Claude Cowork, Claude Code et Claude Desktop. Pour Claude Web (claude.ai) seuls les connecteurs MCP individuels sont disponibles, sans la couche plugin. ## Prérequis | Élément | Comment l'obtenir | | --- | --- | | Compte openlegi avec token actif | [auth.openlegi.fr](https://auth.openlegi.fr/users/dashboard/) | | Claude Code ou Claude Cowork installé | [claude.com/download](https://claude.com/download) | | Git (pour publication éventuelle) | Selon votre OS | Vérifiez la disponibilité du service openlegi avant de commencer : ```bash curl https://mcp.openlegi.fr/health ``` La réponse doit indiquer `{"status": "ok", ...}`. ([openlegi, Health Check](https://www.openlegi.fr/documentation/modes-dintegration/health-check-verifier-la-disponibilite-des-services/)) ## Architecture d'un plugin Un plugin Claude est un répertoire avec une structure normalisée : ``` mon-plugin-openlegi/ .claude-plugin/ plugin.json # manifeste du plugin CLAUDE.md # profil de pratique (template) README.md skills/ # skills déclenchables veille-jorf/ SKILL.md recherche-code/ SKILL.md agents/ # agents planifiés (optionnel) digest-hebdo.md hooks/ # hooks pre/post tool (optionnel) .mcp.json # déclaration des connecteurs MCP ``` Chaque fichier `SKILL.md` est un skill autonome. Chaque agent est un fichier markdown avec une frontmatter de planification. ## Étape 1 : le manifeste `plugin.json` Créez `.claude-plugin/plugin.json` : ```json { "name": "veille-juridique-fr", "version": "0.1.0", "description": "Veille et recherche en droit français via openlegi", "author": { "name": "Cabinet Exemple", "url": "https://exemple.fr" }, "license": "MIT", "keywords": ["droit-francais", "veille", "openlegi", "legifrance"] } ``` Le champ `name` est utilisé comme préfixe pour toutes les slash commands. Un skill nommé `veille-jorf` deviendra `/veille-juridique-fr:veille-jorf`. ## Étape 2 : la configuration MCP Créez `.mcp.json` à la racine du plugin pour déclarer la dépendance à openlegi : ```json { "mcpServers": { "openlegi-legifrance": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://mcp.openlegi.fr/legifrance/mcp?token=${OPENLEGI_TOKEN}" ] }, "openlegi-rne": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://mcp.openlegi.fr/inpi/mcp?token=${OPENLEGI_TOKEN}" ] } } } ``` Les variables d'environnement comme `${OPENLEGI_TOKEN}` sont résolues au moment de l'installation. ([openlegi, Configuration Claude Desktop](https://www.openlegi.fr/documentation/demarrage-rapide/configuration-claude-desktop/)) > **Sécurité.** Ne jamais coder le token en dur dans `.mcp.json`. Le plugin sera potentiellement partagé via Git ou un registry, et le token est personnel. ## Étape 3 : le profil de pratique `CLAUDE.md` Le fichier `CLAUDE.md` à la racine est un template. Il sera lu automatiquement par tous les skills du plugin avant chaque exécution. Voici un exemple minimal : ```markdown # Profil de pratique — Veille juridique FR ## Domaines de pratique À compléter via /veille-juridique-fr:cold-start-interview ## Codes prioritaires - Code du travail - Code de commerce - Code civil ## Juridictions suivies - Cour de cassation (chambre sociale) - Conseil d'État ## Style de restitution - Note de synthèse en 5 points maximum - Citation systématique de l'article source avec lien Légifrance - Aucune paraphrase d'un texte légal sans contrôle préalable ## Garde-fous - Toujours afficher le lien `article_lc` Légifrance pour vérification - Signaler toute troncature (`...`) sans la corriger - Refuser de donner un avis juridique : restitution factuelle uniquement ``` Le profil est rempli soit manuellement, soit via une cold-start interview (voir étape 5). Il survit aux mises à jour du plugin. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) ## Étape 4 : créer un skill Un skill est un fichier `SKILL.md` placé dans `skills//`. La structure est imposée par Anthropic. Exemple complet : `skills/veille-jorf/SKILL.md` ```markdown --- name: veille-jorf description: Surveille les publications récentes au Journal Officiel selon les filtres définis dans le profil de pratique. Utiliser quand l'utilisateur demande une veille JORF, une revue des derniers décrets, ou un suivi des publications récentes du gouvernement français. argument-hint: "[nombre_jours]" --- # Veille JORF Récupère les publications récentes du Journal Officiel français via openlegi et produit une note de synthèse selon le style maison défini dans CLAUDE.md. ## Procédure 1. Lire le profil de pratique dans `~/.claude/plugins/config/veille-juridique-fr/CLAUDE.md` pour identifier les ministères et types de textes prioritaires. 2. Appeler l'outil openlegi `recherche_journal_officiel` : - text_types : selon le profil (par défaut DECRET et ARRETE) - ministeres : selon le profil - date_publication : [today - nombre_jours, today] - sort : PUBLI_DATE_DESC - max_results : 20 3. Pour chaque résultat, extraire : - Titre - Date de signature - Ministère émetteur - Lien Légifrance (champ `article_lc` des métadonnées) 4. Produire une note structurée : - Titre : "Veille JORF — [date début] au [date fin]" - 1 ligne par texte avec lien cliquable - Aucune paraphrase du contenu : titre officiel uniquement ## Garde-fous - Si un texte semble particulièrement pertinent, proposer à l'utilisateur d'appeler `rechercher_dans_texte_legal` pour récupérer le texte intégral, mais ne jamais reproduire le texte sans le lien de vérification. - Si openlegi retourne une erreur de quota, suggérer de configurer des clés API PISTE personnelles via le dashboard openlegi. ``` Points clés du format SKILL.md : La frontmatter YAML contient `name`, `description` et `argument-hint`. Le champ `description` est le signal de déclenchement automatique du skill : Claude le lit pour décider si le skill s'applique au message en cours. Anthropic recommande de garder ce champ sous 1024 caractères. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) Le corps du skill est une procédure en langage naturel. Pas de DSL, pas de pseudo-code obligatoire. Claude exécute les étapes en appelant les outils MCP déclarés dans `.mcp.json`. ## Étape 5 : le cold-start interview C'est la convention Anthropic pour personnaliser le plugin lors du premier usage. Créez `skills/cold-start-interview/SKILL.md` : ```markdown --- name: cold-start-interview description: Initialise le profil de pratique du plugin veille-juridique-fr. À exécuter une fois après l'installation. Pose des questions sur les domaines, juridictions et style attendu, puis écrit le profil dans CLAUDE.md. --- # Cold-start interview — Veille juridique FR ## Objectif Remplir le fichier `~/.claude/plugins/config/veille-juridique-fr/CLAUDE.md` avec les paramètres spécifiques à l'utilisateur ou au cabinet. ## Procédure 1. Présenter brièvement le plugin et expliquer que l'interview dure 5 à 10 minutes. 2. Poser les questions suivantes, une par une : a) Quels sont les 3 à 5 domaines de droit que vous suivez en priorité ? b) Quels codes juridiques consultez-vous le plus souvent ? c) Quelles juridictions surveillez-vous (Cour de cassation, Conseil d'État, etc.) ? d) Quels ministères publient les textes qui vous concernent ? e) Quel format de restitution préférez-vous (note courte, tableau, bullet points) ? f) Avez-vous des garde-fous spécifiques (privilege, anonymisation, etc.) ? 3. Demander à l'utilisateur de fournir 2 à 3 exemples de notes de veille passées (URL ou copier-coller) pour calibrer le style. 4. Écrire le fichier CLAUDE.md selon les réponses. 5. Tester immédiatement avec `/veille-juridique-fr:veille-jorf 7` pour valider. ``` Cette convention permet à un utilisateur non technique de configurer le plugin sans toucher au fichier `CLAUDE.md` directement. ## Étape 6 : ajouter un agent planifié Les agents planifiés s'exécutent en arrière-plan selon une cadence cron. Créez `agents/digest-hebdo.md` : ```markdown --- name: digest-hebdo schedule: "0 8 * * 1" description: Digest hebdomadaire de veille juridique, envoyé chaque lundi à 8h. --- # Digest hebdomadaire Chaque lundi matin, produire une note couvrant : 1. Les publications JORF de la semaine écoulée (appeler veille-jorf 7). 2. Les nouvelles décisions de la Cour de cassation dans les domaines suivis (appeler rechercher_jurisprudence_judiciaire avec juridiction_judiciaire=["Cour de cassation"], date_decision sur les 7 derniers jours, panorama=true). 3. Les éventuelles décisions du Conseil d'État en lien avec les domaines suivis. Sortie attendue : - Un fichier markdown nommé `digest-AAAA-MM-DD.md` - Posté dans le canal Slack #veille-juridique si le connecteur Slack est configuré - Sinon stocké dans `~/Documents/veille-juridique/` ``` La frontmatter `schedule` utilise une syntaxe cron standard. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) Pour un déploiement headless (sans interface), cet agent peut être converti en Managed Agent via l'API Claude. Cela suppose la création d'un cookbook séparé dans `managed-agent-cookbooks/digest-hebdo/`. La documentation Anthropic décrit cette opération via le script `deploy-managed-agent.sh`. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) ## Étape 7 : tester le plugin localement Depuis Claude Code, ajoutez le marketplace local et installez le plugin : ```bash # Pointer Claude Code vers le répertoire local du plugin /plugin marketplace add /chemin/absolu/vers/mon-plugin-openlegi # Installer /plugin install veille-juridique-fr@local # Redémarrer Claude Code, puis lancer la cold-start interview /veille-juridique-fr:cold-start-interview ``` Sur Claude Cowork, l'installation se fait via l'onglet **Customize** > **Browse plugins** > **Upload custom plugin file** en uploadant le répertoire zippé. ## Étape 8 : structurer les garde-fous spécifiques au droit français openlegi documente plusieurs risques structurels lors de l'usage de Légifrance via un LLM, dont la troncature des textes longs, les références internes orphelines et les numéros d'articles réaffectés après renumérotation législative. ([openlegi, Limitations connues](https://www.openlegi.fr/documentation/demarrage-rapide/limitations-connues/)) Pour les couvrir au niveau plugin, ajoutez un hook `pre-tool` dans `hooks/openlegi-guardrails.md` : ```markdown --- name: openlegi-guardrails type: pre-tool applies-to: ["rechercher_code", "rechercher_dans_texte_legal"] --- # Garde-fous openlegi Avant tout appel à openlegi sur un code ou texte légal : 1. Si la requête concerne un article potentiellement renuméroté (Code civil avant 2016, Code du travail avant 2008, Code de commerce), demander à l'utilisateur de confirmer la version recherchée. 2. Après l'appel, si la réponse contient `...` ou se termine par des points de suspension, signaler explicitement la troncature dans la restitution. 3. Toujours afficher le lien `article_lc` retourné dans les métadonnées, sans exception. 4. Ne jamais paraphraser le texte d'un article. Reproduire le texte exact retourné par l'outil. Toute reformulation est interdite. ``` Ces garde-fous reprennent textuellement les recommandations openlegi sur la prévention des hallucinations en droit français. ([openlegi, Limitations connues](https://www.openlegi.fr/documentation/demarrage-rapide/limitations-connues/)) ## Étape 9 : documenter le plugin Le `README.md` à la racine du plugin doit minimalement contenir : - Liste des skills exposés avec leur commande - Liste des connecteurs MCP requis - Exemples d'usage - Mention du token openlegi nécessaire Anthropic recommande également de garder la description de chaque skill sous 1024 caractères, car c'est le signal de déclenchement automatique. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) ## Étape 10 : publier le plugin Trois options de distribution. **Privé (cabinet ou direction juridique)** : héberger le repo sur un GitHub privé, ajouter le marketplace via `/plugin marketplace add https://github.com/cabinet/mon-plugin-openlegi`. **Public via le Legal Builder Hub** : Anthropic propose un système de découverte et d'installation de skills communautaires avec contrôles de sécurité. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) Le passage par ce hub implique de soumettre le plugin à un QA framework qui scanne le contenu, vérifie les licences et journalise les installations. **Public en dehors du hub** : publication sur GitHub sous licence libre. C'est l'approche utilisée pour `anthropics/claude-for-legal` lui-même, sous Apache 2.0. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) ## Exemple complet : repo de référence Un squelette minimal de plugin openlegi est disponible sous la forme suivante : ``` veille-juridique-fr/ .claude-plugin/ plugin.json skills/ cold-start-interview/SKILL.md veille-jorf/SKILL.md recherche-code/SKILL.md recherche-jurisprudence/SKILL.md agents/ digest-hebdo.md hooks/ openlegi-guardrails.md .mcp.json CLAUDE.md README.md LICENSE ``` Pour un exemple grandeur réelle de plugins exploitant des connecteurs MCP juridiques, consulter le repo `anthropics/claude-for-legal` qui contient 12 plugins de référence sous licence Apache 2.0 (5,2k étoiles, 726 forks au 16 mai 2026). ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) ## Limites et points de vigilance Les hooks `pre-tool` et la cadence des agents planifiés sont des fonctionnalités actives sur Claude Code et Cowork. Leur disponibilité sur d'autres clients MCP (Mistral Le Chat, Microsoft Copilot Studio) peut être partielle ou inexistante. ([openlegi, Liste des services compatibles](https://www.openlegi.fr/documentation/demarrage-rapide/liste-des-services-compatibles/)) La délégation à des sous-agents (`callable_agents`) est en Research Preview au moment de la publication de ce guide et supporte un seul niveau de délégation. ([Anthropic, claude-for-legal](https://github.com/anthropics/claude-for-legal)) Tout output produit par un plugin construit sur openlegi reste un brouillon à valider. La règle openlegi est absolue : pour tout usage professionnel, vérifier le texte sur Légifrance via le lien `article_lc` fourni dans les métadonnées. ([openlegi, Limitations connues](https://www.openlegi.fr/documentation/demarrage-rapide/limitations-connues/)) ## Aller plus loin | Sujet | Ressource | | --- | --- | | Outils openlegi exhaustifs | [openlegi, Liste des outils](https://www.openlegi.fr/documentation/outils/liste-des-outils/) | | Référence Claude plugins | [anthropics/claude-for-legal](https://github.com/anthropics/claude-for-legal) | | API Claude Managed Agents | [docs.claude.com/managed-agents](https://docs.claude.com/en/api/managed-agents) | | Spécification MCP | [modelcontextprotocol.io](https://modelcontextprotocol.io/) | | Clés API PISTE personnelles | [openlegi, Clés API personnelles](https://www.openlegi.fr/documentation/demarrage-rapide/cles-api-personnelles/) | ## Outils disponibles Reference des outils MCP pour acceder aux donnees juridiques ### Liste des outils ### Service Légifrance (Droit français) | Outil | Description | |-------|-------------| | `rechercher_code` | Recherche dans les codes juridiques français | | `rechercher_jurisprudence_judiciaire` | Recherche de jurisprudence judiciaire (JURI) | | `rechercher_jurisprudence_administrative` | Recherche de jurisprudence administrative (CETAT) | | `rechercher_decisions_cnil` | Recherche dans les décisions CNIL | | `rechercher_decisions_constitutionnelles` | Recherche dans les décisions du Conseil constitutionnel | | `rechercher_conventions_collectives` | Recherche dans les conventions collectives (KALI) | | `rechercher_dans_texte_legal` | Recherche dans les textes légaux consolidés (LODA) | | `recherche_journal_officiel` | Recherche dans le Journal Officiel (JORF) | | `dernier_journal_officiel` | Récupère les derniers JO publiés | | `lister_codes_juridiques` | Liste tous les codes juridiques disponibles | | `lister_emetteurs_jorf` | Liste les émetteurs du Journal Officiel | | `lister_natures_textes_jorf` | Liste les types de textes publiés au JORF | ### Service RNE (Registre National des Entreprises) | Outil | Description | |-------|-------------| | `rne_search_companies` | Recherche d'entreprises françaises | | `rne_get_company_data` | Données complètes d'une entreprise | | `rne_get_bodacc` | Annonces légales BODACC | | `rne_download_acte` | Télécharge un acte PDF (URL SAS temporaire) | | `rne_download_bilan` | Télécharge un bilan PDF | | `rne_download_extrait_rne` | Télécharge l'extrait RNE (KBIS) | | `rne_list_temp_files` | Liste les fichiers temporaires | | `rne_delete_temp_file` | Supprime un fichier temporaire | | `rne_cleanup_temp_files` | Nettoie les fichiers temporaires | ### Service EUR-Lex (Droit européen) | Outil | Description | |-------|-------------| | `eurlex_search_by_title` | Recherche par titre de document | | `eurlex_search_by_number` | Recherche par numéro CELEX | | `eurlex_fetch_article` | Récupère un article spécifique | | `eurlex_fetch_recital` | Récupère un considérant | | `eurlex_list_articles` | Liste tous les articles d'un document | | `eurlex_list_recitals` | Liste tous les considérants | | `eurlex_search_in_document` | Recherche dans le texte d'un document | | `eurlex_get_metadata` | Récupère les métadonnées d'un document | | `eurlex_fetch_text` | Récupère le texte intégral d'un document | ### Mode d'affichage - pagination et panorama ## Pagination La plupart des outils supportent la pagination : ```python with OpenLegiClient(token="VOTRE_TOKEN_ICI") as client: # Page 1 result_page1 = client.call_tool( "rechercher_code", { "search": "responsabilité", "code_name": "Code civil", "page_number": 1, "page_size": 20 } ) # Page 2 result_page2 = client.call_tool( "rechercher_code", { "search": "responsabilité", "code_name": "Code civil", "page_number": 2, "page_size": 20 } ) ``` ## Mode Panorama Pour éviter de récupérer des textes intégraux volumineux, utilisez le mode `panorama=True` qui retourne uniquement les métadonnées et résumés : ```python with OpenLegiClient(token="VOTRE_TOKEN_ICI") as client: result = client.call_tool( "rechercher_jurisprudence_judiciaire", { "search": "contrat de travail", "panorama": True, # Vue d'ensemble uniquement "page_size": 50 } ) ``` ### Codes juridiques ## `rechercher_code` Recherche dans les codes juridiques français : Code civil, Code pénal, Code du travail, et l'ensemble des codes en vigueur. ## En pratique Dans la plupart des cas, vous n'appelez pas cet outil vous-même : vous posez la question à votre assistant, qui choisit l'outil et les paramètres. > « Donne-moi l'article L1237-11 du Code du travail avec son contexte » > « Que dit le Code civil sur la responsabilité du fait des choses ? » > « Compare les articles du Code pénal sur la légitime défense » La suite de cette page s'adresse aux intégrations qui appellent l'outil directement. ## Paramètres | Paramètre | Type | Description | |-----------|------|-------------| | `search` | string | Termes de recherche (obligatoire) | | `code_name` | string | Nom du code juridique (obligatoire) | | `max_results` | integer | Nombre de résultats (défaut : 10, max : 100) | | `champ` | string | Champ de recherche : `ALL`, `TITLE`, `NUM_ARTICLE`, `ARTICLE` | | `sort` | string | Tri : `PERTINENCE`, `DATE_ASC`, `DATE_DESC` | ## Exemple d'appel ```json { "name": "rechercher_code", "arguments": { "search": "contrat de travail", "code_name": "Code du travail", "max_results": 5 } } ``` Pour cibler un article par son numéro, utilisez `champ: "NUM_ARTICLE"` : ```json { "name": "rechercher_code", "arguments": { "search": "1240", "code_name": "Code civil", "champ": "NUM_ARTICLE" } } ``` ## Codes disponibles L'outil `lister_codes_juridiques` renvoie la liste complète. Les plus demandés : - Code civil - Code pénal - Code du travail - Code de commerce - Code de procédure civile - Code de procédure pénale - Code général des impôts ## À savoir Le nom du code doit être écrit tel qu'il figure dans la nomenclature officielle. En cas de doute, appelez `lister_codes_juridiques` plutôt que de deviner. Un texte non codifié — une loi qui n'a pas été intégrée à un code — ne se trouve pas ici : utilisez l'outil des textes consolidés (LODA). Comme pour toute réponse d'OpenLegi, vérifiez le texte sur Légifrance via le lien fourni avant tout usage professionnel. Voir « Limitations connues ». ### Jurisprudence judiciaire ## `rechercher_jurisprudence_judiciaire` Recherche dans la jurisprudence judiciaire : Cour de cassation, cours d'appel et juridictions du premier degré. Pour la juridiction **administrative** (Conseil d'État, cours administratives d'appel, tribunaux administratifs), utilisez `rechercher_jurisprudence_administrative`. ## En pratique > « Trouve-moi les jurisprudences récentes de la Cour de cassation sur la rupture > brutale des relations commerciales établies » > « Quelles sont les décisions récentes de la Cour de cassation sur la responsabilité des > plateformes numériques ? » > « Y a-t-il de la jurisprudence publiée au bulletin sur la clause de non-concurrence ? » ## Paramètres | Paramètre | Type | Description | |-----------|------|-------------| | `search` | string | Termes ou numéros d'affaires (obligatoire) | | `max_results` | integer | Nombre de résultats (défaut : 10, max : 100) | | `juridiction_judiciaire` | array | Juridictions à inclure | | `publication_bulletin` | array | `["T"]` pour ne retenir que les décisions publiées au bulletin | | `sort` | string | Tri : `PERTINENCE`, `DATE_ASC`, `DATE_DESC` | | `champ` | string | Champ : `ALL`, `TITLE`, `ABSTRACTS`, `TEXTE`, `NUM_AFFAIRE` | ## Exemple d'appel ```json { "name": "rechercher_jurisprudence_judiciaire", "arguments": { "search": "responsabilité civile", "juridiction_judiciaire": ["Cour de cassation"], "publication_bulletin": ["T"], "max_results": 10 } } ``` ## Juridictions disponibles - `Cour de cassation` - `Juridictions d'appel` - `Juridictions du premier degré` ## À savoir **Le filtre bulletin est un filtre de portée.** Une décision publiée au bulletin est celle que la Cour a jugée digne d'être signalée : c'est un bon proxy de l'importance jurisprudentielle. Restreindre avec `["T"]` réduit fortement le volume et remonte les arrêts de principe ; l'omettre donne accès aux arrêts d'espèce. **Pour retrouver une décision précise**, cherchez par numéro de pourvoi avec `champ: "NUM_AFFAIRE"` plutôt qu'en texte libre. Comme pour toute réponse d'OpenLegi, vérifiez la décision sur Légifrance via le lien fourni avant de la citer. Voir « Limitations connues », qui documente notamment des doublons observés sur certaines décisions. ### Journal Officiel (JORF) ## `recherche_journal_officiel` Recherche dans le Journal Officiel de la République française : lois, décrets, arrêtés, ordonnances, nominations et avis. Pour connaître les dernières publications sans critère de recherche, utilisez `dernier_journal_officiel`. ## En pratique > « Quels textes ont été publiés au JO cette semaine sur l'environnement ? » > « Y a-t-il de nouveaux décrets sur la signature électronique? » > « Recherche les derniers arrêtés de nomination au ministère de la Justice » ## Paramètres | Paramètre | Type | Description | |-----------|------|-------------| | `search` | string | Mots-clés à rechercher (obligatoire) | | `max_results` | integer | Nombre de résultats (défaut : 5, max : 100) | | `ministeres` | array | Filtrer par ministère émetteur | | `text_types` | array | Types de textes (`LOI`, `DECRET`, `ARRETE`…) | | `sort` | string | Tri : `PERTINENCE`, `PUBLI_DATE_ASC`, `PUBLI_DATE_DESC` | | `date_publication` | array | Plage de dates `[début, fin]` au format `AAAA-MM-JJ` | ## Exemple d'appel ```json { "name": "recherche_journal_officiel", "arguments": { "search": "nomination ambassadeur", "text_types": ["DECRET"], "max_results": 10 } } ``` Pour une veille sur une période donnée, triez par date décroissante : ```json { "name": "recherche_journal_officiel", "arguments": { "search": "protection des données", "date_publication": ["2026-01-01", "2026-06-30"], "sort": "PUBLI_DATE_DESC" } } ``` ## Types de textes disponibles | Valeur | Signification | |---|---| | `LOI` | Lois | | `DECRET` | Décrets | | `ARRETE` | Arrêtés | | `ORDONNANCE` | Ordonnances | | `DECISION` | Décisions | | `AVIS` | Avis | Les listes complètes des émetteurs et des natures de textes sont accessibles via `lister_emetteurs_jorf` et `lister_natures_textes_jorf`. ## À savoir **Le JORF est un flux de publication, pas un état du droit.** Il vous dit ce qui a été publié à une date donnée, dans sa version d'origine. Pour connaître le texte **en vigueur aujourd'hui**, avec ses modifications successives, passez par les codes ou les textes consolidés (LODA). Les publications les plus récentes peuvent apparaître avec quelques heures de décalage. ### Textes consolides (LODA) ## `rechercher_dans_texte_legal` Recherche dans les **textes consolidés ** : lois, ordonnances, décrets et arrêtés qui n'ont pas été intégrés à un code, dans leur version en vigueur. ## Codes ou LODA : lequel choisir C'est la question la plus fréquente, et le premier motif de recherche infructueuse. | Vous cherchez… | Outil | |---|---| | Un article numéroté d'un code (Code civil, Code du travail…) | `rechercher_code` | | Une loi désignée par son numéro et son année (loi 78-17) | `rechercher_dans_texte_legal` | | Un décret ou un arrêté non codifié, en vigueur | `rechercher_dans_texte_legal` | | Le texte tel que publié à une date donnée | `recherche_journal_officiel` | En résumé : **les codes rassemblent le droit codifié, LODA rassemble le reste**. Les deux donnent l'état consolidé, c'est-à-dire à jour des modifications. ## En pratique > « Que dit l'article 7 de la loi Informatique et Libertés ? » > « Quelles sont les conditions de validité d'une signature électronique ? » > « Trouve le décret d'application de la loi 2016-1321 sur le numérique » ## Paramètres | Paramètre | Type | Description | |-----------|------|-------------| | `search` | string | Mots-clés ou numéro d'article (obligatoire) | | `text_id` | string | Numéro du texte, format `AAAA-NUMERO` (optionnel) | | `champ` | string | Champ : `ALL`, `TITLE`, `TABLE`, `NUM_ARTICLE`, `ARTICLE` | | `max_results` | integer | Nombre de résultats (défaut : 10, max : 100) | | `sort` | string | Tri : `PERTINENCE`, `PUBLICATION_DATE_ASC`, `PUBLICATION_DATE_DESC` | | `type_recherche` | string | `TOUS_LES_MOTS_DANS_UN_CHAMP`, `EXACTE`, `UN_DES_MOT` | ## Exemples d'appel Article précis d'une loi identifiée : ```json { "name": "rechercher_dans_texte_legal", "arguments": { "search": "7", "text_id": "78-17", "champ": "NUM_ARTICLE" } } ``` Recherche thématique : ```json { "name": "rechercher_dans_texte_legal", "arguments": { "search": "signature électronique validité conditions", "max_results": 10 } } ``` ## À savoir **`type_recherche` explique la plupart des recherches vides.** Le mode par défaut, `TOUS_LES_MOTS_DANS_UN_CHAMP`, exige que *tous* les mots figurent dans le même champ. Si vous n'obtenez rien, réduisez le nombre de mots-clés ou basculez sur `UN_DES_MOT` pour élargir. `EXACTE` recherche l'expression littérale. **Le format de `text_id`** reprend la numérotation officielle : la loi du 6 janvier 1978 s'écrit `78-17`, une loi de 2016 s'écrit `2016-1321`. Comme pour toute réponse d'OpenLegi, vérifiez le texte sur Légifrance via le lien fourni avant tout usage professionnel. Voir « Limitations connues », qui documente notamment des cas de renumérotation d'articles et de références internes orphelines. ## Modes d'intégration Differentes facons d'utiliser OpenLegi MCP ### Intégration Python - Installation # Intégration Python - OpenLegi MCP ## 🎯 Recommandation importante **Pour une intégration simple et robuste, nous recommandons d'utiliser les librairies officielles MCP :** - **[MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)** : SDK officiel avec support complet du protocole - **[Claude Desktop](https://claude.ai/download)** : Intégration native dans l'interface Claude **La classe `OpenLegiClient` ci-dessous est fournie à titre éducatif et pour les cas d'usage avancés nécessitant un contrôle fin du protocole.** --- ## Installation ```bash pip install requests ``` ## Configuration ### URLs de base | Environnement | URL | |---------------|-----| | Production | `https://mcp.openlegi.fr` | | Local | `http://localhost:3000` | ### Services disponibles | Service | Endpoint | Description | |---------|----------|-------------| | Légifrance | `/legifrance/mcp` | Codes, jurisprudences, JORF, textes légaux | | INPI | `/inpi/mcp` | Registre du commerce et des sociétés | | EUR-Lex | `/eurlex/mcp` | Droit européen | ## Authentification Trois méthodes supportées : ### 1. Header Authorization (recommandé) ```python session.headers.update({ "Authorization": "Bearer VOTRE_TOKEN_ICI" }) ``` ### 2. Query Parameter ```python url = f"https://mcp.openlegi.fr/legifrance/mcp?token=VOTRE_TOKEN" ``` ### 3. Path Token ```python url = "https://mcp.openlegi.fr/legifrance/mcp/token/VOTRE_TOKEN" ``` --- ## Client Python OpenLegiClient ### Classe complète ```python import requests import json class OpenLegiClient: """Client Python pour l'API OpenLegi MCP. Gère le protocole MCP avec support du format SSE (Server-Sent Events). """ def __init__( self, token: str, service: str = "legifrance", base_url: str = "https://mcp.openlegi.fr" ): """Initialise le client MCP. Args: token: Token d'authentification OpenLegi service: Service à utiliser ('legifrance', 'inpi', 'eurlex') base_url: URL de base du serveur MCP """ self.base_url = base_url self.service = service self.endpoint = f"{base_url}/{service}/mcp" self.session = requests.Session() # Headers requis par le protocole MCP self.session.headers.update({ "Content-Type": "application/json", "Accept": "application/json, text/event-stream", # Les deux types sont requis "Authorization": f"Bearer {token}" }) # Initialiser la session MCP self._initialize() def _initialize(self): """Initialise la session MCP et récupère le session ID.""" payload = { "jsonrpc": "2.0", "id": 0, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "OpenLegiClient", "version": "1.0.0" } } } response = self.session.post(self.endpoint, json=payload) response.raise_for_status() # Récupérer le session ID du header session_id = response.headers.get('mcp-session-id') if session_id: self.session.headers.update({"mcp-session-id": session_id}) @staticmethod def _parse_sse_response(text: str) -> dict: """Parse une réponse SSE et extrait le JSON de la ligne data:. Le serveur MCP renvoie les réponses au format SSE : event: message data: {"jsonrpc":"2.0","id":1,"result":{...}} Args: text: Texte brut de la réponse HTTP Returns: Dictionnaire JSON extrait de la ligne 'data:' Raises: ValueError: Si aucune ligne 'data:' n'est trouvée """ lines = text.strip().split('\n') for line in lines: if line.startswith('data: '): return json.loads(line[6:]) # Retire 'data: ' et parse le JSON raise ValueError("Aucune ligne 'data:' trouvée dans la réponse SSE") def call_tool(self, tool_name: str, arguments: dict) -> dict: """Appelle un tool MCP avec les arguments fournis. Args: tool_name: Nom du tool à appeler (ex: 'rechercher_code') arguments: Dictionnaire des arguments du tool Returns: Résultat du tool (contenu du champ 'result') Raises: requests.HTTPError: Si la requête HTTP échoue Exception: Si le serveur renvoie une erreur JSON-RPC """ payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": tool_name, "arguments": arguments } } response = self.session.post(self.endpoint, json=payload) response.raise_for_status() # Parser la réponse SSE result = self._parse_sse_response(response.text) if "error" in result: raise Exception(f"Erreur MCP: {result['error']}") return result["result"] def list_tools(self) -> list[dict]: """Liste tous les tools disponibles sur le serveur. Returns: Liste des tools avec leurs métadonnées (name, description, inputSchema) Raises: requests.HTTPError: Si la requête HTTP échoue """ payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} } response = self.session.post(self.endpoint, json=payload) response.raise_for_status() # Parser la réponse SSE result = self._parse_sse_response(response.text) return result["result"]["tools"] def close(self): """Ferme la session HTTP.""" self.session.close() def __enter__(self): """Support du context manager (with statement).""" return self def __exit__(self, exc_type, exc_val, exc_tb): """Fermeture automatique de la session.""" self.close() ``` --- ## Exemples d'utilisation ### 1. Lister les tools disponibles ```python from openlegi_client import OpenLegiClient # Créer le client avec votre token token = "votre_token_ici" with OpenLegiClient(token=token) as client: # Récupérer la liste des tools tools = client.list_tools() print(f"📋 {len(tools)} tools disponibles:\n") for tool in tools: print(f"🔧 {tool['name']}") print(f" {tool['description'][:100]}...") print() ``` **Sortie attendue :** ``` 📋 12 tools disponibles: 🔧 rechercher_dans_texte_legal Recherche dans les textes légaux consolidés depuis légifrance... 🔧 rechercher_code Recherche des articles juridiques dans les codes juridiques français... 🔧 rechercher_jurisprudence_judiciaire Recherche des jurisprudences judiciaires avec validation MCP... 🔧 rechercher_jurisprudence_administrative Recherche dans la jurisprudence administrative (Conseil d'État... 🔧 rechercher_decisions_cnil Recherche dans les délibérations et décisions de la CNIL... 🔧 rechercher_conventions_collectives Recherche dans les conventions collectives (KALI)... 🔧 rechercher_decisions_constitutionnelles Recherche dans les décisions du Conseil constitutionnel... 🔧 recherche_journal_officiel Recherche dans le Journal Officiel français... 🔧 dernier_journal_officiel Récupère le(s) dernier(s) Journal(aux) Officiel(s) publiés... 🔧 lister_codes_juridiques Liste tous les codes juridiques disponibles sur Legifrance... 🔧 lister_emetteurs_jorf Liste tous les émetteurs/autorités disponibles pour les recherches JORF... 🔧 lister_natures_textes_jorf Liste toutes les natures de textes disponibles pour les recherches JORF... ``` ### 2. Rechercher un article dans un code ```python from openlegi_client import OpenLegiClient token = "votre_token_ici" with OpenLegiClient(token=token) as client: # Rechercher l'article 9 du Code civil result = client.call_tool( tool_name="rechercher_code", arguments={ "search": "9", "code_name": "Code civil", "champ": "NUM_ARTICLE" } ) print("📖 Résultat de la recherche:\n") print(result) ``` ### 3. Rechercher dans la jurisprudence ```python from openlegi_client import OpenLegiClient token = "votre_token_ici" with OpenLegiClient(token=token) as client: # Rechercher des décisions sur la responsabilité civile result = client.call_tool( tool_name="rechercher_jurisprudence_judiciaire", arguments={ "search": "responsabilité civile", "juridiction_judiciaire": ["Cour de cassation"], "publication_bulletin": ["T"], "sort": "DATE_DESC", "page_size": 5 } ) print("⚖️ Jurisprudences trouvées:\n") print(result) ``` ### 4. Consulter le dernier Journal Officiel ```python from openlegi_client import OpenLegiClient token = "votre_token_ici" with OpenLegiClient(token=token) as client: # Récupérer les 3 derniers JO result = client.call_tool( tool_name="dernier_journal_officiel", arguments={ "nb_jo": 3 } ) print("📰 Derniers Journaux Officiels:\n") print(result) ``` ### 5. Rechercher dans les conventions collectives ```python from openlegi_client import OpenLegiClient token = "votre_token_ici" with OpenLegiClient(token=token) as client: # Rechercher des conventions sur le télétravail result = client.call_tool( tool_name="rechercher_conventions_collectives", arguments={ "search": "télétravail", "panorama": True, # Vue d'ensemble sans texte intégral "page_size": 10 } ) print("📄 Conventions collectives:\n") print(result) ``` ### 6. Lister les codes juridiques disponibles ```python from openlegi_client import OpenLegiClient token = "votre_token_ici" with OpenLegiClient(token=token) as client: # Lister tous les codes disponibles result = client.call_tool( tool_name="lister_codes_juridiques", arguments={} ) print("📚 Codes juridiques disponibles:\n") for code in result: print(f" • {code}") ``` --- ## Gestion des erreurs ### Erreurs HTTP ```python from openlegi_client import OpenLegiClient import requests token = "votre_token_ici" try: with OpenLegiClient(token=token) as client: result = client.call_tool("rechercher_code", {"search": "test"}) except requests.HTTPError as e: print(f"❌ Erreur HTTP: {e}") print(f"Status: {e.response.status_code}") print(f"Détails: {e.response.text}") ``` ### Erreurs JSON-RPC ```python from openlegi_client import OpenLegiClient token = "votre_token_ici" try: with OpenLegiClient(token=token) as client: # Tool inexistant result = client.call_tool("tool_qui_nexiste_pas", {}) except Exception as e: print(f"❌ Erreur MCP: {e}") ``` --- ## Notes importantes ### Format SSE (Server-Sent Events) Le serveur MCP renvoie les réponses au format SSE, même pour les requêtes JSON-RPC simples : ``` event: message data: {"jsonrpc":"2.0","id":1,"result":{...}} ``` C'est pourquoi : 1. Le header `Accept` doit inclure `text/event-stream` 2. La réponse doit être parsée ligne par ligne 3. On ne peut pas utiliser directement `response.json()` ### Performance - Toujours utiliser `requests.Session()` pour réutiliser la connexion HTTP - Le context manager (`with` statement) garantit la fermeture de la session - Les credentials PISTE personnels éliminent les limitations de rate limiting ### Authentification - Le token est obligatoire pour tous les endpoints - Format recommandé : Header `Authorization: Bearer ` - Testez votre token avec `list_tools()` avant d'appeler des tools complexes --- ## Alternatives recommandées Pour une intégration production, considérez : 1. **[MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)** - SDK officiel avec : - Support complet du protocole MCP - Gestion automatique des sessions - Streaming SSE natif - Types Python stricts 2. **[Claude Desktop](https://claude.ai/download)** - Pour une utilisation interactive : - Configuration via `claude_desktop_config.json` - Interface graphique native - Pas de code nécessaire 3. **[Claude Code CLI](https://github.com/anthropics/claude-code)** - Pour l'automatisation : - Intégration Git - Exécution de tâches complexes - Support natif des serveurs MCP --- ## Support - 📧 Contact : [support@openlegi.fr](mailto:support@openlegi.fr) - 📖 Documentation complète : [https://auth.openlegi.fr/documentation](https://auth.openlegi.fr/documentation) - 🐛 Issues : [GitHub Issues](https://github.com/legalchain/legal-mcp/issues) --- ## Licence Ce code est fourni sous licence MIT à titre d'exemple éducatif. ### Health Check - Vérifier la disponibilité des services ## Endpoint public ``` GET https://mcp.openlegi.fr/health ``` Aucune authentification requise. Ne consomme pas votre quota de rate limit. ## Réponse ```json { "status": "ok", "services": { "legifrance": true, "rne": true, "eurlex": true, "bofip": true, "bodacc": true }, "auth_enabled": true } ``` | Champ | Description | |-------|-------------| | `status` | `"ok"` si la gateway est opérationnelle | | `services` | Statut de chaque service (`true` = activé, `false` = désactivé) | | `auth_enabled` | Indique si l'authentification est active | ## Exemple ```bash curl https://mcp.openlegi.fr/health ``` ## Usage recommandé Utilisez cet endpoint pour vérifier la disponibilité du service avant ou pendant vos intégrations. **Ne pas utiliser les outils MCP** (comme `lister_codes_juridiques`) comme health check : - Cela consomme votre quota de rate limit (30 requêtes / 5 min en credentials partagés) - C'est plus lent (~2-3s vs instantané pour `/health`) - Ce n'est pas conçu pour cela ## Monitoring Pour un monitoring automatisé, configurez un check régulier sur cet endpoint : ```bash # Vérification simple STATUS=$(curl -s https://mcp.openlegi.fr/health | jq -r '.status') if [ "$STATUS" != "ok" ]; then echo "Service indisponible" fi ``` ### Integration Python - Utilisation ## Exemples d'utilisation ### Lister les outils disponibles ```python # Service Légifrance with OpenLegiClient(token="VOTRE_TOKEN", service="legifrance") as client: tools = client.list_tools() print(f"🔧 {len(tools)} outils Légifrance disponibles") for tool in tools: print(f"- {tool['name']}: {tool['description']}") # Service RNE (Entreprises) with OpenLegiClient(token="VOTRE_TOKEN", service="rne") as client: tools = client.list_tools() print(f"\n🏢 {len(tools)} outils RNE disponibles") # Service EUR-Lex (Droit européen) with OpenLegiClient(token="VOTRE_TOKEN", service="eurlex") as client: tools = client.list_tools() print(f"\n🇪🇺 {len(tools)} outils EUR-Lex disponibles") ``` ### Rechercher dans le Journal Officiel ```python with OpenLegiClient(token="VOTRE_TOKEN_ICI") as client: result = client.call_tool( "recherche_journal_officiel", { "search": "dechet industriel recyclage", "max_results": 5, "sort": "SIGNATURE_DATE_DESC" } ) # Le résultat est dans result["content"][0]["text"] print(result["content"][0]["text"]) ``` ### Rechercher dans un code juridique ```python with OpenLegiClient(token="VOTRE_TOKEN_ICI") as client: result = client.call_tool( "rechercher_code", { "search": "mariage", "code_name": "Code civil", "page_size": 10 } ) print(result["content"][0]["text"]) ``` ### Rechercher de la jurisprudence ```python with OpenLegiClient(token="VOTRE_TOKEN_ICI") as client: result = client.call_tool( "rechercher_jurisprudence_judiciaire", { "search": "licenciement abusif", "sort": "DATE_DESC", "panorama": True, # Vue d'ensemble (métadonnées uniquement) "page_size": 10 } ) print(result["content"][0]["text"]) ``` ### Rechercher dans un texte légal (LODA) ```python with OpenLegiClient(token="VOTRE_TOKEN_ICI") as client: result = client.call_tool( "rechercher_dans_texte_legal", { "search": "signature électronique", "champ": "ALL", "page_size": 5 } ) print(result["content"][0]["text"]) ``` ### Lister les codes juridiques disponibles ```python with OpenLegiClient(token="VOTRE_TOKEN_ICI") as client: result = client.call_tool("lister_codes_juridiques", {}) print(result["content"][0]["text"]) ``` ## Gestion des erreurs ```python import requests from requests.exceptions import RequestException, HTTPError with OpenLegiClient(token="VOTRE_TOKEN_ICI") as client: try: result = client.call_tool( "recherche_journal_officiel", {"search": "urbanisme"} ) print(result["content"][0]["text"]) except HTTPError as e: if e.response.status_code == 401: print("❌ Erreur d'authentification: token invalide ou expiré") elif e.response.status_code == 403: print("❌ Accès interdit: vérifiez vos permissions") elif e.response.status_code == 404: print("❌ Endpoint non trouvé") else: print(f"❌ Erreur HTTP {e.response.status_code}: {e}") except RequestException as e: print(f"❌ Erreur de connexion: {e}") except Exception as e: print(f"❌ Erreur: {e}") ``` ### Rechercher des décisions CNIL ```python with OpenLegiClient(token="VOTRE_TOKEN", service="legifrance") as client: result = client.call_tool( "rechercher_decisions_cnil", { "search": "RGPD", "nature_delib": ["Sanction"], "sort": "DATE_DECISION_DESC", "page_size": 10 } ) print(result["content"][0]["text"]) ``` ### Rechercher des décisions du Conseil constitutionnel ```python with OpenLegiClient(token="VOTRE_TOKEN", service="legifrance") as client: result = client.call_tool( "rechercher_decisions_constitutionnelles", { "search": "liberté expression", "panorama": True, "page_size": 10 } ) print(result["content"][0]["text"]) ``` ### Rechercher des conventions collectives ```python with OpenLegiClient(token="VOTRE_TOKEN", service="legifrance") as client: result = client.call_tool( "rechercher_conventions_collectives", { "search": "métallurgie", "page_size": 10 } ) print(result["content"][0]["text"]) ``` ### Rechercher une entreprise (RNE) ```python with OpenLegiClient(token="VOTRE_TOKEN", service="rne") as client: result = client.call_tool( "rne_search_companies", { "query": "Google France", "page": 1, "per_page": 10 } ) print(result["content"][0]["text"]) ``` ### Rechercher dans EUR-Lex ```python with OpenLegiClient(token="VOTRE_TOKEN", service="eurlex") as client: result = client.call_tool( "eurlex_search_by_title", { "title": "RGPD", "max_results": 5 } ) print(result["content"][0]["text"]) ``` ### Optimisation des performances ## Optimisation des performances ### Réutilisation de session ```python # ❌ Mauvaise pratique : nouvelle connexion à chaque appel import requests def mauvais_appel(search: str): response = requests.post( "https://mcp.openlegi.fr/legifrance/mcp", json={"jsonrpc": "2.0", "method": "tools/call", ...}, headers={"Authorization": "Bearer TOKEN"} ) return response.json() # ✅ Bonne pratique : réutilisation de session with OpenLegiClient(token="TOKEN") as client: for search_term in ["mariage", "divorce", "succession"]: result = client.call_tool("rechercher_code", {"search": search_term}) # Traitement... ``` ### Connexion persistante ```python # Pour un script long avec de nombreux appels client = OpenLegiClient(token="VOTRE_TOKEN_ICI") try: for i in range(100): result = client.call_tool("recherche_journal_officiel", {"search": f"terme{i}"}) # Traitement... finally: client.close() # Fermeture propre ``` ### Protocole MCP et API Rest # SSE vs REST : Comprendre le protocole MCP ## 🤔 Le malentendu fréquent **Ce que les gens pensent :** > "C'est une API REST classique, je fais une requête POST et je reçois du JSON" **La réalité :** > "C'est un serveur MCP qui utilise SSE (Server-Sent Events) même pour les requêtes simples" --- ## 📊 Comparaison visuelle ### API REST classique ```http POST /api/search HTTP/1.1 Content-Type: application/json Accept: application/json {"query": "test"} ``` **Réponse REST classique :** ```http HTTP/1.1 200 OK Content-Type: application/json {"results": [...], "count": 42} ``` ### MCP avec SSE ```http POST /legifrance/mcp HTTP/1.1 Content-Type: application/json Accept: application/json, text/event-stream {"jsonrpc": "2.0", "method": "tools/list", "params": {}} ``` **Réponse MCP (format SSE) :** ```http HTTP/1.1 200 OK Content-Type: text/event-stream event: message data: {"jsonrpc":"2.0","id":1,"result":{...}} ``` --- ## 🔍 Différence clé | Aspect | REST classique | MCP avec SSE | |--------|----------------|--------------| | **Content-Type** | `application/json` | `text/event-stream` | | **Format réponse** | JSON brut | `event: ...\ndata: {...}` | | **Parsing** | `response.json()` | Parser ligne par ligne | | **Header Accept** | `application/json` | `application/json, text/event-stream` | | **Streaming** | Non (buffer complet) | Oui (événements progressifs) | --- ## 🧩 Pourquoi MCP utilise SSE ? ### 1. **Protocole unifié pour tous les cas d'usage** MCP supporte deux modes de communication : #### Mode 1 : Requête/Réponse simple (votre cas) ```python # Vous envoyez une requête {"jsonrpc": "2.0", "method": "tools/list", "params": {}} # Vous recevez UNE réponse event: message data: {"jsonrpc":"2.0","result":{...}} ``` #### Mode 2 : Notifications asynchrones ```python # Le serveur peut envoyer des notifications à tout moment event: notification data: {"method": "tools/list_changed"} event: notification data: {"method": "resources/updated", "params": {...}} ``` **Le SSE permet au serveur d'envoyer des événements au client SANS que le client n'ait fait de requête.** ### 2. **Support du streaming de contenu** Pour les outils qui génèrent beaucoup de données : ```python # Réponse progressive (streaming) event: message data: {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"Début..."}]}} event: progress data: {"progress": 50, "total": 100} event: message data: {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"...Suite..."}]}} ``` ### 3. **Maintien de la connexion** Avec SSE, la connexion HTTP reste ouverte : - Le serveur peut pousser des mises à jour - Pas besoin de polling (requêtes répétées) - Plus efficace pour les sessions longues --- ## 🎯 "Streamable" vs "Streaming" ### Streamable (capacité) ```python # Le header indique QUE LE CLIENT SUPPORTE le streaming headers = { "Accept": "application/json, text/event-stream" } ``` **Signification :** "Je suis capable de recevoir à la fois du JSON simple ET du streaming SSE" ### Streaming (action) ```python # Le serveur CHOISIT de streamer la réponse for chunk in long_computation(): send_sse_event("progress", {"chunk": chunk}) ``` **En pratique pour MCP :** - Toutes les réponses sont au format SSE (même si elles ne "streament" pas) - C'est le format d'enveloppe du protocole - Même une réponse instantanée utilise `event: message\ndata: {...}` --- ## 💡 Analogie simple ### REST classique = Lettre postale - Vous envoyez une lettre - Vous recevez UNE réponse complète - La boîte aux lettres se ferme après ### MCP avec SSE = Canal téléphonique - Vous appelez et la ligne reste ouverte - Vous posez une question (requête) - Vous recevez la réponse (event: message) - MAIS la ligne reste ouverte - Le serveur peut vous rappeler plus tard (notifications) - Vous pouvez poser d'autres questions sur la même ligne --- ## 🛠️ Implémentation pratique ### Code REST classique (NE MARCHE PAS avec MCP) ```python import requests # ❌ Ceci échoue avec MCP response = requests.post( "https://mcp.openlegi.fr/legifrance/mcp", json={"jsonrpc": "2.0", "method": "tools/list"}, headers={"Authorization": "Bearer TOKEN"} ) # ❌ JSONDecodeError: Expecting value data = response.json() ``` **Pourquoi ça échoue ?** ```python >>> response.text 'event: message\ndata: {"jsonrpc":"2.0",...}\n\n' >>> response.json() # Erreur : "event: message" n'est pas du JSON valide ! ``` ### Code MCP correct (avec parser SSE) ```python import requests import json def parse_sse(text): """Extrait le JSON de la ligne 'data:' """ for line in text.split('\n'): if line.startswith('data: '): return json.loads(line[6:]) # Retire 'data: ' raise ValueError("Pas de ligne data: trouvée") # ✅ Ceci fonctionne response = requests.post( "https://mcp.openlegi.fr/legifrance/mcp", json={"jsonrpc": "2.0", "method": "tools/list"}, headers={ "Authorization": "Bearer TOKEN", "Accept": "application/json, text/event-stream" # Important ! } ) # ✅ Parser le SSE data = parse_sse(response.text) print(data) # {"jsonrpc":"2.0","result":{...}} ``` --- ## 📋 Format SSE en détail ### Structure complète ``` event: message id: 123 data: {"jsonrpc":"2.0","id":1,"result":{...}} ``` | Champ | Description | Exemple | |-------|-------------|---------| | `event:` | Type d'événement | `message`, `notification`, `progress` | | `id:` | Identifiant unique (optionnel) | `123` | | `data:` | Payload JSON | `{"jsonrpc":"2.0",...}` | | Ligne vide | Fin de l'événement | `\n\n` | ### Événements multiples ``` event: message data: {"result": "partie 1"} event: progress data: {"percent": 50} event: message data: {"result": "partie 2"} ``` **Chaque bloc est séparé par une ligne vide.** --- ## ⚠️ Erreurs courantes ### Erreur 1 : Header Accept manquant ```python # ❌ ERREUR 406 Not Acceptable headers = {"Accept": "application/json"} # ✅ CORRECT headers = {"Accept": "application/json, text/event-stream"} ``` **Message d'erreur :** ```json { "error": { "code": -32600, "message": "Not Acceptable: Client must accept both application/json and text/event-stream" } } ``` ### Erreur 2 : Utiliser response.json() directement ```python # ❌ JSONDecodeError data = response.json() # ✅ Parser le SSE d'abord data = parse_sse(response.text) ``` ### Erreur 3 : Oublier l'initialisation de session ```python # ❌ 400 Bad Request (pas de session ID) response = session.post(url, json={"method": "tools/list"}) # ✅ Initialiser d'abord init_response = session.post(url, json={"method": "initialize"}) session_id = init_response.headers.get('mcp-session-id') session.headers.update({"mcp-session-id": session_id}) ``` --- ## 🚀 Avantages du SSE pour MCP ### 1. **Bidirectionnel (serveur → client)** ```python # Le serveur peut notifier le client event: notification data: {"method": "tools/list_changed"} ``` ### 2. **Reconnexion automatique** ```javascript // Côté JavaScript const eventSource = new EventSource('/mcp'); eventSource.addEventListener('message', (e) => { console.log(JSON.parse(e.data)); }); // Se reconnecte automatiquement si déconnecté ``` ### 3. **HTTP standard** - Pas besoin de WebSocket - Passe les proxies/firewalls - Compatible avec HTTP/1.1 et HTTP/2 ### 4. **Streaming progressif** ```python # Pour les longues réponses for i in range(100): send_event("progress", {"step": i, "total": 100}) send_event("message", {"result": final_data}) ``` --- ## 📚 Spécification SSE ### Format officiel W3C ``` stream = [ bom ] *event event = *( comment / field ) end-of-line comment = colon *any-char end-of-line field = 1*name-char [ colon [ space ] *any-char ] end-of-line end-of-line = ( cr lf / cr / lf ) ``` ### Champs standards | Champ | Signification | |-------|---------------| | `event:` | Type d'événement (défaut: "message") | | `data:` | Données de l'événement (peut être multi-lignes) | | `id:` | Identifiant de l'événement (pour reconnexion) | | `retry:` | Délai de reconnexion en ms | ### Exemple multi-lignes ``` event: message data: { data: "long": "json", data: "with": "multiple", data: "lines": true data: } ``` **Le client doit joindre toutes les lignes `data:`** --- ## 🔧 Debugging ### Voir le format brut avec curl ```bash curl -N \ -H "Authorization: Bearer TOKEN" \ -H "Accept: application/json, text/event-stream" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/list","params":{}}' \ https://mcp.openlegi.fr/legifrance/mcp ``` **Sortie :** ``` event: message data: {"jsonrpc":"2.0","id":null,"result":{"tools":[...]}} ``` ### Voir avec Python requests ```python import requests response = requests.post( "https://mcp.openlegi.fr/legifrance/mcp", json={"jsonrpc": "2.0", "method": "tools/list"}, headers={ "Authorization": "Bearer TOKEN", "Accept": "application/json, text/event-stream" } ) print("=== RAW RESPONSE ===") print(response.text) print("=== CONTENT-TYPE ===") print(response.headers.get('Content-Type')) ``` --- ## 📖 Ressources ### Spécifications - **SSE (W3C)** : https://html.spec.whatwg.org/multipage/server-sent-events.html - **MCP Protocol** : https://spec.modelcontextprotocol.io/ - **JSON-RPC 2.0** : https://www.jsonrpc.org/specification ### Librairies Python - **requests** : HTTP classique (ce que vous utilisez) - **httpx** : HTTP avec support async et streaming - **sseclient-py** : Parser SSE dédié - **mcp SDK** : SDK officiel MCP --- ## 🎓 Résumé pour expliquer à quelqu'un > "Le serveur MCP n'est PAS une API REST classique. Il utilise le protocole MCP qui encapsule toutes les réponses au format SSE (Server-Sent Events), même pour les requêtes simples. > > C'est pourquoi vous devez : > 1. Ajouter `text/event-stream` dans le header `Accept` > 2. Parser la réponse ligne par ligne pour extraire le JSON de la ligne `data:` > 3. Ne pas utiliser `response.json()` directement > > Le SSE permet au serveur d'envoyer des notifications asynchrones et de streamer les réponses progressivement, même si pour l'instant vous n'utilisez que le mode requête/réponse simple. > > C'est comme si vous demandiez une lettre postale mais que vous receviez un télégramme : le contenu est le même, mais le format d'enveloppe est différent." --- ## ✅ Checklist de migration REST → MCP - [ ] Ajouter `text/event-stream` au header `Accept` - [ ] Implémenter un parser SSE (`parse_sse_response()`) - [ ] Remplacer `response.json()` par `parse_sse(response.text)` - [ ] Ajouter l'initialisation de session (`initialize` avec `mcp-session-id`) - [ ] Gérer les notifications asynchrones (optionnel) - [ ] Tester avec différents tools - [ ] Documenter le changement pour l'équipe --- ## 📞 Questions fréquentes ### Q: Pourquoi pas du JSON simple ? **R:** MCP a besoin de supporter les notifications serveur et le streaming. SSE est le standard HTTP pour ça. ### Q: Est-ce que je peux forcer du JSON pur ? **R:** Non, c'est le protocole MCP. Utilisez les SDK officiels si vous voulez abstraire ça. ### Q: Ça consomme plus de ressources ? **R:** Négligeable. Le surcoût est juste quelques lignes de parsing. ### Q: Et WebSocket alors ? **R:** SSE est plus simple (HTTP standard) et suffisant pour MCP. WebSocket serait overkill. ### Q: Ça marche avec tous les clients HTTP ? **R:** Oui, mais vous devez parser manuellement. Les SDK MCP le font pour vous. --- ## 🎯 Conclusion **MCP avec SSE ≠ API REST classique** Même si vous faites des requêtes POST et recevez des données, le format est différent. C'est une architecture événementielle (event-driven) qui se trouve être synchrone pour vos cas d'usage actuels. **Solution recommandée :** Utilisez un SDK MCP officiel ou la classe `OpenLegiClient` fournie qui gère tout ça pour vous. ### Dépannage - codes erreur ### Erreur 400 Bad Request - Vérifiez qu'il n'y a pas de slash final avant le `?` dans l'URL - Vérifiez le format JSON de votre payload ### Erreur 401 Unauthorized - Vérifiez que votre token est valide - Vérifiez que le token est bien préfixé par `Bearer ` dans le header ### Erreur 403 Forbidden - Vérifiez que votre token a les permissions nécessaires (scopes) - Contactez l'administrateur pour vérifier vos droits d'accès ### Erreur de connexion - Vérifiez que le serveur est accessible - En local : vérifiez que le serveur est démarré (`./scripts/run_dev.sh`) - Vérifiez votre connexion réseau ## Fonds disponibles Liste et caractéristiques des fonds disponibles ### Fonds EurLex ## Carte d'identité | Champ | Valeur | |---|---| | Nom public | EURlex — Droit de l'Union européenne | | Identifiant du fonds | `eurlex` | | Périmètre | Législation de l'Union en français, principalement en vigueur (règlements, directives, décisions, y compris leurs versions consolidées), jurisprudence de la CJUE et du Tribunal, conclusions d'avocat général et références de transposition françaises. | | Granularité de recherche | Unité textuelle : article, considérant, annexe ou bloc `fulltext` pour les actes ; point et dispositif pour la jurisprudence. Chaque résultat restitue le contexte de l'acte et le lien EUR-Lex officiel. | | Producteur de la donnée | Office des publications de l'Union européenne. | | Sources primaires | [EUR-Lex](https://eur-lex.europa.eu/), [Cellar](https://op.europa.eu/en/web/cellar/) et [archives Open Data de l'Office des publications](https://datadump.publications.europa.eu/). | | Mise à jour | Stock initial, rattrapage des actes manquants et synchronisation nocturne du flux de notifications de l'éditeur. La fraîcheur et la couverture réellement servies se consultent avec `eurlex_statistiques_corpus` ou `GET /api/v1/health`. | EURlex permet de rechercher et consulter le droit de l'Union européenne par mot-clé, expression exacte, CELEX, ELI, matière EuroVoc, type de texte, date, vigueur ou juridiction. Il permet aussi de suivre les versions consolidées, de comparer deux dates, de retrouver les mesures françaises de transposition et d'explorer les citations entre législation et jurisprudence. Le fonds est en français. Il ne couvre pas les traités, les documents préparatoires, les autres langues ni, sauf quelques exceptions présentes dans la source, l'ensemble du droit abrogé. ## Origine et licence Les données proviennent des archives Formex, de Cellar et des services EUR-Lex de l'Office des publications. Le fonds conserve l'identifiant CELEX, l'identité de l'acte (`base_celex`) et le lien vers l'éditeur ; il enrichit les textes avec leurs métadonnées, leurs versions consolidées, les vocabulaires EuroVoc, les transpositions françaises et le réseau de citations. | Élément | Licence / condition | |---|---| | Documents juridiques EUR-Lex | Réutilisation commerciale ou non commerciale admise par la [décision 2011/833/UE](https://eur-lex.europa.eu/eli/dec/2011/833/oj), sauf condition particulière signalée sur le document concerné. | | Textes consolidés et contenu éditorial EUR-Lex | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) : indiquer la source et les éventuelles modifications. | | Métadonnées EUR-Lex | [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/) ; voir la [notice légale EUR-Lex](https://eur-lex.europa.eu/content/legal-notice/legal-notice.html). | Le fonds facilite la recherche et la navigation, mais ne constitue pas une publication authentique du droit. Lorsqu'une réponse a un enjeu juridique, vérifier le texte, sa version et sa date sur EUR-Lex ; seuls les documents publiés au Journal officiel de l'Union européenne sont authentiques et, pour la jurisprudence, les versions publiées au Recueil de la jurisprudence sont les sources officielles. ## Mode de mise à disposition **Fonds maison Normatic, moteur dédié.** EURlex n'est pas un simple wrapper d'une API tierce : le moteur télécharge et normalise les sources de l'Office des publications, les conserve dans sa propre base et indexe les unités en BM25 français. Il résout ensuite les liens entre actes, versions, articles, décisions, matières EuroVoc et mesures nationales de transposition. Pour les actes modifiés, le fonds adopte un modèle hybride : les articles sont remplacés par la dernière version consolidée disponible en français, tandis que les considérants restent ceux de l'acte de base. Cette préparation rend possible la recherche rapide, les filtres, l'accès à une version à date et le compare d'articles entre deux versions. L'API conserve néanmoins le lien EUR-Lex vers la source qui arbitre en cas de doute. Le fonds est accessible via le MCP Normatic. Il expose aussi une API REST de lecture pour les intégrations autorisées. ## Accès MCP EURlex est accessible via le MCP Normatic, qui relaie l'API du fonds : | Outil | Usage | |---|---| | `eurlex_rechercher` | Rechercher dans la législation, la CJUE ou les conclusions ; filtrer notamment par type, vigueur, période, matière EuroVoc, juridiction ou numéro d'acte. | | `eurlex_consulter_document` | Obtenir la fiche d'un CELEX et son sommaire enrichi ; demander une unité pour en lire le texte intégral. | | `eurlex_resoudre_eli` | Résoudre un ELI vers le CELEX et la fiche correspondante. | | `eurlex_rechercher_eurovoc` | Découvrir une matière EuroVoc, ses synonymes et ses descendants. | | `eurlex_historique_document` | Lister les versions consolidées disponibles d'un acte. | | `eurlex_lire_version` | Lire le texte applicable à une date donnée, récupéré chez l'éditeur. | | `eurlex_comparer_versions` | Comparer deux versions d'un acte, article par article. | | `eurlex_lister_transpositions` | Lister les mesures françaises de transposition d'une directive, avec leur NOR. | | `eurlex_citations` | Explorer les décisions qui visent un texte — jusqu'à l'article et au point de décision — ou les textes visés par une décision. | | `eurlex_resoudre_affaire` | Résoudre une référence d'affaire (`C-311/18`, `T-201/04`) ou un ECLI. | | `eurlex_statistiques_corpus` | Consulter la volumétrie, les facettes, la couverture et les limites mesurées du fonds. | Pour une question portant sur le droit actuellement applicable, vérifier `in_force`, `is_consolidated`, `version_date` et, lorsqu'il existe, `latest_consolidated_version`. Après une recherche, ouvrir l'unité concernée avant de citer son texte. Pour la jurisprudence, utiliser la collection CJUE — arrêts et ordonnances — plutôt que les conclusions d'avocat général, qui ne lient pas la Cour. ## Accès API REST Base de production : `https://mcp.normatic.fr/europe`. Les routes métier sont destinées aux intégrations autorisées et demandent un jeton de service (`Authorization: Bearer …` ou `X-API-Token`). - [Documentation interactive de l'API](https://mcp.normatic.fr/api/v1/docs#/Droit%20de%20l'UE%20(eurlex)) - [Spécification OpenAPI (JSON)](https://mcp.normatic.fr/api/v1/openapi.json) Les endpoints ci-dessous sont relatifs à cette base. | Endpoint | Équivalent MCP / usage | |---|---| | `GET /search` | `eurlex_rechercher` — recherche BM25, pagination, regroupement et filtres. | | `GET /doc/{celex}` | `eurlex_consulter_document` — fiche, sommaire et, sur demande, unité ou texte complet. | | `GET /by-eli/{eli}` | `eurlex_resoudre_eli` — résolution ELI. | | `GET /eurovoc` | `eurlex_rechercher_eurovoc` — matière, synonymes, hiérarchie. | | `GET /doc/{celex}/timeline` | `eurlex_historique_document` — historique des versions consolidées. | | `GET /doc/{celex}/version/{date}` | `eurlex_lire_version` — texte à une date. | | `GET /doc/{celex}/compare` | `eurlex_comparer_versions` — diff entre deux dates. | | `GET /doc/{celex}/transpositions` | `eurlex_lister_transpositions` — mesures françaises de transposition. | | `GET /doc/{celex}/citations` | `eurlex_citations` — réseau de citations. | | `GET /by-case/{reference}` | `eurlex_resoudre_affaire` — affaire ou ECLI. | | `GET /stats` | `eurlex_statistiques_corpus` — volume, couverture et périmètre. | | `GET /health` | État de service, sans donnée métier. | | `GET /monitoring` | Supervision technique ; jeton de supervision distinct en production. | Les paramètres et schémas exposés par le service complètent cette liste. Les identifiants CELEX, ELI, ECLI, références d'affaire et NOR sont transmis sans transformation. ## Limites à connaître - Le fonds est en français et porte avant tout le droit de l'Union en vigueur ; une absence de résultat ne prouve jamais une absence de droit. Le `404` d'un acte absent conserve son lien EUR-Lex et, quand elle est connue, la raison de l'absence. - Un acte de base et sa version consolidée ne sont pas la même chose. Lire `is_consolidated`, `version_date` et le lien de la version réellement servie avant de citer une disposition. - La recherche indexe articles, considérants, annexes et blocs complets ; elle ne garantit pas que chaque texte soit navigable article par article. Les annexes des versions consolidées ne sont pas encore comparées entre deux dates. - Les conclusions d'avocat général sont des analyses, pas des décisions de la Cour. Ne pas les présenter comme la jurisprudence ; filtrer sur les arrêts et ordonnances lorsque c'est la position de la Cour qui est demandée. - Les résultats sont paginés. Utiliser `total`, `count`, `limit` et `offset` plutôt que de conclure à partir de la première page ; afficher les éventuels `scope_note`, `in_force_note` et `date_quality`. ### Fonds KALI — conventions collectives ## Carte d'identité | Champ | Valeur | |---|---| | Nom public | KALI — Conventions collectives | | Identifiant du fonds | `kali` | | Périmètre | Conventions collectives, accords, avenants, salaires et leurs articles, avec leurs métadonnées de vigueur, d'extension et d'IDCC. | | Granularité de recherche | Article (`KALIARTI`) ; chaque résultat restitue son contexte : convention, IDCC, texte et sections. | | Producteur de la donnée | Direction de l'information légale et administrative (DILA). | | Source primaire | [Archives Open Data KALI de la DILA](https://echanges.dila.gouv.fr/OPENDATA/KALI/). | | Mise à jour | Stock complet, puis rattrapage des incréments publiés par la DILA. La fraîcheur réellement servie se consulte avec `kali_statistiques_corpus` ou `GET /api/v1/health`. | KALI permet de rechercher et de consulter les textes conventionnels français par mot-clé, expression exacte, IDCC, état, extension et date d'effet. Il ne couvre pas, à lui seul, les codes, lois et décrets : ces sources relèvent d'autres fonds. ## Origine et licence Les archives DILA contiennent les conteneurs de conventions (`KALICONT`), les textes (`KALITEXT`), les sections (`KALISCTA`) et les articles (`KALIARTI`). Normatic en conserve la traçabilité jusqu'à l'archive source et respecte les suppressions publiées dans les incréments. | Élément | Licence / condition | |---|---| | Données KALI | [Licence Ouverte / Open Licence 2.0](https://www.data.gouv.fr/pages/legal/licences/etalab-2.0) ; indiquer la source DILA lors de la réutilisation. | Le fonds facilite la recherche, mais ne constitue pas une publication officielle du droit : lorsqu'une réponse a un enjeu juridique, vérifier le texte et sa date sur Légifrance. ## Mode de mise à disposition **Fonds maison Normatic, moteur dédié.** KALI n'est pas un simple wrapper d'une API tierce : le moteur télécharge les archives DILA, les normalise, les conserve dans sa propre base, indexe les articles (BM25 et, lorsque disponible, sémantique) et résout les liens entre objets du fonds. Cette préparation permet les filtres de vigueur et d'extension, la navigation dans la structure d'une convention et une recherche paginée. Le fonds est accessible via deux serveurs MCP : le MCP Légifrance (OpenLEGI) et le MCP Normatic. Le moteur Kali expose aussi une API REST de lecture pour les intégrations autorisées. ## Accès MCP KALI est disponible via deux canaux MCP : | Canal | Accès au fonds | Différence à connaître | |---|---|---| | MCP Légifrance (OpenLEGI) | Consultation et recherche dans KALI. | Accès au fonds via l'écosystème Légifrance / OpenLEGI. | | MCP Normatic | Consultation et recherche dans KALI. | Propose en plus la recherche sémantique, utile pour les requêtes par notion ou synonymes. | Les outils KALI à utiliser, selon ceux exposés par le serveur MCP sélectionné, sont les suivants : | Outil | Usage | |---|---| | `kali_rechercher` | Rechercher des clauses et articles ; filtrer notamment par `idcc`, `en_vigueur`, `etendu`, état ou dates. Sur Normatic, employer la recherche sémantique pour une recherche par notion. | | `kali_consulter_article` | Obtenir le texte intégral, les dates et le contexte d'un `KALIARTI…`. | | `kali_consulter_convention` | Consulter une convention depuis un IDCC (`1486`, `IDCC 1486`) ou un identifiant `KALICONT…`. | | `kali_lister_conventions` | Découvrir et filtrer les conventions disponibles. | | `kali_structure_convention` | Parcourir l'arborescence texte → sections. | | `kali_resoudre_liens` | Suivre les renvois DILA depuis un article. | | `kali_statistiques_corpus` | Consulter la couverture et l'état des index du fonds. | Pour répondre à une question sur le droit actuellement applicable, conserver le champ `applicable_a_ce_jour` : l'état seul ne suffit pas. Après une recherche, ouvrir l'article avant de citer son texte. ## Accès API REST Base de production : `https://mcp.normatic.fr/social`. Les routes métier sont destinées aux intégrations autorisées et demandent un jeton de service (`Authorization: Bearer …` ou `X-API-Token`). - [Documentation interactive de l'API](https://mcp.normatic.fr/api/v1/docs#/Conventions%20collectives%20(kali)) - [Spécification OpenAPI (JSON)](https://mcp.normatic.fr/social/openapi.json) Les endpoints ci-dessous sont relatifs à cette base. | Endpoint | Équivalent MCP / usage | |---|---| | `GET /search` | `kali_rechercher` — recherche, pagination et filtres. | | `GET /articles` | Liste d'articles filtrable. | | `GET /articles/{article_id}` | `kali_consulter_article` — article et contexte. | | `GET /articles/{article_id}/liens` | `kali_resoudre_liens` — renvois enrichis. | | `GET /conventions` | `kali_lister_conventions` — liste des conventions. | | `GET /conventions/{convention_id}` | `kali_consulter_convention` — IDCC ou `KALICONT…`. | | `GET /conventions/{convention_id}/structure` | `kali_structure_convention` — texte et sections. | | `GET /stats` | `kali_statistiques_corpus` — volumétrie et index. | | `GET /health` | État de service, sans donnée métier. | | `GET /monitoring` | Supervision technique ; jeton de supervision distinct en production. | Les paramètres et schémas exposés par le service complètent cette liste. Les identifiants DILA et les IDCC sont transmis sans transformation. ## Limites à connaître - La date d'effet, la date de signature, l'état et l'extension sont distincts : ne les déduisez pas les uns des autres. - Une convention peut contenir des versions, accords et avenants : citer l'identifiant de l'article et ses dates, pas seulement le titre de la convention. - Les résultats sont paginés. Utiliser `total`, `count`, `limit` et `offset` plutôt que de conclure à partir de la première page. ## Architecture ### Vue d'ensemble OpenLegi repose sur **deux services distincts**, ce qui explique que vous rencontriez deux noms de domaine. ``` ┌────────────────────────────┐ │ Votre client MCP │ │ Claude · ChatGPT · │ │ Mistral · Cursor · VS Code│ └──────────────┬─────────────┘ │ MCP (JSON-RPC sur HTTP) ▼ ┌─────────────────────┐ ┌────────────────────────────┐ │ auth.openlegi.fr │◄──┤ mcp.openlegi.fr │ │ Authentification │ │ Passerelle MCP │ │ │ │ │ │ · comptes │ │ · expose les outils │ │ · tokens │ │ · valide l'accès │ │ · OAuth2 / OIDC │ │ · applique les quotas │ │ · clés PISTE │ │ · met en forme les réponses│ └─────────────────────┘ └──────────────┬─────────────┘ │ API officielles ▼ ┌───────────────────────────────────────────────────────┐ │ Légifrance (via PISTE) · RNE / INPI · EUR-Lex │ │ BOFiP · BODACC │ └───────────────────────────────────────────────────────┘ ``` ## Les composants **Votre client MCP.** Tout assistant qui gère le protocole MCP. C'est lui qui décide d'appeler un outil en fonction de votre question. **La passerelle MCP — `mcp.openlegi.fr`.** Elle expose les outils, vérifie que l'appel est autorisé, applique les quotas, interroge la source officielle et met le résultat en forme pour un modèle de langage. C'est le seul service que votre client contacte directement. **Le serveur d'authentification — `auth.openlegi.fr`.** Il gère les comptes, les tokens, le rôle de serveur d'autorisation OAuth 2.0 / OpenID Connect, et le stockage chiffré de vos identifiants PISTE personnels. C'est aussi là que vivent le tableau de bord et cette documentation. Vous vous y connectez, mais votre client MCP ne l'appelle pas. **Les sources officielles.** Légifrance via l'API PISTE de l'État, le RNE via l'INPI, EUR-Lex pour le droit européen, ainsi que BOFiP et BODACC. OpenLegi n'héberge aucune copie de ces bases : chaque requête part vers la source. ## Le parcours d'une requête 1. Vous posez une question à votre assistant, qui décide d'appeler un outil OpenLegi. 2. Le client envoie une requête MCP à la passerelle, avec un jeton OAuth ou un token. 3. La passerelle vérifie l'accès — signature du jeton pour OAuth, validation auprès du serveur d'authentification pour un token — et contrôle le quota. 4. Si vous avez déclaré vos propres identifiants PISTE, la passerelle les récupère (chiffrés au repos, déchiffrés le temps de l'appel). Sinon elle utilise les identifiants partagés. 5. La requête est traduite en appel à l'API de la source concernée. 6. Le résultat est mis en forme, accompagné des **liens vers la source officielle**, et renvoyé au client. ## Ce que cette architecture implique pour vous - **Une seule adresse à configurer** dans votre client : celle de la passerelle. Si un guide vous demande de pointer un client MCP vers `auth.openlegi.fr`, il est périmé. - **Les données ne sont pas stockées par OpenLegi.** Chaque réponse provient d'une requête en direct à la source, à la latence de cache près. - **Ce que vous lisez est une représentation intermédiaire** du texte officiel : filtrée, remise en forme, puis souvent reformulée par votre assistant. D'où la règle de vérification systématique sur Légifrance avant tout usage professionnel — voir la page « Limitations connues ». ### Sécurité OpenLegi est un point d'accès à des sources juridiques officielles pour des assistants IA. Cette page décrit comment vos accès sont protégés et ce que vous devez faire de votre côté. ## Authentification Deux modes coexistent. Voir « Les deux modes de connexion » pour choisir. ### OAuth 2.0 / OpenID Connect — recommandé OpenLegi est un **serveur d'autorisation OAuth 2.0 / OpenID Connect**. Le client MCP ne manipule jamais de secret permanent : - Vous vous authentifiez une fois, puis le client reçoit un **jeton d'accès temporaire** (JWT signé en RS256), valable une heure. - Le renouvellement est automatique, par un jeton de rafraîchissement à rotation. - Les clients sont des **clients publics protégés par PKCE** : aucun secret client à stocker, donc aucun secret à fuiter. - Les portées accordées sont l'intersection de ce que le client demande et de vos droits réels. Un droit retiré prend effet au renouvellement suivant. **Comment un client s'identifie.** Deux méthodes, transparentes pour vous : - **Automatiquement (CIMD, *Client ID Metadata Document*)** — le client présente l'adresse de son document de métadonnées en guise d'identifiant. OpenLegi va le chercher, le valide et enregistre le client sans intervention. Vous n'avez aucun identifiant à saisir. - **Par identifiant pré-enregistré** — pour les clients qui réclament un « Client ID ». L'identifiant public de chaque plateforme est publié sur la page « Problème connexion spécifique à Claude ». Le champ « Client Secret » reste vide dans les deux cas. L'enregistrement automatique n'est pas ouvert à tous : seuls les domaines explicitement autorisés peuvent l'emprunter, et la récupération du document de métadonnées est durcie contre les requêtes détournées vers des ressources internes. Un domaine inconnu est refusé plutôt que toléré. ### Token personnel Pour les clients qui ne gèrent pas OAuth (Claude Desktop en configuration locale, VS Code, Cursor), un token personnel reste disponible. C'est un **secret permanent** : il ne perd sa validité que si vous le régénérez. Trois façons de le transmettre, par ordre de préférence : 1. En-tête HTTP `Authorization: Bearer VOTRE_TOKEN` — **recommandé** 2. Paramètre d'URL `?token=VOTRE_TOKEN` 3. Segment de chemin `/mcp/token/VOTRE_TOKEN` Les méthodes 2 et 3 font apparaître le secret dans l'URL, donc potentiellement dans les journaux de serveurs intermédiaires et dans l'historique de votre shell. Préférez l'en-tête chaque fois que votre client le permet. ## Transport Toutes les communications se font en HTTPS, vers le serveur d'authentification (`auth.openlegi.fr`) comme vers la passerelle MCP (`mcp.openlegi.fr`). ## Protection de vos clés PISTE Si vous déclarez vos propres identifiants PISTE, le secret client est **chiffré au repos** (chiffrement symétrique authentifié : AES-128 en mode CBC avec HMAC). Il n'est déchiffré qu'au moment de l'appel à l'API, et n'apparaît jamais dans les journaux ni dans les messages d'erreur. Conséquence à connaître : OpenLegi ne peut pas vous réafficher un secret déjà enregistré. En cas de perte, régénérez-le côté PISTE et déclarez-le à nouveau. ## Journalisation Les appels sont journalisés pour des raisons techniques et de facturation d'usage : horodatage, service et outil appelés, code de statut, temps de réponse. **Le contenu de vos recherches n'est pas enregistré** dans ces journaux. Ils sont purgés automatiquement au bout de 90 jours. Point d'attention qui ne dépend pas d'OpenLegi : votre conversation est traitée par l'éditeur de votre assistant IA selon **ses** conditions. Pour un dossier sensible, c'est ce point qu'il faut examiner en premier. ## Limitation de débit Le nombre de requêtes est plafonné pour garantir la disponibilité du service. En déclarant vos propres identifiants PISTE, vos requêtes ne sont plus décomptées. Votre consommation est visible en temps réel depuis le tableau de bord. ## Bonnes pratiques 1. **Préférez OAuth** quand votre client le permet : rien à copier, expiration automatique. 2. **Ne partagez jamais votre token** et ne le committez pas dans un dépôt. En script, passez-le par une variable d'environnement. 3. **Utilisez l'en-tête `Authorization`** plutôt que l'URL. 4. **Ne déclarez vos identifiants PISTE que sur le tableau de bord OpenLegi**, jamais dans un fichier de configuration partagé. ## En cas de compromission **Si vous utilisez un token :** connectez-vous au [tableau de bord](https://auth.openlegi.fr/users/dashboard/), régénérez le token, puis mettez à jour vos configurations. L'ancien token cesse immédiatement de fonctionner. **Si vous utilisez OAuth :** révoquez la connexion OpenLegi depuis les paramètres de votre client (Claude, ChatGPT, Mistral). Les jetons d'accès expirent d'eux-mêmes en moins d'une heure. **Si vos identifiants PISTE sont concernés :** régénérez-les sur [piste.gouv.fr](https://piste.gouv.fr), puis remplacez-les dans le tableau de bord. Signalez l'incident via le [formulaire de contact](/contact/) si vous pensez que le problème vient d'OpenLegi. ### Performance ## Optimisations - **Formatage optimisé** — réponses adaptées à la lecture par un modèle de langage - **Transport HTTP streamable** — pour les réponses volumineuses - **Pagination** — pour parcourir les grands volumes sans tout charger ## Conseils d'utilisation 1. **Limitez le nombre de résultats** — ne demandez que ce dont vous avez besoin. Une recherche qui renvoie 100 décisions intégrales sature la fenêtre de contexte de votre assistant et dégrade la qualité de sa réponse. 2. **Utilisez le mode panorama** pour balayer un grand nombre de résultats : il ne renvoie que les métadonnées et les résumés. Vous demandez ensuite le texte complet des seuls résultats retenus. 3. **Utilisez les filtres** — juridiction, ministère, type de texte, plage de dates. Filtrer à la source coûte moins cher que trier après coup. 4. **Préférez les recherches spécifiques** aux termes trop généraux. Par défaut, tous les mots doivent être présents : trois mots précis valent mieux qu'une phrase entière. ## Temps de réponse typiques | Opération | Temps moyen | |-----------|-------------| | Liste des outils | < 100 ms | | Recherche simple | 200 à 500 ms | | Recherche complexe | 500 ms à 2 s | Ces ordres de grandeur concernent la passerelle. Le temps perçu inclut en plus celui que votre assistant met à formuler sa réponse, qui est généralement le plus long. ## Gestion des erreurs En cas de dépassement de délai ou d'erreur, le serveur renvoie un message explicite. Attendez quelques secondes avant de réessayer. Pour vérifier que le service est disponible sans consommer votre quota, utilisez le point d'accès public `https://mcp.openlegi.fr/health` — voir la page « Health Check ».